summaryrefslogtreecommitdiffstats
path: root/lib/ansible/plugins/become/su.py
blob: ae2d39a5217bedd452021d600f28321bb91f1ea1 (plain)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# -*- 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: su
    short_description: Substitute User
    description:
        - This become plugin allows your remote/login user to execute commands as another user via the su utility.
    author: ansible (@core)
    version_added: "2.8"
    options:
        become_user:
            description: User you 'become' to execute the task
            default: root
            ini:
              - section: privilege_escalation
                key: become_user
              - section: su_become_plugin
                key: user
            vars:
              - name: ansible_become_user
              - name: ansible_su_user
            env:
              - name: ANSIBLE_BECOME_USER
              - name: ANSIBLE_SU_USER
            keyword:
              - name: become_user
        become_exe:
            description: Su executable
            default: su
            ini:
              - section: privilege_escalation
                key: become_exe
              - section: su_become_plugin
                key: executable
            vars:
              - name: ansible_become_exe
              - name: ansible_su_exe
            env:
              - name: ANSIBLE_BECOME_EXE
              - name: ANSIBLE_SU_EXE
            keyword:
              - name: become_exe
        become_flags:
            description: Options to pass to su
            default: ''
            ini:
              - section: privilege_escalation
                key: become_flags
              - section: su_become_plugin
                key: flags
            vars:
              - name: ansible_become_flags
              - name: ansible_su_flags
            env:
              - name: ANSIBLE_BECOME_FLAGS
              - name: ANSIBLE_SU_FLAGS
            keyword:
              - name: become_flags
        become_pass:
            description: Password to pass to su
            required: False
            vars:
              - name: ansible_become_password
              - name: ansible_become_pass
              - name: ansible_su_pass
            env:
              - name: ANSIBLE_BECOME_PASS
              - name: ANSIBLE_SU_PASS
            ini:
              - section: su_become_plugin
                key: password
        prompt_l10n:
            description:
                - List of localized strings to match for prompt detection
                - If empty we'll use the built in one
                - Do NOT add a colon (:) to your custom entries. Ansible adds a colon at the end of each prompt;
                  if you add another one in your string, your prompt will fail with a "Timeout" error.
            default: []
            type: list
            elements: string
            ini:
              - section: su_become_plugin
                key: localized_prompts
            vars:
              - name: ansible_su_prompt_l10n
            env:
              - name: ANSIBLE_SU_PROMPT_L10N
"""

import re
import shlex

from ansible.module_utils.common.text.converters import to_bytes
from ansible.plugins.become import BecomeBase


class BecomeModule(BecomeBase):

    name = 'su'

    # messages for detecting prompted password issues
    fail = ('Authentication failure',)

    SU_PROMPT_LOCALIZATIONS = [
        'Password',
        '암호',
        'パスワード',
        'Adgangskode',
        'Contraseña',
        'Contrasenya',
        'Hasło',
        'Heslo',
        'Jelszó',
        'Lösenord',
        'Mật khẩu',
        'Mot de passe',
        'Parola',
        'Parool',
        'Pasahitza',
        'Passord',
        'Passwort',
        'Salasana',
        'Sandi',
        'Senha',
        'Wachtwoord',
        'ססמה',
        'Лозинка',
        'Парола',
        'Пароль',
        'गुप्तशब्द',
        'शब्दकूट',
        'సంకేతపదము',
        'හස්පදය',
        '密码',
        '密碼',
        '口令',
    ]

    def check_password_prompt(self, b_output):
        ''' checks if the expected password prompt exists in b_output '''

        prompts = self.get_option('prompt_l10n') or self.SU_PROMPT_LOCALIZATIONS
        b_password_string = b"|".join((br'(\w+\'s )?' + to_bytes(p)) for p in prompts)
        # Colon or unicode fullwidth colon
        b_password_string = b_password_string + to_bytes(u' ?(:|:) ?')
        b_su_prompt_localizations_re = re.compile(b_password_string, flags=re.IGNORECASE)
        return bool(b_su_prompt_localizations_re.match(b_output))

    def build_become_command(self, cmd, shell):
        super(BecomeModule, self).build_become_command(cmd, shell)

        # Prompt handling for ``su`` is more complicated, this
        # is used to satisfy the connection plugin
        self.prompt = True

        if not cmd:
            return cmd

        exe = self.get_option('become_exe') or self.name
        flags = self.get_option('become_flags') or ''
        user = self.get_option('become_user') or ''
        success_cmd = self._build_success_command(cmd, shell)

        return "%s %s %s -c %s" % (exe, flags, user, shlex.quote(success_cmd))