File: runas.py

package info (click to toggle)
ansible-core 2.19.0~beta6-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 32,628 kB
  • sloc: python: 180,313; cs: 4,929; sh: 4,601; xml: 34; makefile: 21
file content (145 lines) | stat: -rw-r--r-- 5,325 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import annotations

DOCUMENTATION = """
    name: runas
    short_description: Run As user
    description:
        - This become plugin allows your remote/login user to execute commands as another user via the windows runas facility.
    author: ansible (@core)
    version_added: "2.8"
    options:
        become_user:
            description: User you 'become' to execute the task
            ini:
              - section: privilege_escalation
                key: become_user
              - section: runas_become_plugin
                key: user
            vars:
              - name: ansible_become_user
              - name: ansible_runas_user
            env:
              - name: ANSIBLE_BECOME_USER
              - name: ANSIBLE_RUNAS_USER
            keyword:
              - name: become_user
            required: True
        become_flags:
            description: Options to pass to runas, a space delimited list of k=v pairs
            default: ''
            ini:
              - section: privilege_escalation
                key: become_flags
              - section: runas_become_plugin
                key: flags
            vars:
              - name: ansible_become_flags
              - name: ansible_runas_flags
            env:
              - name: ANSIBLE_BECOME_FLAGS
              - name: ANSIBLE_RUNAS_FLAGS
            keyword:
              - name: become_flags
        become_pass:
            description: password
            ini:
              - section: runas_become_plugin
                key: password
            vars:
              - name: ansible_become_password
              - name: ansible_become_pass
              - name: ansible_runas_pass
            env:
              - name: ANSIBLE_BECOME_PASS
              - name: ANSIBLE_RUNAS_PASS
    notes:
        - runas is really implemented in the powershell module handler and as such can only be used with winrm connections.
        - This plugin ignores the 'become_exe' setting as it uses an API and not an executable.
        - The Secondary Logon service (seclogon) must be running to use runas
"""

from ansible.errors import AnsibleError
from ansible.parsing.splitter import split_args
from ansible.plugins.become import BecomeBase


class BecomeModule(BecomeBase):

    name = 'runas'

    def build_become_command(self, cmd, shell):
        # this is a noop, the 'real' runas is implemented
        # inside the windows powershell execution subsystem
        return cmd

    def _build_powershell_wrapper_action(self) -> tuple[str, dict[str, object], dict[str, object]]:
        # See ansible.executor.powershell.become_wrapper.ps1 for the
        # parameter names
        params = {
            'BecomeUser': self.get_option('become_user'),
        }
        secure_params = {}

        password = self.get_option('become_pass')
        if password:
            secure_params['BecomePassword'] = password

        flags = self.get_option('become_flags')
        if flags:
            split_flags = split_args(flags)
            for flag in split_flags:
                if '=' not in flag:
                    raise ValueError(f"become_flags entry '{flag}' is in an invalid format, must be a key=value pair")

                k, v = flag.split('=', 1)

                param_name, param_value = self._parse_flag(k, v)
                params[param_name] = param_value

        return 'become_wrapper.ps1', params, secure_params

    def _parse_flag(self, name: str, value: str) -> tuple[str, str]:
        logon_types = {
            'interactive': 'Interactive',
            'network': 'Network',
            'batch': 'Batch',
            'service': 'Service',
            'unlock': 'Unlock',
            'network_cleartext': 'NetworkCleartext',
            'new_credentials': 'NewCredentials',
        }
        logon_flags = {
            'none': 'None',
            'with_profile': 'WithProfile',
            'netcredentials_only': 'NetCredentialsOnly',
        }

        match name.lower():
            case 'logon_type':
                param_name = 'LogonType'
                if param_value := logon_types.get(value.lower(), None):
                    return param_name, param_value
                else:
                    raise AnsibleError(f"become_flags logon_type value '{value}' is not valid, valid values are: {', '.join(logon_types.keys())}")

            case 'logon_flags':
                param_name = 'LogonFlags'
                flags = value.split(',')

                param_values: list[str] = []
                for flag in flags:
                    if not flag:
                        continue

                    if flag_value := logon_flags.get(flag.lower(), None):
                        param_values.append(flag_value)
                    else:
                        raise AnsibleError(f"become_flags logon_flags value '{flag}' is not valid, valid values are: {', '.join(logon_flags.keys())}")

                return param_name, ", ".join(param_values)

            case _:
                raise AnsibleError(f"become_flags key '{name}' is not a valid runas flag, must be 'logon_type' or 'logon_flags'")