User and group ACL saving
authorJamie Cameron <jcameron@webmin.com>
Sun, 12 Sep 2010 20:21:38 +0000 (13:21 -0700)
committerJamie Cameron <jcameron@webmin.com>
Sun, 12 Sep 2010 20:21:38 +0000 (13:21 -0700)
acl/save_acl.cgi
lang/en
miniserv.pl
web-lib-funcs.pl

index ec8b151..bc0b29d 100755 (executable)
@@ -24,7 +24,18 @@ $aclfile = $in{'_acl_group'} ? "$config_directory/$in{'_acl_mod'}/$who.gacl"
                             : "$config_directory/$in{'_acl_mod'}/$who.acl";
 if ($in{'reset'}) {
        # Just remove the .acl file
-       &unlink_logged($aclfile);
+       &lock_file($aclfile);
+       if ($in{'_acl_group'}) {
+               # For a group
+               &save_group_module_acl(undef, $in{'_acl_group'},
+                                      $in{'_acl_mod'}, 1);
+               }
+       else {
+               # For a user
+               &save_module_acl(undef, $in{'_acl_user'},
+                                $in{'_acl_mod'},1);
+               }
+       &unlock_file($aclfile);
        $in{'moddesc'} = $minfo{'desc'};
        &webmin_log("reset", undef, $who, \%in);
        }
@@ -43,15 +54,28 @@ else {
                &foreign_call($in{'_acl_mod'}, "acl_security_save",
                              \%maccess, \%in);
                }
+
+       # Write out the ACL
        &lock_file($aclfile);
-       &write_file($aclfile, \%maccess);
-       chmod(0640, $aclfile);
+       if ($in{'_acl_group'}) {
+               # For a group
+               &save_group_module_acl(\%maccess, $in{'_acl_group'},
+                                      $in{'_acl_mod'}, 1);
+               }
+       else {
+               # For a user
+               &save_module_acl(\%maccess, $in{'_acl_user'},
+                                $in{'_acl_mod'},1);
+               }
+       chmod(0640, $aclfile) if (-r $aclfile);
        &unlock_file($aclfile);
+
        %minfo = $in{'_acl_mod'} ? &get_module_info($in{'_acl_mod'})
                                 : ( 'desc' => $text{'index_global'} );
 
        if ($in{'_acl_group'}) {
                # Recursively update the ACL for all member users and groups
+               # XXX ACL in DB?
                @ulist = &list_users();
                @glist = &list_groups();
                ($group) = grep { $_->{'name'} eq $in{'_acl_group'} } @glist;
diff --git a/lang/en b/lang/en
index c2b07b8..19cf209 100644 (file)
--- a/lang/en
+++ b/lang/en
@@ -65,6 +65,10 @@ cancel=Cancel
 helpsearch=Search Docs..
 switch_remote_euser=The Unix user $1 does not exist.
 programname=Webmin
+euserdbacl=Failed to fetch user ACL : $1
+euserdbacl2=Failed to update user ACL : $1
+egroupdbacl=Failed to fetch group ACL : $1
+egroupdbacl2=Failed to update group ACL : $1
 
 chooser_title1=Choose File..
 chooser_title2=Choose Directory..
index e82c027..cd7a18d 100755 (executable)
@@ -4055,6 +4055,17 @@ if ($config{'userfile'}) {
                }
        close(USERS);
        }
+
+# Test user DB, if configured
+if ($config{'userdb'}) {
+       my $dbh = &connect_userdb($config{'userdb'});
+       if (!ref($dbh)) {
+               print STDERR "Failed to open users database : $dbh\n"
+               }
+       else {
+               &disconnect_userdb($config{'userdb'}, $dbh);
+               }
+       }
 }
 
 # get_user_details(username)
index c47b9de..8bae4fe 100755 (executable)
@@ -1733,7 +1733,7 @@ if (!%main::acl_hash_cache) {
                                        $main::acl_array_cache{$user} = \@mods;
                                        }
                                }
-                       $cmd->finish();
+                       $cmd->finish() if ($cmd);
                        }
                elsif ($proto eq "ldap") {
                        # XXX read from LDAP
@@ -3314,15 +3314,49 @@ elsif ($gconfig{"risk_$u"} && $m) {
        }
 elsif ($u ne '') {
        # Use normal Webmin ACL, if a user is set
-       my %miniserv;
-       &get_miniserv_config(\%miniserv);
-       if ($miniserv{'userdb'}) {
+       my $userdb = &get_userdb_string();
+       my $foundindb = 0;
+       if ($userdb) {
                # Look for this user in the user/group DB
-               # XXX
+               my ($dbh, $proto) = &connect_userdb($userdb);
+               ref($dbh) || &error(&text('euserdbacl', $dbh));
+               if ($proto eq "mysql" || $proto eq "postgresql") {
+                       # Find the user in the SQL DB
+                       my $cmd = $dbh->prepare(
+                               "select id from webmin_user where name = ?");
+                       $cmd && $cmd->execute($u) ||
+                               &error(&text('euserdbacl', $dbh->errstr));
+                       my ($id) = $cmd->fetchrow();
+                       $foundindb = 1 if (defined($id));
+                       $cmd->finish();
+
+                       # Fetch ACLs with SQL
+                       if ($foundindb) {
+                               my $cmd = $dbh->prepare(
+                                   "select attr,value from webmin_user_acl ".
+                                   "where id = ? and module = ?");
+                               $cmd && $cmd->execute($id, $m) ||
+                                   &error(&text('euserdbacl', $dbh->errstr));
+                               while(my ($a, $v) = $cmd->fetchrow()) {
+                                       $rv{$a} = $v;
+                                       }
+                               $cmd->finish();
+                               }
+                       }
+               elsif ($proto eq "ldap") {
+                       # Fetch ACLs from LDAP
+                       # XXX
+                       }
+               &disconnect_userdb($userdb, $dbh);
                }
-       &read_file_cached("$config_directory/$m/$u.acl", \%rv);
-       if ($remote_user ne $base_remote_user && !defined($_[0])) {
-               &read_file_cached("$config_directory/$m/$remote_user.acl",\%rv);
+
+       if (!$foundindb) {
+               # Read from local files
+               &read_file_cached("$config_directory/$m/$u.acl", \%rv);
+               if ($remote_user ne $base_remote_user && !defined($_[0])) {
+                       &read_file_cached(
+                               "$config_directory/$m/$remote_user.acl",\%rv);
+                       }
                }
        }
 if ($tconfig{'preload_functions'}) {
@@ -3354,22 +3388,24 @@ if (defined(&theme_get_module_acl)) {
 return %rv;
 }
 
-=head2 save_module_acl(&acl, [user], [module])
+=head2 save_module_acl(&acl, [user], [module], [never-update-group])
 
 Updates the acl hash for some user and module. The parameters are :
 
-=item acl - Hash reference for the new access control options.
+=item acl - Hash reference for the new access control options, or undef to clear
 
 =item user - User to update, defaulting to the current user.
 
 =item module - Module to update, defaulting to the caller.
 
+=item never-update-group - Never update the user's group's ACL
+
 =cut
 sub save_module_acl
 {
 my $u = defined($_[1]) ? $_[1] : $base_remote_user;
 my $m = defined($_[2]) ? $_[2] : &get_module_name();
-if (&foreign_check("acl")) {
+if (!$_[3] && &foreign_check("acl")) {
        # Check if this user is a member of a group, and if he gets the
        # module from a group. If so, update its ACL as well
        &foreign_require("acl", "acl-lib.pl");
@@ -3385,13 +3421,67 @@ if (&foreign_check("acl")) {
                &save_group_module_acl($_[0], $group->{'name'}, $m);
                }
        }
-if (!-d "$config_directory/$m") {
-       mkdir("$config_directory/$m", 0755);
+
+my $userdb = &get_userdb_string();
+my $foundindb = 0;
+if ($userdb) {
+       # Look for this user in the user/group DB
+       my ($dbh, $proto) = &connect_userdb($userdb);
+       ref($dbh) || &error(&text('euserdbacl', $dbh));
+       if ($proto eq "mysql" || $proto eq "postgresql") {
+               # Find the user in the SQL DB
+               my $cmd = $dbh->prepare(
+                       "select id from webmin_user where name = ?");
+               $cmd && $cmd->execute($u) ||
+                       &error(&text('euserdbacl2', $dbh->errstr));
+               my ($id) = $cmd->fetchrow();
+               $foundindb = 1 if (defined($id));
+               $cmd->finish();
+
+               # Replace ACLs for user
+               if ($foundindb) {
+                       my $cmd = $dbh->prepare("delete from webmin_user_acl ".
+                                               "where id = ? and module = ?");
+                       $cmd && $cmd->execute($id, $m) ||
+                           &error(&text('euserdbacl', $dbh->errstr));
+                       $cmd->finish();
+                       if ($_[0]) {
+                               my $cmd = $dbh->prepare(
+                                   "insert into webmin_user_acl ".
+                                   "(id,module,attr,value) values (?,?,?,?)");
+                               $cmd || &error(&text('euserdbacl2',
+                                                    $dbh->errstr));
+                               foreach my $a (keys %{$_[0]}) {
+                                       $cmd->execute($id,$m,$a,$_[0]->{$a}) ||
+                                           &error(&text('euserdbacl2',
+                                                        $dbh->errstr));
+                                       $cmd->finish();
+                                       }
+                               }
+                       }
+               }
+       elsif ($proto eq "ldap") {
+               # Update ACLs in LDAP
+               # XXX
+               }
+       &disconnect_userdb($userdb, $dbh);
+       }
+
+if (!$foundindb) {
+       # Save ACL to local file
+       if (!-d "$config_directory/$m") {
+               mkdir("$config_directory/$m", 0755);
+               }
+       if ($_[0]) {
+               &write_file("$config_directory/$m/$u.acl", $_[0]);
+               }
+       else {
+               &unlink_file("$config_directory/$m/$u.acl");
+               }
        }
-&write_file("$config_directory/$m/$u.acl", $_[0]);
 }
 
-=head2 save_group_module_acl(&acl, group, [module])
+=head2 save_group_module_acl(&acl, group, [module], [never-update-group])
 
 Updates the acl hash for some group and module. The parameters are :
 
@@ -3401,12 +3491,14 @@ Updates the acl hash for some group and module. The parameters are :
 
 =item module - Module to update, defaulting to the caller.
 
+=item never-update-group - Never update the parent group's ACL
+
 =cut
 sub save_group_module_acl
 {
 my $g = $_[1];
 my $m = defined($_[2]) ? $_[2] : &get_module_name();
-if (&foreign_check("acl")) {
+if (!$_[3] && &foreign_check("acl")) {
        # Check if this group is a member of a group, and if it gets the
        # module from a group. If so, update the parent ACL as well
        &foreign_require("acl", "acl-lib.pl");
@@ -3422,10 +3514,66 @@ if (&foreign_check("acl")) {
                &save_group_module_acl($_[0], $group->{'name'}, $m);
                }
        }
-if (!-d "$config_directory/$m") {
-       mkdir("$config_directory/$m", 0755);
+
+my $userdb = &get_userdb_string();
+my $foundindb = 0;
+if ($userdb) {
+       # Look for this group in the user/group DB
+       my ($dbh, $proto) = &connect_userdb($userdb);
+       ref($dbh) || &error(&text('egroupdbacl', $dbh));
+       if ($proto eq "mysql" || $proto eq "postgresql") {
+               # Find the group in the SQL DB
+               my $cmd = $dbh->prepare(
+                       "select id from webmin_group where name = ?");
+               $cmd && $cmd->execute($u) ||
+                       &error(&text('egroupdbacl2', $dbh->errstr));
+               my ($id) = $cmd->fetchrow();
+               $foundindb = 1 if (defined($id));
+               $cmd->finish();
+
+               # Replace ACLs for group
+               if ($foundindb) {
+                       my $cmd = $dbh->prepare("delete from webmin_group_acl ".
+                                               "where id = ? and module = ?");
+                       $cmd && $cmd->execute($id, $m) ||
+                           &error(&text('egroupdbacl', $dbh->errstr));
+                       $cmd->finish();
+                       if ($_[0]) {
+                               my $cmd = $dbh->prepare(
+                                   "insert into webmin_group_acl ".
+                                   "(id,module,attr,value) values (?,?,?,?)");
+                               $cmd || &error(&text('egroupdbacl2',
+                                                    $dbh->errstr));
+                               foreach my $a (keys %{$_[0]}) {
+                                       $cmd->execute($id,$m,$a,$_[0]->{$a}) ||
+                                           &error(&text('egroupdbacl2',
+                                                        $dbh->errstr));
+                                       $cmd->finish();
+                                       }
+                               }
+                       }
+               }
+       elsif ($proto eq "ldap") {
+               # Update ACLs in LDAP
+               # XXX
+               }
+       &disconnect_userdb($userdb, $dbh);
+       }
+
+
+
+if (!$foundindb) {
+       # Save ACL to local file
+       if (!-d "$config_directory/$m") {
+               mkdir("$config_directory/$m", 0755);
+               }
+       if ($_[0]) {
+               &write_file("$config_directory/$m/$g.gacl", $_[0]);
+               }
+       else {
+               &unlink_file("$config_directory/$m/$g.gacl");
+               }
        }
-&write_file("$config_directory/$m/$g.gacl", $_[0]);
 }
 
 =head2 init_config