[pve-devel] r4864 - pve-access-control/trunk
svn-commits at proxmox.com
svn-commits at proxmox.com
Fri Jul 2 09:39:26 CEST 2010
Author: dietmar
Date: 2010-07-02 07:39:26 +0000 (Fri, 02 Jul 2010)
New Revision: 4864
Modified:
pve-access-control/trunk/AccessControl.pm
pve-access-control/trunk/ChangeLog
Log:
2010-07-02 Proxmox Support Team <support at proxmox.com>
* AccessControl.pm (lock_user_config): renamed from lock_config,
because we will have more then one config file (auth.conf, shadow
password, ...)
(modify_user): check for exceptions after lock_user_config()
(delete_user): check for exceptions after lock_user_config(),
raise invalid characters exception
(delete_group): check for exceptions after lock_user_config(),
raise invalid characters exception
(modify_role): check for exceptions after lock_user_config()
(delete_role): check for exceptions after lock_user_config(),
raise invalid characters exception
2010-07-01 Proxmox Support Team <support at proxmox.com>
* AccessControl.pm: implemented file locking functionality for all
processes that make modifications to configuration file (Seth) -
code for lock_file() was copied from QemuServer.pm.
Modified: pve-access-control/trunk/AccessControl.pm
===================================================================
--- pve-access-control/trunk/AccessControl.pm 2010-07-01 12:57:26 UTC (rev 4863)
+++ pve-access-control/trunk/AccessControl.pm 2010-07-02 07:39:26 UTC (rev 4864)
@@ -8,12 +8,16 @@
use Crypt::OpenSSL::Random;
use Crypt::OpenSSL::RSA;
use MIME::Base64;
+use Fcntl ':flock';
use Authen::PAM qw(:constants);
use Data::Dumper; # fixme: remove
# $authdir must be writable by root only!
my $authdir = "/etc/pve/auth";
-my $userconfigfn = "/etc/pve/user.cfg";
+my $confdir = "/etc/pve";
+my $userconfigfile = "user.cfg";
+my $userconfigpath = "$confdir/$userconfigfile";
+my $userconfiglock = "$confdir/.lock-$userconfigfile";
my $ticket_lifetime = 3600*2; # 2 hours
@@ -21,6 +25,71 @@
return $authdir;
}
+sub lock_user_config {
+ my ($code, @param) = @_;
+
+ my $parent = ( caller(1) )[3];
+
+ lock_file ($userconfiglock, $parent, $code, @param);
+}
+
+# flock: we use one file handle per process, so lock file
+# can be called multiple times and succeeds for the same process.
+
+my $lock_handles = {};
+
+sub lock_file {
+ my ($filename, $text, $code, @param) = @_;
+
+ my $timeout = 10;
+
+ my $res;
+
+ eval {
+
+ local $SIG{ALRM} = sub { die "got timeout\n"; };
+
+ alarm ($timeout);
+
+ if (!$lock_handles->{$$}->{$filename}) {
+ $lock_handles->{$$}->{$filename} = new IO::File (">>$filename") ||
+ die "can't open lock for $text '$filename' - $!\n";
+ }
+
+ if (!flock ($lock_handles->{$$}->{$filename}, LOCK_EX|LOCK_NB)) {
+ print STDERR "trying to aquire lock...";
+ if (!flock ($lock_handles->{$$}->{$filename}, LOCK_EX)) {
+ print STDERR " failed\n";
+ die "can't aquire lock for $text '$filename' - $!\n";
+ }
+ print STDERR " OK\n";
+ }
+ alarm (0);
+
+ $res = &$code (@param);
+ };
+
+ my $err = $@;
+
+ alarm (0);
+
+ if ($lock_handles->{$$}->{$filename}) {
+ my $fh = $lock_handles->{$$}->{$filename};
+ $lock_handles->{$$}->{$filename} = undef;
+ close ($fh);
+ }
+
+ if ($err) {
+ $@ = $err;
+ return undef;
+ }
+
+ $@ = undef;
+
+ return $res;
+}
+
+
sub file_set_contents {
my ($filename, $data, $perm) = @_;
@@ -435,81 +504,94 @@
sub modify_user {
my ($username, $opts) = @_;
+
+ lock_user_config (sub {
- my $domain;
+ my $domain;
- ($username, undef, $domain) = verify_username ($username);
+ ($username, undef, $domain) = verify_username ($username);
- die "modify failed: username '$username' contains invalid characters\n" if !$username;
-
- my $usercfg = load_user_config();
+ die "username '$username' contains invalid characters\n" if !$username;
+
+ my $usercfg = load_user_config();
- if ($opts->{create}) {
+ if ($opts->{create}) {
- die "user '$username' already exists\n"
- if $usercfg->{users}->{$username};
-
- warn "ignore password - can't set password on auth domain '$domain'\n" if $domain && $opts->{passwd};
+ die "user '$username' already exists\n"
+ if $usercfg->{users}->{$username};
+
+ warn "ignore password - can't set password on auth domain '$domain'\n" if $domain && $opts->{passwd};
- store_shadow_passwd() if !$domain && $opts->{passwd};
+ store_shadow_passwd() if !$domain && $opts->{passwd};
- enable_user ($username, $usercfg);
+ enable_user ($username, $usercfg);
- if ($opts->{groups}) {
- foreach my $group (split_list ($opts->{groups})) {
- if ($usercfg->{groups}->{$group}) {
- add_user_group ($username,$usercfg,$group);
- } else {
- warn "ignore group '$group' - no such group\n";
- next;
+ if ($opts->{groups}) {
+ foreach my $group (split_list ($opts->{groups})) {
+ if ($usercfg->{groups}->{$group}) {
+ add_user_group ($username,$usercfg,$group);
+ } else {
+ warn "ignore group '$group' - no such group\n";
+ next;
+ }
}
}
- }
- } else {
+ } else {
- die "user '$username' does not exist\n" if !$usercfg->{users}->{$username};
- store_shadow_passwd() if !$domain && $opts->{passwd};
- enable_user ($username,$usercfg) if $opts->{unlock} &&
- !$usercfg->{users}->{$username}->{enabled};
- disable_user ($username,$usercfg) if $opts->{lock} &&
- $usercfg->{users}->{$username}->{enabled};
- delete_user_group ($username,$usercfg) if (!$opts->{append} && $opts->{groups});
- if ($opts->{groups}) {
- foreach my $group (split_list ($opts->{groups})) {
- if ($usercfg->{groups}->{$group}) {
- add_user_group ($username,$usercfg,$group);
- } else {
- warn "ignore group '$group' - no such group\n";
- next;
+ die "user '$username' does not exist\n" if !$usercfg->{users}->{$username};
+ store_shadow_passwd() if !$domain && $opts->{passwd};
+ enable_user ($username,$usercfg) if $opts->{unlock} &&
+ !$usercfg->{users}->{$username}->{enabled};
+ disable_user ($username,$usercfg) if $opts->{lock} &&
+ $usercfg->{users}->{$username}->{enabled};
+ delete_user_group ($username,$usercfg) if (!$opts->{append} && $opts->{groups});
+ if ($opts->{groups}) {
+ foreach my $group (split_list ($opts->{groups})) {
+ if ($usercfg->{groups}->{$group}) {
+ add_user_group ($username,$usercfg,$group);
+ } else {
+ warn "ignore group '$group' - no such group\n";
+ next;
+ }
}
}
+
+ change_password ($username,$usercfg) if $opts->{password};
+ name_user ($username,$usercfg) if $opts->{name};
+ comment_user ($username,$usercfg) if $opts->{comment};
}
- change_password ($username,$usercfg) if $opts->{password};
- name_user ($username,$usercfg) if $opts->{name};
- comment_user ($username,$usercfg) if $opts->{comment};
- }
+ save_user_config ($usercfg);
+ });
- save_user_config ($usercfg);
+ my $err = $@;
+
+ die "modify user failed: $err" if $err;
}
sub delete_user {
my ($username) = @_;
+
+ lock_user_config (sub {
- ($username, undef, undef) = verify_username ($username);
+ ($username, undef, undef) = verify_username ($username);
+ die "username '$username' contains invalid characters\n" if !$username;
- my $usercfg = load_user_config();
+ my $usercfg = load_user_config();
- delete ($usercfg->{users}->{$username})
- if $usercfg->{users}->{$username};
+ delete ($usercfg->{users}->{$username})
+ if $usercfg->{users}->{$username};
- delete_user_group ($username,$usercfg);
- delete_user_acl ($username,$usercfg);
+ delete_user_group ($username,$usercfg);
+ delete_user_acl ($username,$usercfg);
+ save_user_config ($usercfg);
+ });
- save_user_config ($usercfg);
+ my $err = $@;
+ die "delete user failed: $err" if $err;
}
sub store_shadow_passwd {
@@ -589,31 +671,47 @@
sub add_group {
my ($group) = @_;
+
+ lock_user_config (sub {
- my $usercfg = load_user_config();
+ my $usercfg = load_user_config();
- die "add group failed: '$group' - invalid characters in group name\n" if (!verify_groupname ($group));
+ die "'$group' - invalid characters in group name\n" if (!verify_groupname ($group));
+
+ die "group '$group' already exists\n"
+ if $usercfg->{groups}->{$group};
+
+ $usercfg->{groups}->{$group} = {};
+
+ save_user_config ($usercfg);
- die "group '$group' already exists\n"
- if $usercfg->{groups}->{$group};
+ });
- $usercfg->{groups}->{$group} = {};
+ my $err = $@;
- save_user_config ($usercfg);
-
+ die "add group failed: $err" if $err;
}
sub delete_group {
my ($group) = @_;
- my $usercfg = load_user_config();
+ lock_user_config (sub {
- delete ($usercfg->{groups}->{$group})
- if $usercfg->{groups}->{$group};
+ die "'$group' - invalid characters in group name\n" if (!verify_groupname ($group));
- save_user_config ($usercfg);
+ my $usercfg = load_user_config();
+ delete ($usercfg->{groups}->{$group})
+ if $usercfg->{groups}->{$group};
+
+ save_user_config ($usercfg);
+
+ });
+
+ my $err = $@;
+
+ die "delete group failed: $err" if $err;
}
my $valid_privs = {
@@ -656,44 +754,60 @@
};
sub modify_role {
-
my ($role, $opts) = @_;
- my $usercfg = load_user_config();
- die "modify role '$role' failed - invalid characters in role name\n" if (!verify_rolename ($role));
+ lock_user_config (sub {
+
+ my $usercfg = load_user_config();
- if ($opts->{create}) {
- die "add role '$role' failed - role already exists\n" if $usercfg->{roles}->{$role};
- $usercfg->{roles}->{$role} = {};
- }
+ die "invalid characters in role name\n" if !verify_rolename ($role);
- die "modify role '$role' failed - role does not exist\n" if !$usercfg->{roles}->{$role};
+ if ($opts->{create}) {
+ die "can't add role '$role' - role already exists\n" if $usercfg->{roles}->{$role};
+ $usercfg->{roles}->{$role} = {};
+ }
- $usercfg->{roles}->{$role} = {} if !$opts->{append};
- if ($opts->{privs}) {
- foreach my $priv (split_list ($opts->{privs})) {
- if ($usercfg->{roles}->{$role} && defined ($valid_privs->{$priv})) {
- $usercfg->{roles}->{$role}->{$priv} = 1;
- } else {
- warn "modify role - ignore invalid priviledge '$priv'\n";
- }
- }
- }
+ die "role '$role' does not exist\n" if !$usercfg->{roles}->{$role};
- save_user_config ($usercfg);
+ $usercfg->{roles}->{$role} = {} if !$opts->{append};
+ if ($opts->{privs}) {
+ foreach my $priv (split_list ($opts->{privs})) {
+ if ($usercfg->{roles}->{$role} && defined ($valid_privs->{$priv})) {
+ $usercfg->{roles}->{$role}->{$priv} = 1;
+ } else {
+ warn "modify role - ignore invalid priviledge '$priv'\n";
+ }
+ }
+ }
+
+ save_user_config ($usercfg);
+ });
+
+ my $err = $@;
+
+ die "modify role failed: $err" if $err;
}
sub delete_role {
my ($role) = @_;
- my $usercfg = load_user_config();
+ lock_user_config (sub {
- delete ($usercfg->{roles}->{$role})
- if $usercfg->{roles}->{$role};
+ my $usercfg = load_user_config();
- save_user_config ($usercfg);
+ die "invalid characters in role name\n" if !verify_rolename ($role);
+ delete ($usercfg->{roles}->{$role})
+ if $usercfg->{roles}->{$role};
+
+ save_user_config ($usercfg);
+
+ });
+
+ my $err = $@;
+
+ die "delete role '$role' failed: $err" if $err;
}
sub split_list {
@@ -916,8 +1030,8 @@
my $cfg = {};
- my $fh = IO::File->new ($userconfigfn, 'r');
- $cfg = parse_config ($userconfigfn, $fh);
+ my $fh = IO::File->new ($userconfigpath, 'r');
+ $cfg = parse_config ($userconfigpath, $fh);
$fh->close() if $fh;
$user_config_cache = $cfg;
@@ -1013,7 +1127,7 @@
}
}
- file_set_contents($userconfigfn, $data, 0644);
+ file_set_contents($userconfigpath, $data, 0644);
}
sub roles {
Modified: pve-access-control/trunk/ChangeLog
===================================================================
--- pve-access-control/trunk/ChangeLog 2010-07-01 12:57:26 UTC (rev 4863)
+++ pve-access-control/trunk/ChangeLog 2010-07-02 07:39:26 UTC (rev 4864)
@@ -1,3 +1,23 @@
+2010-07-02 Proxmox Support Team <support at proxmox.com>
+
+ * AccessControl.pm (lock_user_config): renamed from lock_config,
+ because we will have more then one config file (auth.conf, shadow
+ password, ...)
+ (modify_user): check for exceptions after lock_user_config()
+ (delete_user): check for exceptions after lock_user_config(),
+ raise invalid characters exception
+ (delete_group): check for exceptions after lock_user_config(),
+ raise invalid characters exception
+ (modify_role): check for exceptions after lock_user_config()
+ (delete_role): check for exceptions after lock_user_config(),
+ raise invalid characters exception
+
+2010-07-01 Proxmox Support Team <support at proxmox.com>
+
+ * AccessControl.pm: implemented file locking functionality for all
+ processes that make modifications to configuration file (Seth) -
+ code for lock_file() was copied from QemuServer.pm.
+
2010-06-29 Proxmox Support Team <support at proxmox.com>
* pveum: new roleadd/rolemod/roledel (Seth)
More information about the pve-devel
mailing list