+
+my $verify_auth = sub {
+ my ($rpcenv, $username, $pw_or_ticket, $otp, $path, $privs) = @_;
+
+ my $normpath = PVE::AccessControl::normalize_path($path);
+
+ my $ticketuser;
+ if (($ticketuser = PVE::AccessControl::verify_ticket($pw_or_ticket, 1)) &&
+ ($ticketuser eq $username)) {
+ # valid ticket
+ } elsif (PVE::AccessControl::verify_vnc_ticket($pw_or_ticket, $username, $normpath, 1)) {
+ # valid vnc ticket
+ } else {
+ $username = PVE::AccessControl::authenticate_user($username, $pw_or_ticket, $otp);
+ }
+
+ my $privlist = [ PVE::Tools::split_list($privs) ];
+ if (!($normpath && scalar(@$privlist) && $rpcenv->check($username, $normpath, $privlist))) {
+ die "no permission ($path, $privs)\n";
+ }
+
+ return { username => $username };
+};
+
+my $create_ticket = sub {
+ my ($rpcenv, $username, $pw_or_ticket, $otp) = @_;
+
+ my $ticketuser;
+ if (($ticketuser = PVE::AccessControl::verify_ticket($pw_or_ticket, 1)) &&
+ ($ticketuser eq 'root@pam' || $ticketuser eq $username)) {
+ # valid ticket. Note: root@pam can create tickets for other users
+ } else {
+ $username = PVE::AccessControl::authenticate_user($username, $pw_or_ticket, $otp);
+ }
+
+ my $ticket = PVE::AccessControl::assemble_ticket($username);
+ my $csrftoken = PVE::AccessControl::assemble_csrf_prevention_token($username);
+
+ return {
+ ticket => $ticket,
+ username => $username,
+ CSRFPreventionToken => $csrftoken,
+ };
+};
+
+my $compute_api_permission = sub {
+ my ($rpcenv, $authuser) = @_;
+
+ my $usercfg = $rpcenv->{user_cfg};
+
+ my $res = {};
+ my $priv_re_map = {
+ vms => qr/VM\.|Permissions\.Modify/,
+ access => qr/(User|Group)\.|Permissions\.Modify/,
+ storage => qr/Datastore\./,
+ nodes => qr/Sys\.|Permissions\.Modify/,
+ dc => qr/Sys\.Audit/,
+ };
+ map { $res->{$_} = {} } keys %$priv_re_map;
+
+ my $required_paths = ['/', '/nodes', '/access/groups', '/vms', '/storage'];
+
+ my $checked_paths = {};
+ foreach my $path (@$required_paths, keys %{$usercfg->{acl}}) {
+ next if $checked_paths->{$path};
+ $checked_paths->{$path} = 1;
+
+ my $path_perm = $rpcenv->permissions($authuser, $path);
+
+ my $toplevel = ($path =~ /^\/(\w+)/) ? $1 : 'dc';
+ if ($toplevel eq 'pool') {
+ foreach my $priv (keys %$path_perm) {
+ if ($priv =~ m/^VM\./) {
+ $res->{vms}->{$priv} = 1;
+ } elsif ($priv =~ m/^Datastore\./) {
+ $res->{storage}->{$priv} = 1;
+ } elsif ($priv eq 'Permissions.Modify') {
+ $res->{storage}->{$priv} = 1;
+ $res->{vms}->{$priv} = 1;
+ }
+ }
+ } else {
+ my $priv_regex = $priv_re_map->{$toplevel} // next;
+ foreach my $priv (keys %$path_perm) {
+ next if $priv !~ m/^($priv_regex)/;
+ $res->{$toplevel}->{$priv} = 1;
+ }
+ }
+ }
+
+ return $res;
+};
+
+__PACKAGE__->register_method ({
+ name => 'get_ticket',
+ path => 'ticket',
+ method => 'GET',
+ permissions => { user => 'world' },
+ description => "Dummy. Useful for formaters which want to provide a login page.",
+ parameters => {
+ additionalProperties => 0,
+ },
+ returns => { type => "null" },
+ code => sub { return undef; }});
+