1 package PMG
::API2
::AccessControl
;
6 use PVE
::Exception
qw(raise raise_perm_exc);
8 use PMG
::RESTEnvironment
;
10 use PVE
::JSONSchema
qw(get_standard_option);
14 use PMG
::AccessControl
;
19 use base
qw(PVE::RESTHandler);
21 __PACKAGE__-
>register_method ({
22 subclass
=> "PMG::API2::Users",
26 __PACKAGE__-
>register_method ({
30 description
=> "Directory index.",
35 additionalProperties
=> 0,
43 subdir
=> { type
=> 'string' },
46 links
=> [ { rel
=> 'child', href
=> "{subdir}" } ],
52 { subdir
=> 'ticket' },
53 { subdir
=> 'password' },
54 { subdir
=> 'users' },
61 my $create_ticket = sub {
62 my ($rpcenv, $username, $pw_or_ticket, $otp) = @_;
66 if ($pw_or_ticket =~ m/^PMGQUAR:/) {
67 PMG
::Ticket
::verify_quarantine_ticket
($pw_or_ticket);
69 my $csrftoken = PMG
::Ticket
::assemble_csrf_prevention_token
($username);
73 ticket
=> $pw_or_ticket,
74 username
=> $username,
75 CSRFPreventionToken
=> $csrftoken,
79 my $role = PMG
::AccessControl
::check_user_enabled
($rpcenv->{usercfg
}, $username);
81 if (($ticketuser = PMG
::Ticket
::verify_ticket
($pw_or_ticket, 1)) &&
82 ($ticketuser eq 'root@pam' || $ticketuser eq $username)) {
83 # valid ticket. Note: root@pam can create tickets for other users
85 $username = PMG
::AccessControl
::authenticate_user
($username, $pw_or_ticket, $otp);
88 my $ticket = PMG
::Ticket
::assemble_ticket
($username);
89 my $csrftoken = PMG
::Ticket
::assemble_csrf_prevention_token
($username);
94 username
=> $username,
95 CSRFPreventionToken
=> $csrftoken,
100 __PACKAGE__-
>register_method ({
101 name
=> 'get_ticket',
104 permissions
=> { user
=> 'world' },
105 description
=> "Dummy. Useful for formaters which want to priovde a login page.",
107 additionalProperties
=> 0,
109 returns
=> { type
=> "null" },
110 code
=> sub { return undef; }});
112 __PACKAGE__-
>register_method ({
113 name
=> 'create_ticket',
117 description
=> "You need to pass valid credientials.",
120 protected
=> 1, # else we can't access shadow files
121 description
=> "Create or verify authentication ticket.",
123 additionalProperties
=> 0,
126 description
=> "User name",
130 realm
=> get_standard_option
('realm', {
131 description
=> "You can optionally pass the realm using this parameter. Normally the realm is simply added to the username <username>\@<relam>.",
135 description
=> "The secret password. This can also be a valid ticket.",
139 description
=> "One-time password for Two-factor authentication.",
148 username
=> { type
=> 'string' },
149 ticket
=> { type
=> 'string', optional
=> 1},
150 CSRFPreventionToken
=> { type
=> 'string', optional
=> 1 },
151 role => { type
=> 'string', optional
=> 1},
157 my $username = $param->{username
};
159 if ($param->{realm
}) {
160 $username .= "\@$param->{realm}";
161 } elsif ($username !~ m/\@(pam|pve)$/) {
162 $username .= "\@quarantine";
165 my $rpcenv = PMG
::RESTEnvironment-
>get();
169 $res = &$create_ticket($rpcenv, $username, $param->{password
}, $param->{otp
});
172 my $clientip = $rpcenv->get_client_ip() || '';
173 syslog
('err', "authentication failure; rhost=$clientip user=$username msg=$err");
174 # do not return any info to prevent user enumeration attacks
175 die PVE
::Exception-
>new("authentication failure\n", code
=> 401);
178 syslog
('info', "successful auth for user '$username'");
183 __PACKAGE__-
>register_method ({
184 name
=> 'change_passsword',
187 protected
=> 1, # else we can't access shadow files
189 description
=> "Each user is allowed to change his own password. Only root can change the password of another user.",
192 description
=> "Change user password.",
194 additionalProperties
=> 0,
196 userid
=> get_standard_option
('userid'),
198 description
=> "The new password.",
205 returns
=> { type
=> "null" },
209 my $rpcenv = PMG
::RESTEnvironment-
>get();
210 my $authuser = $rpcenv->get_user();
212 my ($userid, $ruid, $realm) = PMG
::Utils
::verify_username
($param->{userid
});
214 if ($authuser eq 'root@pam') {
215 # OK - root can change anything
217 if ($realm eq 'pmg' && $authuser eq $userid) {
218 # OK - each enable user can change its own password
219 PMG
::AccessControl
::check_user_enabled
($rpcenv->{usercfg
}, $userid);
225 PMG
::AccessControl
::set_user_password
($userid, $param->{password
});
227 syslog
('info', "changed password for user '$userid'");