Exemple #1
0
    def __init__(self,
                 username=None,
                 password=None,
                 hostname=None,
                 service=None,
                 channel_bindings=None,
                 context_req=ContextReq.default,
                 usage='initiate',
                 protocol='negotiate',
                 options=0):

        if not HAS_SSPI:
            reraise(
                ImportError(
                    "SSPIProxy requires the SSPI Cython extension to be compiled"
                ), SSPI_IMP_ERR)

        super(SSPIProxy, self).__init__(username, password, hostname, service,
                                        channel_bindings, context_req, usage,
                                        protocol, options, False)

        self._attr_sizes = None
        self._complete = False
        self._credential = None
        self._context = SSPISecContext()
        self.__seq_num = 0

        credential_kwargs = {
            'package': to_text(protocol),
        }

        if usage == 'initiate':
            # TODO: It seems like the SPN is just an empty string for anon auth.
            credential_kwargs['principal'] = None
            credential_kwargs['credential_use'] = CredentialUse.outbound

            if self.username:
                domain, username = split_username(self.username)
                credential_kwargs['auth_data'] = WinNTAuthIdentity(
                    to_text(username, nonstring='passthru'),
                    to_text(domain, nonstring='passthru'),
                    to_text(password, nonstring='passthru'))

        else:
            credential_kwargs['principal'] = self.spn
            credential_kwargs['credential_use'] = CredentialUse.inbound

        try:
            self._credential = acquire_credentials_handle(**credential_kwargs)
        except NativeError as win_err:
            reraise(
                SpnegoError(base_error=win_err,
                            context_msg="Getting SSPI credential"))
Exemple #2
0
    def store_lines(text):
        for line in text.splitlines():
            line_split = line.split(':')

            if len(line_split) == 3:
                yield line_split[0], line_split[1], line_split[2], None, None

            elif len(line_split) == 6:
                domain_entry, user_entry = split_username(line_split[0])
                lm_entry = base64.b16decode(line_split[2].upper())
                nt_entry = base64.b16decode(line_split[3].upper())

                yield domain_entry or u"", user_entry, None, lm_entry, nt_entry
Exemple #3
0
def test_split_username(value, expected_domain, expected_user):
    actual_domain, actual_user = context.split_username(value)

    assert actual_domain == expected_domain
    assert actual_user == expected_user
Exemple #4
0
    def __init__(self,
                 username,
                 password,
                 hostname=None,
                 service=None,
                 channel_bindings=None,
                 context_req=ContextReq.default,
                 usage='initiate',
                 protocol='ntlm',
                 options=0,
                 _is_wrapped=False):
        super(NTLMProxy, self).__init__(username, password, hostname, service,
                                        channel_bindings, context_req, usage,
                                        protocol, options, _is_wrapped)

        self._complete = False  # type: bool
        self._credential = None  # type: Optional[_NTLMCredential]

        # Set the default flags, these might change depending on the LM_COMPAT_LEVEL set.
        self._context_req = self._context_req | \
            NegotiateFlags.key_128 | \
            NegotiateFlags.key_56 | \
            NegotiateFlags.key_exch | \
            NegotiateFlags.extended_session_security | \
            NegotiateFlags.always_sign | \
            NegotiateFlags.ntlm | \
            NegotiateFlags.lm_key | \
            NegotiateFlags.request_target | \
            NegotiateFlags.oem | \
            NegotiateFlags.unicode

        # gss-ntlmssp uses the env var 'LM_COMPAT_LEVEL' to control the NTLM compatibility level. To try and make our
        # NTLM implementation similar in functionality we will also use that behaviour.
        # https://github.com/gssapi/gss-ntlmssp/blob/e498737a96e8832a2cb9141ab1fe51e129185a48/src/gss_ntlmssp.c#L159-L170
        # See the below policy link for more details on what these mean, for now 3 is the sane behaviour.
        # https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-security-lan-manager-authentication-level
        lm_compat_level = int(os.environ.get('LM_COMPAT_LEVEL',
                                             3))  # type: int
        if lm_compat_level < 0 or lm_compat_level > 5:
            raise SpnegoError(
                ErrorCode.failure,
                context_msg=
                "Invalid LM_COMPAT_LEVEL %d, must be between 0 and 5" %
                lm_compat_level)

        if lm_compat_level == 0:
            self._context_req &= ~NegotiateFlags.extended_session_security

        if self.usage == 'initiate':
            domain, user = split_username(self.username)
            self._credential = _NTLMCredential(domain=domain,
                                               username=user,
                                               password=self.password)

            self._lm = lm_compat_level < 2  # type: bool
            self._nt_v1 = lm_compat_level < 3  # type: bool
            self._nt_v2 = lm_compat_level > 2  # type: bool

            if lm_compat_level > 1:
                self._context_req &= ~NegotiateFlags.lm_key

        else:
            self._lm = lm_compat_level < 4  # type: bool
            self._nt_v1 = lm_compat_level < 5  # type: bool
            self._nt_v2 = True  # type: bool

            # Make sure that the credential file is set and exists
            if not _get_credential_file():
                raise OperationNotAvailableError(
                    context_msg=
                    "Retrieving NTLM store without NTLM_USER_FILE set to a "
                    "filepath")

        self._temp_msg = {
            'negotiate': None,
            'challenge': None,
        }  # type: Dict[str, any]
        self._mic_required = False  # type: bool

        # Crypto state for signing and sealing.
        self._session_key = None  # type: Optional[bytes]
        self._sign_key_out = None  # type: Optional[bytes]
        self._sign_key_in = None  # type: Optional[bytes]
        self._handle_out = None  # type: Optional[RC4Handle]
        self._handle_in = None  # type: Optional[RC4Handle]
        self.__seq_num_in = 0  # type: int
        self.__seq_num_out = 0  # type: int