]>
Commit | Line | Data |
---|---|---|
1360e6f0 DM |
1 | package PMG::AccessControl; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use Authen::PAM; | |
9d7f54a3 | 6 | use PVE::Tools; |
1360e6f0 DM |
7 | |
8 | use PVE::JSONSchema qw(get_standard_option); | |
9 | ||
62ebb4bc | 10 | use PMG::UserConfig; |
1360e6f0 DM |
11 | |
12 | sub normalize_path { | |
13 | my $path = shift; | |
14 | ||
15 | $path =~ s|/+|/|g; | |
16 | ||
17 | $path =~ s|/$||; | |
18 | ||
19 | $path = '/' if !$path; | |
20 | ||
21 | $path = "/$path" if $path !~ m|^/|; | |
22 | ||
23 | return undef if $path !~ m|^[[:alnum:]\.\-\_\/]+$|; | |
24 | ||
25 | return $path; | |
26 | } | |
27 | ||
1360e6f0 DM |
28 | # password should be utf8 encoded |
29 | # Note: some plugins delay/sleep if auth fails | |
30 | sub authenticate_user { | |
31 | my ($username, $password, $otp) = @_; | |
32 | ||
33 | die "no username specified\n" if !$username; | |
34 | ||
35 | my ($ruid, $realm); | |
36 | ||
62ebb4bc | 37 | ($username, $ruid, $realm) = PMG::Utils::verify_username($username); |
1360e6f0 DM |
38 | |
39 | if ($realm eq 'pam') { | |
62ebb4bc DM |
40 | die "invalid pam user (only root allowed)\n" if $ruid ne 'root'; |
41 | authenticate_pam_user($ruid, $password); | |
1360e6f0 DM |
42 | return $username; |
43 | } | |
44 | ||
62ebb4bc DM |
45 | if ($realm eq 'pmg') { |
46 | my $usercfg = PMG::UserConfig->new(); | |
47 | $usercfg->authenticate_user($ruid, $password); | |
48 | return $username; | |
49 | } | |
50 | ||
1360e6f0 DM |
51 | die "no such realm '$realm'\n"; |
52 | } | |
53 | ||
54 | sub domain_set_password { | |
62ebb4bc | 55 | my ($realm, $ruid, $password) = @_; |
1360e6f0 DM |
56 | |
57 | die "no auth domain specified" if !$realm; | |
58 | ||
62ebb4bc DM |
59 | if ($realm eq 'pam') { |
60 | die "invalid pam user (only root allowed)\n" if $ruid ne 'root'; | |
1360e6f0 | 61 | |
62ebb4bc | 62 | my $cmd = ['usermod']; |
1360e6f0 | 63 | |
62ebb4bc | 64 | my $epw = PMG::Utils::encrypt_pw($password); |
1360e6f0 | 65 | |
62ebb4bc | 66 | push @$cmd, '-p', $epw, $ruid; |
1360e6f0 | 67 | |
62ebb4bc | 68 | run_command($cmd, errmsg => "change password for '$ruid' failed"); |
1360e6f0 | 69 | |
62ebb4bc DM |
70 | } elsif ($realm eq 'pmg') { |
71 | PMG::UserConfig->set_password($ruid, $password); | |
72 | } else { | |
73 | die "no such realm '$realm'\n"; | |
74 | } | |
1360e6f0 DM |
75 | } |
76 | ||
62ebb4bc | 77 | # test if user exists and is enabled |
1360e6f0 | 78 | sub check_user_enabled { |
62ebb4bc | 79 | my ($username, $noerr) = @_; |
1360e6f0 | 80 | |
62ebb4bc | 81 | my ($userid, $ruid, $realm) = PMG::Utils::verify_username($username, 1); |
1360e6f0 | 82 | |
62ebb4bc DM |
83 | if ($realm && $ruid) { |
84 | if ($realm eq 'pam') { | |
85 | return 1 if $ruid eq 'root'; | |
86 | } elsif ($realm eq 'pmg') { | |
87 | my $usercfg = PMG::UserConfig->new(); | |
88 | my $data = $usercfg->check_user_exist($ruid, $noerr); | |
89 | return 1 if $data && $data->{enable}; | |
90 | } | |
91 | } | |
1360e6f0 DM |
92 | |
93 | die "user '$username' is disabled\n" if !$noerr; | |
94 | ||
95 | return undef; | |
96 | } | |
97 | ||
62ebb4bc | 98 | sub authenticate_pam_user { |
1360e6f0 DM |
99 | my ($username, $password) = @_; |
100 | ||
62ebb4bc | 101 | # user need to be able to read /etc/passwd /etc/shadow |
1360e6f0 DM |
102 | |
103 | my $pamh = Authen::PAM->new('common-auth', $username, sub { | |
104 | my @res; | |
105 | while(@_) { | |
106 | my $msg_type = shift; | |
107 | my $msg = shift; | |
108 | push @res, (0, $password); | |
109 | } | |
110 | push @res, 0; | |
111 | return @res; | |
112 | }); | |
113 | ||
114 | if (!ref($pamh)) { | |
115 | my $err = $pamh->pam_strerror($pamh); | |
116 | die "Error during PAM init: $err"; | |
117 | } | |
118 | ||
119 | my $res; | |
120 | ||
121 | if (($res = $pamh->pam_authenticate(0)) != PAM_SUCCESS) { | |
122 | my $err = $pamh->pam_strerror($res); | |
123 | die "auth failed: $err"; | |
124 | } | |
125 | ||
9d7f54a3 | 126 | if (($res = $pamh->pam_acct_mgmt(0)) != PAM_SUCCESS) { |
1360e6f0 DM |
127 | my $err = $pamh->pam_strerror($res); |
128 | die "auth failed: $err"; | |
129 | } | |
130 | ||
131 | $pamh = 0; # call destructor | |
132 | ||
133 | return 1; | |
134 | } | |
135 | ||
1360e6f0 | 136 | 1; |