1 package PMG
::API2
::AccessControl
;
6 use PVE
::Exception
qw(raise raise_perm_exc);
8 use PVE
::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) = @_;
65 if (($ticketuser = PMG
::Ticket
::verify_ticket
($pw_or_ticket, 1)) &&
66 ($ticketuser eq 'root@pam' || $ticketuser eq $username)) {
67 # valid ticket. Note: root@pam can create tickets for other users
69 $username = PMG
::AccessControl
::authenticate_user
($username, $pw_or_ticket, $otp);
72 my $ticket = PMG
::Ticket
::assemble_ticket
($username);
73 my $csrftoken = PMG
::Ticket
::assemble_csrf_prevention_token
($username);
77 username
=> $username,
78 CSRFPreventionToken
=> $csrftoken,
83 __PACKAGE__-
>register_method ({
87 permissions
=> { user
=> 'world' },
88 description
=> "Dummy. Useful for formaters which want to priovde a login page.",
90 additionalProperties
=> 0,
92 returns
=> { type
=> "null" },
93 code
=> sub { return undef; }});
95 __PACKAGE__-
>register_method ({
96 name
=> 'create_ticket',
100 description
=> "You need to pass valid credientials.",
103 protected
=> 1, # else we can't access shadow files
104 description
=> "Create or verify authentication ticket.",
106 additionalProperties
=> 0,
109 description
=> "User name",
113 realm
=> get_standard_option
('realm', {
114 description
=> "You can optionally pass the realm using this parameter. Normally the realm is simply added to the username <username>\@<relam>.",
118 description
=> "The secret password. This can also be a valid ticket.",
122 description
=> "One-time password for Two-factor authentication.",
131 username
=> { type
=> 'string' },
132 ticket
=> { type
=> 'string', optional
=> 1},
133 CSRFPreventionToken
=> { type
=> 'string', optional
=> 1 },
139 my $username = $param->{username
};
140 $username .= "\@$param->{realm}" if $param->{realm
};
142 my $rpcenv = PVE
::RESTEnvironment
::get
();
146 PMG
::AccessControl
::check_user_enabled
($username);
147 $res = &$create_ticket($rpcenv, $username, $param->{password
}, $param->{otp
});
150 my $clientip = $rpcenv->get_client_ip() || '';
151 syslog
('err', "authentication failure; rhost=$clientip user=$username msg=$err");
152 # do not return any info to prevent user enumeration attacks
153 die PVE
::Exception-
>new("authentication failure\n", code
=> 401);
156 syslog
('info', "successful auth for user '$username'");
161 __PACKAGE__-
>register_method ({
162 name
=> 'change_passsword',
165 protected
=> 1, # else we can't access shadow files
166 description
=> "Change user password.",
168 additionalProperties
=> 0,
170 userid
=> get_standard_option
('userid'),
172 description
=> "The new password.",
179 returns
=> { type
=> "null" },
183 my $rpcenv = PVE
::RESTEnvironment
::get
();
184 my $authuser = $rpcenv->get_user();
186 my ($userid, $ruid, $realm) = PMG
::Utils
::verify_username
($param->{userid
});
188 if ($authuser eq 'root@pam') {
189 # OK - root can change anything
191 if ($authuser eq $userid) {
192 # OK - each enable user can change its own password
193 PMG
::AccessControl
::check_user_enabled
($userid);
199 PMG
::AccessControl
::set_user_password
($userid, $param->{password
});
201 syslog
('info', "changed password for user '$userid'");