summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/vpn/helpers/__init__.py
blob: 96ec4f2ef04e0a01abb5d2c9376b3fe86f76237a (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
168
169
170
171
172
173
174
175
176
import os.path
import sys

from os import remove, chmod, access, R_OK
from shutil import copyfile
from hashlib import sha512

from twisted.logger import Logger

from leap.bitmask.vpn import _config

from leap.bitmask.system import IS_LINUX, IS_MAC, IS_SNAP
from leap.bitmask.util import STANDALONE

log = Logger()

if IS_LINUX:

    from leap.bitmask.vpn.constants import BITMASK_ROOT_SYSTEM
    from leap.bitmask.vpn.constants import BITMASK_ROOT_LOCAL
    from leap.bitmask.vpn.constants import BITMASK_ROOT_SNAP
    from leap.bitmask.vpn.constants import OPENVPN_SYSTEM, OPENVPN_LOCAL
    from leap.bitmask.vpn.constants import OPENVPN_SNAP
    from leap.bitmask.vpn.constants import POLKIT_SYSTEM, POLKIT_LOCAL, POLKIT_SNAP
    from leap.bitmask.vpn.privilege import is_pkexec_in_system
    from leap.bitmask.vpn.privilege import LinuxPolicyChecker

    def install():
        print('installing bitmask helpers...')
        helper_from = _config.get_bitmask_helper_path()
        polkit_from = _config.get_bitmask_polkit_policy_path()
        openvpn_from = _config.get_bitmask_openvpn_path()

        sbin = '/usr/local/sbin'
        if not os.path.isdir(sbin):
            os.makedirs(sbin)

        copyfile(helper_from, BITMASK_ROOT_LOCAL)
        chmod(BITMASK_ROOT_LOCAL, 0744)

        copyfile(polkit_from, POLKIT_LOCAL)

        if STANDALONE:
            copyfile(openvpn_from, OPENVPN_LOCAL)
            chmod(OPENVPN_LOCAL, 0744)

    def uninstall():
        remove(BITMASK_ROOT_LOCAL)
        remove(POLKIT_LOCAL)
        remove(OPENVPN_LOCAL)

    def privcheck(timeout=5):
        has_pkexec = is_pkexec_in_system()
        running = LinuxPolicyChecker.is_up()
        if not running:
            try:
                LinuxPolicyChecker.get_usable_pkexec(timeout=timeout)
                running = LinuxPolicyChecker.is_up()
            except Exception:
                running = False
        result = has_pkexec and running
        log.debug('Privilege check: %s' % result)
        return result

    def check():
        pkexec = is_pkexec_in_system()
        helper = _check_helper()
        polkit = _check_polkit_file_exist()
        openvpn = _check_openvpn()
        if not pkexec:
            log.error('No pkexec in system!')
        if not helper:
            log.error('No bitmask-root in system!')
        if not polkit:
            log.error('No polkit file in system!')
        if not openvpn:
            log.error('No openvpn in system!')
        result = all([pkexec, helper, polkit, openvpn])
        if result is True:
            log.debug('All checks passed')
        return result

    def _check_helper():
        log.debug('Checking whether helper exists')
        helper_path = _config.get_bitmask_helper_path()
        if not _exists_and_can_read(helper_path):
            log.debug('Cannot read helpers')
            return True

        if IS_SNAP:
            if os.path.isfile(BITMASK_ROOT_SNAP):
                return True
            log.error('Cannot find bitmask-root in snap')
            return False

        helper_path_digest = digest(helper_path)
        if (_exists_and_can_read(BITMASK_ROOT_SYSTEM) and
                helper_path_digest == digest(BITMASK_ROOT_SYSTEM)):
            log.debug('Global bitmask-root: %s'
                      % os.path.isfile(BITMASK_ROOT_SYSTEM))
            return True
        if (_exists_and_can_read(BITMASK_ROOT_LOCAL) and
                helper_path_digest == digest(BITMASK_ROOT_LOCAL)):
            log.debug('Local bitmask-root: %s'
                      % os.path.isfile(BITMASK_ROOT_LOCAL))
            return True

        log.debug('No valid bitmask-root found')
        return False

    def _check_openvpn():
        if IS_SNAP:
            return os.path.exists(OPENVPN_SNAP)

        if os.path.exists(OPENVPN_SYSTEM):
            return True

        openvpn_path = _config.get_bitmask_openvpn_path()
        if openvpn_path is None:
            # If Bitmask does not provide any openvpn binary
            # (we are not in a bundle: either running from debian packages, git
            # or pip) reporting an error on check will trigger an attempt to
            # install helpers that can not be successful.
            # XXX: we need a better way to flag errors that can not be solved
            # by installing helpers
            return True

        openvpn_path_digest = digest(openvpn_path)
        if (_exists_and_can_read(OPENVPN_LOCAL) and
                openvpn_path_digest == digest(OPENVPN_LOCAL)):
            return True

        return False

    def _check_polkit_file_exist():
        """
        We are just checking if there is any policy file installed not
        if it's valid or if it's the correct one that will be used.

        If LOCAL: we use /usr/local/sbin/bitmask-root
        If SYSTEM: we use /usr/sbin/bitmask-root, and
        if SNAP:   we use /snap/bin/riseup-vpn.bitmask-root
        """
        return (os.path.exists(POLKIT_LOCAL) or
                os.path.exists(POLKIT_SYSTEM) or
                os.path.exists(POLKIT_SNAP))

    def _exists_and_can_read(file_path):
        return access(file_path, R_OK)


elif IS_MAC:

    def check():
        # XXX check if bitmask-helper is running
        return True

    def privcheck(timeout=5):
        return True


def digest(path):
    with open(path, 'r') as f:
        s = f.read()
    return sha512(s).digest()


def main():
    if sys.argv[-1] == 'install':
        install()
    if sys.argv[-1] == 'uninstall':
        uninstall()


if __name__ == "__main__":
    main()