]> git.proxmox.com Git - pve-access-control.git/blobdiff - PVE/Auth/Plugin.pm
encrypt_pw: avoid '+' for crypt salt
[pve-access-control.git] / PVE / Auth / Plugin.pm
index e9d54f0147c943ddb340dcc04acb396c669c166f..3356f691c55d1b5ff8bc3e1b5c5a54e63ac57a8e 100755 (executable)
@@ -83,11 +83,65 @@ PVE::JSONSchema::register_standard_option('userid', {
     maxLength => 64,
 });
 
+PVE::JSONSchema::register_format('pve-tfa-config', \&verify_tfa_config);
+sub verify_tfa_config {
+    my ($value, $noerr) = @_;
+
+    return $value if parse_tfa_config($value);
+
+    return undef if $noerr;
+
+    die "unable to parse tfa option\n";
+}
+
+PVE::JSONSchema::register_standard_option('tfa', {
+    description => "Use Two-factor authentication.",
+    type => 'string', format => 'pve-tfa-config',
+    optional => 1,
+    maxLength => 128,
+});
+
+sub parse_tfa_config {
+    my ($data) = @_;
+
+    my $res = {};
+
+    foreach my $kvp (split(/,/, $data)) {
+
+       if ($kvp =~ m/^type=(yubico|oath)$/) {
+           $res->{type} = $1;
+       } elsif ($kvp =~ m/^id=(\S+)$/) {
+           $res->{id} = $1;
+       } elsif ($kvp =~ m/^key=(\S+)$/) {
+           $res->{key} = $1;
+       } elsif ($kvp =~ m/^url=(\S+)$/) {
+           $res->{url} = $1;
+       } elsif ($kvp =~ m/^digits=([6|7|8])$/) {
+           $res->{digits} = $1;
+       } elsif ($kvp =~ m/^step=([1-9]\d+)$/) {
+           $res->{step} = $1;
+       } else {
+           return undef;
+       }           
+    }
+
+    return undef if !$res->{type};
+
+    return $res;
+}
+
+my $salt_starter = time();
+
 sub encrypt_pw {
     my ($pw) = @_;
 
-    my $time = substr(Digest::SHA::sha1_base64 (time), 0, 8);
-    return crypt(encode("utf8", $pw), "\$5\$$time\$");
+    $salt_starter++;
+    my $salt = substr(Digest::SHA::sha1_base64(time() + $salt_starter + $$), 0, 8);
+
+    # crypt does not want '+' in salt (see 'man crypt')
+    $salt =~ s/\+/X/g;
+
+    return crypt(encode("utf8", $pw), "\$5\$$salt\$");
 }
 
 my $defaultData = {
@@ -140,16 +194,14 @@ sub parse_config {
 
     # add default domains
 
-    $cfg->{ids}->{pve} = {
-       type => 'pve',
-       comment => "Proxmox VE authentication server", 
-    };
+    $cfg->{ids}->{pve}->{type} = 'pve'; # force type
+    $cfg->{ids}->{pve}->{comment} = "Proxmox VE authentication server"
+       if !$cfg->{ids}->{pve}->{comment};
 
-    $cfg->{ids}->{pam} = {
-       type => 'pam',
-       plugin => 'PVE::Auth::PAM',
-       comment => "Linux PAM standard authentication", 
-    };
+    $cfg->{ids}->{pam}->{type} = 'pam'; # force type
+    $cfg->{ids}->{pam}->{plugin} =  'PVE::Auth::PAM';
+    $cfg->{ids}->{pam}->{comment} = "Linux PAM standard authentication"
+       if !$cfg->{ids}->{pam}->{comment};
 
     return $cfg;
 };
@@ -157,9 +209,6 @@ sub parse_config {
 sub write_config {
     my ($class, $filename, $cfg) = @_;
 
-    delete $cfg->{ids}->{pve};
-    delete $cfg->{ids}->{pam};
-
     foreach my $realm (keys %{$cfg->{ids}}) {
        my $data = $cfg->{ids}->{$realm};
        if ($data->{comment}) {