]> git.proxmox.com Git - pmg-api.git/blame - PMG/AccessControl.pm
PMG/API2/Services.pm: return Result for oneshot services in dead state
[pmg-api.git] / PMG / AccessControl.pm
CommitLineData
1360e6f0
DM
1package PMG::AccessControl;
2
3use strict;
4use warnings;
5use Authen::PAM;
9d7f54a3 6use PVE::Tools;
1360e6f0
DM
7
8use PVE::JSONSchema qw(get_standard_option);
9
10my $realm_regex = qr/[A-Za-z][A-Za-z0-9\.\-_]+/;
11
12PVE::JSONSchema::register_format('pmg-realm', \&verify_realm);
13sub verify_realm {
14 my ($realm, $noerr) = @_;
15
16 if ($realm !~ m/^${realm_regex}$/) {
17 return undef if $noerr;
18 die "value does not look like a valid realm\n";
19 }
20 return $realm;
21}
22
23PVE::JSONSchema::register_standard_option('realm', {
24 description => "Authentication domain ID",
25 type => 'string', format => 'pmg-realm',
26 maxLength => 32,
27});
28
29PVE::JSONSchema::register_format('pmg-userid', \&verify_username);
30sub verify_username {
31 my ($username, $noerr) = @_;
32
33 $username = '' if !$username;
34 my $len = length($username);
35 if ($len < 3) {
36 die "user name '$username' is too short\n" if !$noerr;
37 return undef;
38 }
39 if ($len > 64) {
40 die "user name '$username' is too long ($len > 64)\n" if !$noerr;
41 return undef;
42 }
43
44 # we only allow a limited set of characters
45 # colon is not allowed, because we store usernames in
46 # colon separated lists)!
47 # slash is not allowed because it is used as pve API delimiter
48 # also see "man useradd"
49 if ($username =~ m!^([^\s:/]+)\@(${realm_regex})$!) {
50 return wantarray ? ($username, $1, $2) : $username;
51 }
52
53 die "value '$username' does not look like a valid user name\n" if !$noerr;
54
55 return undef;
56}
57
58PVE::JSONSchema::register_standard_option('userid', {
59 description => "User ID",
60 type => 'string', format => 'pmg-userid',
61 maxLength => 64,
62});
63
64sub normalize_path {
65 my $path = shift;
66
67 $path =~ s|/+|/|g;
68
69 $path =~ s|/$||;
70
71 $path = '/' if !$path;
72
73 $path = "/$path" if $path !~ m|^/|;
74
75 return undef if $path !~ m|^[[:alnum:]\.\-\_\/]+$|;
76
77 return $path;
78}
79
1360e6f0
DM
80# password should be utf8 encoded
81# Note: some plugins delay/sleep if auth fails
82sub authenticate_user {
83 my ($username, $password, $otp) = @_;
84
85 die "no username specified\n" if !$username;
86
87 my ($ruid, $realm);
88
89 ($username, $ruid, $realm) = verify_username($username);
90
91 if ($realm eq 'pam') {
92 is_valid_user_utf8($ruid, $password);
93 return $username;
94 }
95
96 die "no such realm '$realm'\n";
97}
98
99sub domain_set_password {
100 my ($realm, $username, $password) = @_;
101
102 die "no auth domain specified" if !$realm;
103
104 die "not implemented";
105}
106
107sub check_user_exist {
108 my ($usercfg, $username, $noerr) = @_;
109
110 $username = verify_username($username, $noerr);
111 return undef if !$username;
112
113 return $usercfg->{users}->{$username} if $usercfg && $usercfg->{users}->{$username};
114
115 die "no such user ('$username')\n" if !$noerr;
116
117 return undef;
118}
119
120sub check_user_enabled {
121 my ($usercfg, $username, $noerr) = @_;
122
123 my $data = check_user_exist($usercfg, $username, $noerr);
124 return undef if !$data;
125
126 return 1 if $data->{enable};
127
128 die "user '$username' is disabled\n" if !$noerr;
129
130 return undef;
131}
132
133sub is_valid_user_utf8 {
134 my ($username, $password) = @_;
135
136 # user (www-data) need to be able to read /etc/passwd /etc/shadow
137
138 my $pamh = Authen::PAM->new('common-auth', $username, sub {
139 my @res;
140 while(@_) {
141 my $msg_type = shift;
142 my $msg = shift;
143 push @res, (0, $password);
144 }
145 push @res, 0;
146 return @res;
147 });
148
149 if (!ref($pamh)) {
150 my $err = $pamh->pam_strerror($pamh);
151 die "Error during PAM init: $err";
152 }
153
154 my $res;
155
156 if (($res = $pamh->pam_authenticate(0)) != PAM_SUCCESS) {
157 my $err = $pamh->pam_strerror($res);
158 die "auth failed: $err";
159 }
160
9d7f54a3 161 if (($res = $pamh->pam_acct_mgmt(0)) != PAM_SUCCESS) {
1360e6f0
DM
162 my $err = $pamh->pam_strerror($res);
163 die "auth failed: $err";
164 }
165
166 $pamh = 0; # call destructor
167
168 return 1;
169}
170
171sub is_valid_user {
172 my ($username, $password) = @_;
173
9d7f54a3 174 return is_valid_user_utf8($username, encode("utf8", $password));
1360e6f0
DM
175}
176
1771;