7f03b9e531881dd976499353975437bec04aaaa3
[pve-access-control.git] / PVE / Auth / PVE.pm
1 package PVE::Auth::PVE;
2
3 use strict;
4 use warnings;
5
6 use PVE::Auth::Plugin;
7 use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
8
9 use base qw(PVE::Auth::Plugin);
10
11 my $shadowconfigfile = "priv/shadow.cfg";
12
13 cfs_register_file($shadowconfigfile, 
14                   \&parse_shadow_passwd, 
15                   \&write_shadow_config);
16
17 sub parse_shadow_passwd {
18     my ($filename, $raw) = @_;
19
20     my $shadow = {};
21
22     while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
23         my $line = $1;
24
25         next if $line =~ m/^\s*$/; # skip empty lines
26
27         if ($line !~ m/^\S+:\S+:$/) {
28             warn "pve shadow password: ignore invalid line $.\n";
29             next;
30         }
31
32         my ($userid, $crypt_pass) = split (/:/, $line);
33         $shadow->{users}->{$userid}->{shadow} = $crypt_pass;
34     }
35
36     return $shadow;
37 }
38
39 sub write_shadow_config {
40     my ($filename, $cfg) = @_;
41
42     my $data = '';
43     foreach my $userid (keys %{$cfg->{users}}) {
44         my $crypt_pass = $cfg->{users}->{$userid}->{shadow};
45         $data .= "$userid:$crypt_pass:\n";
46     }
47
48     return $data
49 }
50
51 sub lock_shadow_config {
52     my ($code, $errmsg) = @_;
53
54     cfs_lock_file($shadowconfigfile, undef, $code);
55     my $err = $@;
56     if ($err) {
57         $errmsg ? die "$errmsg: $err" : die $err;
58     }
59 }
60
61 sub type {
62     return 'pve';
63 }
64
65 sub options {
66     return {
67         default => { optional => 1 },
68         comment => { optional => 1 },
69         tfa => { optional => 1 },
70     };
71 }
72
73 sub authenticate_user {
74     my ($class, $config, $realm, $username, $password) = @_;
75
76     die "no password\n" if !$password;
77
78     my $shadow_cfg = cfs_read_file($shadowconfigfile);
79     
80     if ($shadow_cfg->{users}->{$username}) {
81         my $encpw = crypt($password, $shadow_cfg->{users}->{$username}->{shadow});
82         die "invalid credentials\n" if ($encpw ne $shadow_cfg->{users}->{$username}->{shadow});
83     } else {
84         die "no password set\n";
85     }
86
87     return 1;
88 }
89
90 sub store_password {
91     my ($class, $config, $realm, $username, $password) = @_;
92
93     lock_shadow_config(sub {
94         my $shadow_cfg = cfs_read_file($shadowconfigfile);
95         my $epw = PVE::Auth::Plugin::encrypt_pw($password);
96         $shadow_cfg->{users}->{$username}->{shadow} = $epw;
97         cfs_write_file($shadowconfigfile, $shadow_cfg);
98     });
99 }
100
101 sub delete_user {
102     my ($class, $config, $realm, $username) = @_;
103  
104     lock_shadow_config(sub {
105         my $shadow_cfg = cfs_read_file($shadowconfigfile);
106
107         delete $shadow_cfg->{users}->{$username};
108
109         cfs_write_file($shadowconfigfile, $shadow_cfg);
110    });
111 }
112
113 1;