improve parse_user_config, parse_shadow_config
[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 =~ /^\s*(.+?)\s*$/gm) {
23         my $line = $1;
24
25         if ($line !~ m/^\S+:\S+:$/) {
26             warn "pve shadow password: ignore invalid line $.\n";
27             next;
28         }
29
30         my ($userid, $crypt_pass) = split (/:/, $line);
31         $shadow->{users}->{$userid}->{shadow} = $crypt_pass;
32     }
33
34     return $shadow;
35 }
36
37 sub write_shadow_config {
38     my ($filename, $cfg) = @_;
39
40     my $data = '';
41     foreach my $userid (keys %{$cfg->{users}}) {
42         my $crypt_pass = $cfg->{users}->{$userid}->{shadow};
43         $data .= "$userid:$crypt_pass:\n";
44     }
45
46     return $data
47 }
48
49 sub lock_shadow_config {
50     my ($code, $errmsg) = @_;
51
52     cfs_lock_file($shadowconfigfile, undef, $code);
53     my $err = $@;
54     if ($err) {
55         $errmsg ? die "$errmsg: $err" : die $err;
56     }
57 }
58
59 sub type {
60     return 'pve';
61 }
62
63 sub options {
64     return {
65         default => { optional => 1 },
66         comment => { optional => 1 },
67         tfa => { optional => 1 },
68     };
69 }
70
71 sub authenticate_user {
72     my ($class, $config, $realm, $username, $password) = @_;
73
74     die "no password\n" if !$password;
75
76     my $shadow_cfg = cfs_read_file($shadowconfigfile);
77     
78     if ($shadow_cfg->{users}->{$username}) {
79         my $encpw = crypt($password, $shadow_cfg->{users}->{$username}->{shadow});
80         die "invalid credentials\n" if ($encpw ne $shadow_cfg->{users}->{$username}->{shadow});
81     } else {
82         die "no password set\n";
83     }
84
85     return 1;
86 }
87
88 sub store_password {
89     my ($class, $config, $realm, $username, $password) = @_;
90
91     lock_shadow_config(sub {
92         my $shadow_cfg = cfs_read_file($shadowconfigfile);
93         my $epw = PVE::Auth::Plugin::encrypt_pw($password);
94         $shadow_cfg->{users}->{$username}->{shadow} = $epw;
95         cfs_write_file($shadowconfigfile, $shadow_cfg);
96     });
97 }
98
99 sub delete_user {
100     my ($class, $config, $realm, $username) = @_;
101  
102     lock_shadow_config(sub {
103         my $shadow_cfg = cfs_read_file($shadowconfigfile);
104
105         delete $shadow_cfg->{users}->{$username};
106
107         cfs_write_file($shadowconfigfile, $shadow_cfg);
108    });
109 }
110
111 1;