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();
10 # Get the samba version
11 if (open(VERSION, "$module_config_directory/version")) {
12 chop($samba_version = <VERSION>);
16 $has_pdbedit = ( $samba_version >= 3 && &has_command($config{'pdbedit'}) );
17 $has_smbgroupedit = 1 if (&has_command($config{'smbgroupedit'}));
18 $has_net = 1 if ($config{'net'} =~ /^(\S+)/ && &has_command("$1"));
19 $has_groups = ( $samba_version >= 3 && ($has_smbgroupedit || $has_net) );
22 # List all the shares from the samba config file
26 &open_readfile(SAMBA, $config{smb_conf});
28 chop; s/;.*$//g; s/^\s*#.*$//g;
29 if (/^\s*\[([^\]]+)\]/) {
35 # Check for an include directive in the [global] share
37 &get_share("global", \%global);
38 local $inc = &getval("include", \%global);
39 if ($inc && $inc !~ /\%/) {
47 # get_share(share, [array])
48 # Fills the associative array %share with the parameters from the given share
51 local($found, $_, $first, $arr);
52 $arr = (@_==2 ? $_[1] : "share");
54 &open_readfile(SAMBA, $config{smb_conf});
56 chop; s/^\s*;.*$//g; s/^\s*#.*$//g;
57 if (/^\s*\[([^\]]+)\]/) {
58 # Start of share section
61 elsif ($1 eq $_[0]) { $found = 1; $$arr{share_name} = $1; }
63 elsif ($found && /^\s*([^=]*\S)\s*=\s*(.*)$/) {
64 # Directives inside a section
65 if (lc($1) eq "read only") {
66 # bastard special case.. change to writable
67 $$arr{'writable'} = $2 =~ /yes|true|1/i ? "no" : "yes";
69 else { $$arr{lc($1)} = $2; }
71 elsif (!$first && /^\s*([^=]*\S)\s*=\s*(.*)$/ && $_[0] eq "global") {
72 # Directives outside a section! Assume to be part of [global]
73 $$arr{share_name} = "global";
84 # Add an entry to the config file
87 &open_tempfile(CONF, ">> $config{smb_conf}");
88 &print_tempfile(CONF, "\n");
89 &print_tempfile(CONF, "[$_[0]]\n");
90 foreach $k (grep {!/share_name/} (keys %share)) {
91 &print_tempfile(CONF, "\t$k = $share{$k}\n");
93 &close_tempfile(CONF);
97 # modify_share(oldname, newname)
98 # Change a share (and maybe it's name)
101 local($_, @conf, $replacing, $first);
102 &open_readfile(CONF, $config{smb_conf});
105 &open_tempfile(CONF, ">$config{smb_conf}");
106 for($i=0; $i<@conf; $i++) {
107 chop($_ = $conf[$i]); s/;.*$//g; s/#.*$//g;
108 if (/^\s*\[([^\]]+)\]/) {
110 if ($replacing) { $replacing = 0; }
111 elsif ($1 eq $_[0]) {
112 &print_tempfile(CONF, "[$_[1]]\n");
113 foreach $k (grep {!/share_name/} (keys %share)) {
114 &print_tempfile(CONF, "\t$k = $share{$k}\n");
116 #&print_tempfile(CONF, "\n");
120 elsif (!$first && /^\s*([^=]*\S)\s*=\s*(.*)$/ && $_[0] eq "global") {
121 # found start of directives outside any share - assume [global]
123 &print_tempfile(CONF, "[$_[1]]\n");
124 foreach $k (grep {!/share_name/} (keys %share)) {
125 &print_tempfile(CONF, "\t$k = $share{$k}\n");
127 &print_tempfile(CONF, "\n");
130 if (!$replacing || $conf[$i] =~ /^\s*[#;]/ || $conf[$i] =~ /^\s*$/) {
131 &print_tempfile(CONF, $conf[$i]);
134 &close_tempfile(CONF);
138 # delete_share(share)
139 # Delete some share from the config file
142 local($_, @conf, $deleting);
143 &open_readfile(CONF, $config{smb_conf});
146 &open_tempfile(CONF, "> $config{smb_conf}");
147 for($i=0; $i<@conf; $i++) {
148 chop($_ = $conf[$i]); s/;.*$//g;
149 if (/^\s*\[([^\]]+)\]/) {
150 if ($deleting) { $deleting = 0; }
151 elsif ($1 eq $_[0]) {
152 &print_tempfile(CONF, "\n");
157 &print_tempfile(CONF, $conf[$i]);
160 &close_tempfile(CONF);
164 # list_connections([share])
165 # Uses the smbstatus program to return a list of connections a share. Each
166 # element of the returned list is of the form:
167 # share, user, group, pid, hostname, date/time
170 local($l, $started, @rv);
171 if ($samba_version >= 3) {
172 # New samba status format
175 local $ex = &execute_command("$config{samba_status_program} -s $config{smb_conf}", undef, \$out, undef);
177 # -s option not supported
178 &execute_command("$config{samba_status_program}",
179 undef, \$out, undef);
181 foreach $l (split(/\n/ , $out)) {
185 elsif ($started == 1 &&
186 $l =~ /^\s*(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+\((\S+)\)/) {
187 # A line with a PID, username, group and hostname
188 $pidmap{$1} = [ $1, $2, $3, $4, $5 ];
190 elsif ($started == 2 &&
191 $l =~ /^\s*(\S+)\s+(\d+)\s+(\S+)\s+(.*)$/) {
192 # A line with a service, PID and machine. This must be
193 # combined data from the first type of line to create
194 # the needed information
195 local $p = $pidmap{$2};
196 if (!$_[0] || $1 eq $_[0] ||
197 $1 eq $p->[1] && $_[0] eq "homes") {
198 push(@rv, [ $1, $p->[1], $p->[2], $2, $3, $4 ]);
204 # Old samba status format
206 &execute_command("$config{samba_status_program} -S",
207 undef, \$out, undef);
208 foreach $l (split(/\n/, $out)) {
209 if ($l =~ /^----/) { $started++; }
210 if ($started && $l =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\s+\(\S+\)\s+(.*)$/ && (!$_[0] || $1 eq $_[0] || $1 eq $2 && $_[0] eq "homes")) {
211 push(@rv, [ $1, $2, $3, $4, $5, $6 ]);
219 # Returns a list of locked files as an array, in the form:
220 # pid, mode, rw, oplock, file, date
223 local($l, $started, @rv);
226 &execute_command("$config{samba_status_program} -L", undef, \$out, undef);
227 &reset_environment();
228 foreach $l (split(/\n/, $out)) {
229 if ($l =~ /^----/) { $started = 1; }
230 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) {
232 push(@rv, [ $1, $3, $5, $6, $7.'/'.$8, $9 ]);
234 elsif ($started && $l =~ /^(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)/) {
236 push(@rv, [ $1, $2, $3, $4, $5, $6 ]);
244 # Checks if the value of this key (or it's synonyms) in %share is true
247 return &getval($_[0]) =~ /yes|true|1/i;
252 # Checks if the value of this key (or it's synonyms) in %share is false
255 return &getval($_[0]) =~ /no|false|0/i;
259 # getval(name, [&hash])
260 # Given the name of a key in %share, return the value. Also looks for synonyms.
261 # If the value is not found, a default is looked for.. this can come from
262 # a copied section, the [global] configuration section, or from the SAMBA
263 # defaults. This means that getval() always returns something..
266 local $hash = $_[1] || \%share;
269 foreach (split(/,/, $synon{$_[0]})) {
270 if (defined($hash->{$_})) { return $hash->{$_}; }
273 if (defined($hash->{$_[0]})) {
274 return $hash->{$_[0]};
276 elsif ($_[0] ne "copy" && ($copy = $hash->{"copy"})) {
277 # this share is a copy.. get the value from the source
280 return &getval($_[0]);
283 # return the default value...
284 return &default_value($_[0]);
290 # setval(name, value, [default])
291 # Sets some value in %share. Synonyms with the same meaning are removed.
292 # If the value is the same as the share or given default, dont store it
297 # default was given..
300 elsif ($_[0] ne "copy" && ($copy = $share{"copy"})) {
301 # get value from copy source..
304 $def = &getval($_[0]);
307 # get global/samba default
308 $def = &default_value($_[0]);
310 if ($_[1] eq $def || ($def !~ /\S/ && $_[1] !~ /\S/) ||
311 ($def =~ /^(true|yes|1)$/i && $_[1] =~ /^(true|yes|1)$/i) ||
312 ($def =~ /^(false|no|0)$/i && $_[1] =~ /^(false|no|0)$/i)) {
313 # The value is the default.. delete this entry
318 foreach (split(/,/, $synon{$_[0]})) {
322 $share{$_[0]} = $_[1];
328 # Delete a value from %share (and it's synonyms)
333 foreach (split(/,/, $synon{$_[0]})) {
337 else { delete($share{$_[0]}); }
341 # default_value(name)
342 # Returns the default value for a parameter
347 # First look in the [global] section.. (unless this _is_ the global section)
348 if ($share{share_name} ne "global") {
349 &get_share("global", "global");
351 foreach (split(/,/, $synon{$_[0]})) {
352 if (defined($global{$_})) { return $global{$_}; }
355 if (defined($global{$_[0]})) { return $global{$_[0]}; }
358 # Else look in the samba defaults
360 foreach (split(/,/, $synon{$_[0]})) {
361 if (exists($default_values{$_})) {
362 return $default_values{$_};
366 return $default_values{$_[0]};
370 # The list of synonyms used by samba for parameter names
371 @synon = ( "writeable,write ok,writable",
373 "printable,print ok",
374 "allow hosts,hosts allow",
375 "deny hosts,hosts deny",
376 "create mode,create mask",
377 "directory mode,directory mask",
381 "only guest,guest only",
382 "user,username,users",
383 "default,default service",
384 "auto services,preload",
385 "lock directory,lock dir",
386 "max xmit,max packet",
387 "root directory,root dir,root",
388 "case sensitive,case sig names",
389 "idmap uid,winbind uid",
390 "idmap gid,winbind gid",
392 foreach $s (@synon) {
393 foreach $ss (split(/,/ , $s)) {
399 # Default values for samba configuration parameters
400 %default_values = ( "allow hosts",undef,
401 "alternate permissions","no",
407 "directory mode","755",
408 "default case","lower",
409 "case sensitive","no",
411 "preserve case","yes",
412 "short preserve case","yes",
413 "delete readonly","no",
415 "dont descend",undef,
418 "force create mode","000",
419 "force directory mode","000",
420 "guest account","nobody", # depends
422 "hide dot files","yes",
423 "invalid users",undef,
425 "lppause command",undef, # depends
426 "lpq command",undef, # depends
427 "lpresume command",undef, # depends
428 "lprm command",undef, #depends
429 "magic output",undef, # odd..
430 "magic script",undef,
432 "mangled names","yes",
442 "level2 oplocks","no",
443 "load printers","yes",
448 "print command",undef,
449 # "print command","lpr -r -P %p %s",
451 "printer driver",undef,
455 "root preexec",undef,
456 "root postexec",undef,
457 "set directory","no",
459 "socket options","TCP_NODELAY",
460 "strict locking","no",
462 "unix password sync","no",
465 "volume",undef, # depends
470 "winbind cache time",300,
471 "winbind enable local accounts","yes",
472 "winbind trusted domains only","no",
473 "winbind enum users","yes",
474 "winbind enum groups","yes",
476 $default_values{'encrypt passwords'} = 'yes' if ($samba_version >= 3);
479 # Convert a samba unix user list into a more readable form
483 foreach $u (split(/[ \t,]+/ , $_[0])) {
484 if ($u =~ /^\@(.*)$/) {
485 push(@rv, "group <tt>".&html_escape($1)."</tt>");
488 push(@rv, "<tt>".&html_escape($u)."</tt>");
491 return join("," , @rv);
497 ($n = $_[0]) =~ s/ /_/g;
498 return sprintf "<input type=radio name=$n value=yes %s> $text{'yes'}\n".
499 "<input type=radio name=$n value=no %s> $text{'no'}\n",
500 &istrue($_[0]) ? "checked" : "",
501 &isfalse($_[0]) ? "checked" : "";
504 # username_input(name)
505 # Outputs HTML for an username field
508 ($n = $_[0]) =~ s/ /_/g;
510 print "<td><input name=$n size=8 value=\"$v\"> ",
511 &user_chooser_button($n, 0),"</td>\n";
514 # username_input(name, default)
517 ($n = $_[0]) =~ s/ /_/g;
519 print "<td><input name=$n size=8 value=\"$v\"> ",
520 &group_chooser_button($n, 0),"</td>\n";
525 @sock_opts = ("SO_KEEPALIVE", "SO_REUSEADDR", "SO_BROADCAST", "TCP_NODELAY",
526 "IPTOS_LOWDELAY", "IPTOS_THROUGHPUT", "SO_SNDBUF*", "SO_RCVBUF*",
527 "SO_SNDLOWAT*", "SO_RCVLOWAT*");
529 @protocols = ("CORE", "COREPLUS", "LANMAN1", "LANMAN2", "NT1");
533 # Returns an array of all the users from the samba password file
536 local(@rv, @b, $_, $lnum);
538 # Get list of users from the pdbedit command, which uses a configurable
539 # back-end for storage
540 &open_execute_command(PASS, "cd / && $config{'pdbedit'} -L -w -s $config{'smb_conf'}", 1);
543 # Read the password file directly
544 &open_readfile(PASS, $config{'smb_passwd'});
550 local @b = split(/:/, $_);
552 local $u = { 'name' => $b[0], 'uid' => $b[1],
553 'pass1' => $b[2], 'pass2' => $b[3],
554 'oldname' => $b[0] };
555 if ($samba_version >= 2 && $b[4] =~ /^\[/) {
556 $b[4] =~ s/[\[\] ]//g;
557 $u->{'opts'} = [ split(//, $b[4]) ];
558 $u->{'change'} = $b[5];
561 $u->{'real'} = $b[4];
562 $u->{'home'} = $b[5];
563 $u->{'shell'} = $b[6];
565 $u->{'index'} = scalar(@rv);
566 $u->{'line'} = $lnum-1;
573 # smbpasswd_cmd(args)
574 # Returns the full smbpasswd command with extra args
578 return $config{'samba_password_program'}.
579 ($samba_version >= 3 ? " -c " : " -s ").
580 $config{'smb_conf'}." ".$args;
584 # Add a user to the samba password file
588 # Use the pdbedit command
589 local $ws = &indexof("W", @{$_[0]->{'opts'}}) >= 0 ? "-m" : "";
590 local @opts = grep { $_ ne "U" && $_ ne "W" } @{$_[0]->{'opts'}};
591 local $out = &backquote_logged(
592 "cd / && $config{'pdbedit'} -a -s $config{'smb_conf'} -u ".
593 quotemeta($_[0]->{'name'}).
594 ($config{'sync_gid'} ? " -G $config{'sync_gid'}" : "").
595 " -c '[".join("", @opts)."]' $ws");
596 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
599 # Try using smbpasswd -a
600 local $out = &backquote_logged(
601 "cd / && ".&smbpasswd_cmd(
603 (&indexof("D", @{$_[0]->{'opts'}}) >= 0 ? "-d " : "").
604 (&indexof("N", @{$_[0]->{'opts'}}) >= 0 ? "-n " : "").
605 (&indexof("W", @{$_[0]->{'opts'}}) >= 0 ? "-m " : "").
606 quotemeta($_[0]->{'name'})));
608 # Add direct to Samba password file
609 &open_tempfile(PASS, ">>$config{'smb_passwd'}");
610 &print_tempfile(PASS, &user_string($_[0]));
611 &close_tempfile(PASS);
612 chown(0, 0, $config{'smb_passwd'});
613 chmod(0600, $config{'smb_passwd'});
619 # Change an existing samba user
623 # Use the pdbedit command
624 if ($_[0]->{'oldname'} ne "" && $_[0]->{'oldname'} ne $_[0]->{'name'}) {
625 # Username changed! Have to delete and re-create
626 local $out = &backquote_logged(
627 "cd / && $config{'pdbedit'} -x -s $config{'smb_conf'} -u ".
628 quotemeta($_[0]->{'oldname'}));
629 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
634 local @opts = grep { $_ ne "U" } @{$_[0]->{'opts'}};
635 &indexof("W", @{$_[0]->{'opts'}}) >= 0 && &error($text{'saveuser_ews'});
636 $out = &backquote_logged(
637 "cd / && $config{'pdbedit'} -r -s $config{'smb_conf'} -u ".
638 quotemeta($_[0]->{'name'}).
639 " -c '[".join("", @opts)."]' 2>&1");
640 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
644 if (!$_[0]->{'oldname'} || $_[0]->{'oldname'} eq $_[0]->{'name'}) {
645 # Try using smbpasswd command
646 local $out = &backquote_logged(
647 "cd / && ".&smbpasswd_cmd(
648 (&indexof("D", @{$_[0]->{'opts'}}) >= 0 ? "-d "
650 quotemeta($_[0]->{'name'})));
653 # Also directly update the Samba password file
654 &replace_file_line($config{'smb_passwd'}, $_[0]->{'line'},
655 &user_string($_[0]));
660 # Delete a samba user
664 # Use the pdbedit command
665 local $out = &backquote_logged(
666 "cd / && $config{'pdbedit'} -x -s $config{'smb_conf'} -u ".
667 quotemeta($_[0]->{'name'}));
668 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
671 # Try the smbpasswd command
672 local $out = &backquote_logged(
673 "cd / && ".&smbpasswd_cmd("-x ".quotemeta($_[0]->{'name'})));
675 # Just remove from the Samba password file
676 &replace_file_line($config{'smb_passwd'}, $_[0]->{'line'});
683 local @u = ($_[0]->{'name'}, $_[0]->{'uid'},
684 $_[0]->{'pass1'}, $_[0]->{'pass2'});
685 if ($_[0]->{'opts'}) {
686 push(@u, sprintf "[%-11s]", join("", @{$_[0]->{'opts'}}));
687 push(@u, sprintf "LCT-%X", time());
691 push(@u, $_[0]->{'real'}, $_[0]->{'home'}, $_[0]->{'shell'});
693 return join(":", @u)."\n";
696 # set_password(user, password, [&output])
697 # Changes the password of a user in the encrypted password file
700 local $qu = quotemeta($_[0]);
701 local $qp = quotemeta($_[1]);
702 if ($samba_version >= 2) {
703 local $passin = "$_[1]\n$_[1]\n";
704 local $ex = &execute_command(
705 &smbpasswd_cmd("-s $qu"), \$passin, $_[2], $_[2]);
711 &execute_command("$config{'samba_password_program'} $qu $qp",
712 undef, $_[2], $_[2]);
713 return $out =~ /changed/i;
718 # Returns 0 if not, 1 if it is, or 2 if run from (x)inetd
721 local ($found_inet, @smbpids, @nmbpids);
722 if (&foreign_check("inetd")) {
723 &foreign_require("inetd", "inetd-lib.pl");
724 foreach $inet (&foreign_call("inetd", "list_inets")) {
725 $found_inet++ if (($inet->[8] =~ /smbd/ ||
726 $inet->[9] =~ /smbd/) && $inet->[1]);
729 elsif (&foreign_check("xinetd")) {
730 &foreign_require("xinetd", "xinetd-lib.pl");
731 foreach $xi (&foreign_call("xinetd", "get_xinetd_config")) {
732 local $q = $xi->{'quick'};
733 $found_inet++ if ($q->{'disable'}->[0] ne 'yes' &&
734 $q->{'server'}->[0] =~ /smbd/);
737 @smbpids = &find_byname("smbd");
738 @nmbpids = &find_byname("nmbd");
739 return !$found_inet && !@smbpids && !@nmbpids ? 0 :
740 !$found_inet ? 1 : 2;
743 # is_winbind_running()
744 # Returns 0 if not, 1 if it is
745 sub is_winbind_running
748 @wbpids = &find_byname("winbindd");
749 return !@wbpids ? 0 : 1;
752 # can($permissions_string, \%access, [$sname])
753 # check global and per-share permissions:
755 # $permissions_string = any exists permissions except 'c' (creation).
756 # \%access = ref on what get_module_acl() returns.
759 local ($acl, $stype, @perm);
760 local ($perm, $acc, $sname) = @_;
761 @perm = split(//, $perm);
762 $sname = $in{'old_name'} || $in{'share'} unless $sname;
765 &get_share($sname); # use local %share
766 $stype = &istrue('printable') ? 'ps' : 'fs';
769 # check global acl (r,w)
771 next if ($_ ne 'r') && ($_ ne 'w');
772 return 0 unless $acc->{$_ . '_' . $stype};
775 # check per-share acl
776 if ($acc->{'per_' . $stype . '_acls'}) {
777 $acl = $acc->{'ACL' . $stype . '_' . $sname};
779 # next if $_ eq 'c'; # skip creation perms for per-share acls
780 return 0 if index($acl, $_) == -1;
786 # save_samba_acl($permissions_string, \%access, $share_name)
789 local ($p, $a, $s)=@_;
790 %share || &get_share($s); # use global %share
791 local $t=&istrue('printable') ? 'ps' : 'fs';
792 $a->{'ACL'. $t .'_'. $s} = $p;
794 return &save_module_acl($a);
797 # drop_samba_acl(\%access, $share_name)
801 %share || &get_share($s); # use global %share
802 local $t=&istrue('printable') ? 'ps' : 'fs';
803 delete($a->{'ACL'. $t .'_' . $s});
805 return &save_module_acl($a);
809 # Returns an array containing details of Samba groups
812 local (@rv, $group, $cmd);
813 if ($has_smbgroupedit) {
814 $cmd = "$config{'smbgroupedit'} -v -l";
817 $cmd = "$config{'net'} -s $config{'smb_conf'} groupmap list verbose";
819 &open_execute_command(GROUPS, $cmd, 1);
823 $group = { 'name' => $1,
824 'index' => scalar(@rv) };
827 elsif (/^\s+SID\s*:\s+(.*)/i) {
828 $group->{'sid'} = $1;
830 elsif (/^\s+Unix group\s*:\s*(.*)/i) {
831 $group->{'unix'} = $1;
833 elsif (/^\s+Group type\s*:\s*(.*)/i) {
834 $group->{'type'} = lc($1) eq 'domain group' ? 'd' :
835 lc($1) eq 'nt builtin' ? 'b' :
836 lc($1) eq 'unknown type' ? 'u' :
837 lc($1) eq 'local group' ? 'l' : $1;
839 elsif (/^\s+Comment\s*:\s*(.*)/i) {
840 $group->{'desc'} = $1;
842 elsif (/^\s+Privilege\s*:\s*(.*)/i) {
843 $group->{'priv'} = lc($1) eq 'no privilege' ? undef : $1;
850 # delete_group(&group)
851 # Delete an existing Samba group
855 if ($has_smbgroupedit) {
856 $out = &backquote_logged("$config{'smbgroupedit'} -x ".quotemeta($_[0]->{'name'})." 2>&1");
857 $? && &error("$config{'smbgroupedit'} failed : <pre>$out</pre>");
860 $out = &backquote_logged("$config{'net'} -s $config{'smb_conf'} groupmap delete ntgroup=".quotemeta($_[0]->{'name'})." 2>&1");
861 $? && &error("$config{'net'} failed : <pre>$out</pre>");
865 # modify_group(&group)
866 # Update the details of an existing Samba group
870 if ($has_smbgroupedit) {
871 $out = &backquote_logged(
872 $config{'smbgroupedit'}.
873 " -c ".quotemeta($_[0]->{'sid'}).
874 ($_[0]->{'unix'} == -1 ? "" :" -u ".quotemeta($_[0]->{'unix'})).
875 ($_[0]->{'desc'} ? " -d ".quotemeta($_[0]->{'desc'}) :" -d ''").
876 " -t ".$_[0]->{'type'}.
878 $? && &error("$config{'smbgroupedit'} failed : <pre>$out</pre>");
881 $out = &backquote_logged(
882 "$config{'net'} -s $config{'smb_conf'} groupmap modify".
883 " sid=".quotemeta($_[0]->{'sid'}).
884 ($_[0]->{'unix'} == -1 ? "" :
885 " unixgroup=".quotemeta($_[0]->{'unix'})).
886 ($_[0]->{'desc'} ? " comment=".quotemeta($_[0]->{'desc'})
888 " type=".quotemeta($_[0]->{'type'})." 2>&1");
889 $? && &error("$config{'net'} failed : <pre>$out</pre>");
893 # create_group(&group)
894 # Add a Samba new group
898 if ($has_smbgroupedit) {
899 $out = &backquote_logged(
900 $config{'smbgroupedit'}.
901 " -a ".quotemeta($_[0]->{'unix'}).
902 " -n ".quotemeta($_[0]->{'name'}).
903 ($_[0]->{'priv'} ? " -p ".quotemeta($_[0]->{'priv'}) : "").
904 ($_[0]->{'desc'} ? " -d ".quotemeta($_[0]->{'desc'}) :" -d ''").
905 " -t ".$_[0]->{'type'}." 2>&1");
906 $? && &error("$config{'smbgroupedit'} failed : <pre>$out</pre>");
909 $out = &backquote_logged("$config{'net'} -s $config{'smb_conf'} maxrid 2>&1");
910 local $maxrid = $out =~ /rid:\s+(\d+)/ ? $1 + 1 : undef;
911 $maxrid = 1000 if ($maxrid < 1000); # Should be >1000
912 $out = &backquote_logged(
913 "$config{'net'} -s $config{'smb_conf'} groupmap add".
915 " unixgroup=".quotemeta($_[0]->{'unix'}).
916 " ntgroup=".quotemeta($_[0]->{'name'}).
917 " type=".quotemeta($_[0]->{'type'})." 2>&1");
918 $? && &error("<pre>$out</pre>");
919 $out = &backquote_logged(
920 "$config{'net'} groupmap modify".
921 " ntgroup=".quotemeta($_[0]->{'name'}).
922 ($_[0]->{'desc'} ? " comment=".quotemeta($_[0]->{'desc'})
924 " type=".quotemeta($_[0]->{'type'})." 2>&1");
925 $? && &error("$config{'net'} failed : <pre>$out</pre>");
929 # get_samba_version(&out, [keep-original-format])
930 # Returns the Samba version
931 sub get_samba_version
934 foreach $flag ("-V", "-v") {
935 &execute_command("$config{'samba_server'} $flag", undef, $_[0], $_[0]);
936 if (${$_[0]} =~ /(Version|Samba)\s+(CVS\s+)?[^0-9 ]*(\d+)\.(\S+)/i) {
948 sub check_user_enabled
951 &get_share("global");
952 if (!&istrue("encrypt passwords")) {
953 $err = &text('check_user1', $_[0], "conf_pass.cgi");
955 elsif (!$config{'smb_passwd'} && !$has_pdbedit) {
956 $err = &text('check_user2', $_[0], "../config.cgi?$module_name");
959 print "<p>$err<p>\n";
961 &footer("", $text{'index_sharelist'});
966 sub check_group_enabled
968 if ($samba_version < 3) {
969 $err = &text('check_groups1', $_[0]);
971 elsif (!$has_groups) {
972 $err = &text('check_groups2', $_[0], "../config.cgi?$module_name");
975 print "<p>$err<p>\n";
977 &footer("", $text{'index_sharelist'});