]> git.proxmox.com Git - pmg-api.git/blob - PMG/AccessControl.pm
PMG/API2/AccessControl.pm: create_ticket() - return role
[pmg-api.git] / PMG / AccessControl.pm
1 package PMG::AccessControl;
2
3 use strict;
4 use warnings;
5 use Authen::PAM;
6
7 use PVE::Tools;
8 use PVE::JSONSchema qw(get_standard_option);
9
10 use PMG::UserConfig;
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
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
37 ($username, $ruid, $realm) = PMG::Utils::verify_username($username);
38
39 if ($realm eq 'pam') {
40 die "invalid pam user (only root allowed)\n" if $ruid ne 'root';
41 authenticate_pam_user($ruid, $password);
42 return $username;
43 }
44
45 if ($realm eq 'pmg') {
46 my $usercfg = PMG::UserConfig->new();
47 $usercfg->authenticate_user($username, $password);
48 return $username;
49 }
50
51 die "no such realm '$realm'\n";
52 }
53
54 sub set_user_password {
55 my ($username, $password) = @_;
56
57 my ($ruid, $realm);
58
59 ($username, $ruid, $realm) = PMG::Utils::verify_username($username);
60
61 if ($realm eq 'pam') {
62 die "invalid pam user (only root allowed)\n" if $ruid ne 'root';
63
64 my $cmd = ['usermod'];
65
66 my $epw = PVE::Tools::encrypt_pw($password);
67
68 push @$cmd, '-p', $epw, $ruid;
69
70 run_command($cmd, errmsg => "change password for '$ruid' failed");
71
72 } elsif ($realm eq 'pmg') {
73 PMG::UserConfig->set_user_password($username, $password);
74 } else {
75 die "no such realm '$realm'\n";
76 }
77 }
78
79 # test if user exists and is enabled
80 # returns: role
81 sub check_user_enabled {
82 my ($username, $noerr) = @_;
83
84 my ($ruid, $realm);
85
86 ($username, $ruid, $realm) = PMG::Utils::verify_username($username, 1);
87
88 if ($realm && $ruid) {
89 if ($realm eq 'pam') {
90 return 'root' if $ruid eq 'root';
91 } elsif ($realm eq 'pmg') {
92 my $usercfg = PMG::UserConfig->new();
93 my $data = $usercfg->lookup_user_data($username, $noerr);
94 return $data->{role} if $data && $data->{enable};
95 }
96 }
97
98 die "user '$username' is disabled\n" if !$noerr;
99
100 return undef;
101 }
102
103 sub authenticate_pam_user {
104 my ($username, $password) = @_;
105
106 # user need to be able to read /etc/passwd /etc/shadow
107
108 my $pamh = Authen::PAM->new('common-auth', $username, sub {
109 my @res;
110 while(@_) {
111 my $msg_type = shift;
112 my $msg = shift;
113 push @res, (0, $password);
114 }
115 push @res, 0;
116 return @res;
117 });
118
119 if (!ref($pamh)) {
120 my $err = $pamh->pam_strerror($pamh);
121 die "Error during PAM init: $err";
122 }
123
124 my $res;
125
126 if (($res = $pamh->pam_authenticate(0)) != PAM_SUCCESS) {
127 my $err = $pamh->pam_strerror($res);
128 die "auth failed: $err";
129 }
130
131 if (($res = $pamh->pam_acct_mgmt(0)) != PAM_SUCCESS) {
132 my $err = $pamh->pam_strerror($res);
133 die "auth failed: $err";
134 }
135
136 $pamh = 0; # call destructor
137
138 return 1;
139 }
140
141 1;