gssapi/ctx.py
def step(self, input_token):
        """Performs a step to establish the context as an acceptor.

        This method should be called in a loop and fed input tokens from the initiator, and its
        output tokens should be sent to the initiator, until this context's :attr:`established`
        attribute is True.

        :param input_token: The input token from the initiator (required).
        :type input_token: bytes
        :returns: either a byte string with the next token to send to the initiator,
            or None if there is no further token to send to the initiator.
        :raises: :exc:`~gssapi.error.GSSException` if there is an error establishing the context.
        """
        minor_status = ffi.new('OM_uint32[1]')
        input_token_buffer = ffi.new('gss_buffer_desc[1]')
        input_token_buffer[0].length = len(input_token)
        c_str_import_token = ffi.new('char[]', input_token)
        input_token_buffer[0].value = c_str_import_token

        mech_type = ffi.new('gss_OID[1]')
        output_token_buffer = ffi.new('gss_buffer_desc[1]')
        src_name_handle = ffi.new('gss_name_t[1]')
        actual_flags = ffi.new('OM_uint32[1]')
        time_rec = ffi.new('OM_uint32[1]')
        delegated_cred_handle = ffi.new('gss_cred_id_t[1]')

        if self._cred_object is not None:
            cred = self._cred_object._cred[0]
        else:
            cred = ffi.cast('gss_cred_id_t', C.GSS_C_NO_CREDENTIAL)

        retval = C.gss_accept_sec_context(
            minor_status,
            self._ctx,
            cred,
            input_token_buffer,
            self._channel_bindings,
            src_name_handle,
            mech_type,
            output_token_buffer,
            actual_flags,
            time_rec,
            delegated_cred_handle
        )
        if src_name_handle[0]:
            src_name = MechName(src_name_handle, mech_type[0])  # make sure src_name is GC'd
        try:
            if output_token_buffer[0].length != 0:
                out_token = _buf_to_str(output_token_buffer[0])
            else:
                out_token = None

            if GSS_ERROR(retval):
                if minor_status[0] and mech_type[0]:
                    raise _exception_for_status(retval, minor_status[0], mech_type[0], out_token)
                else:
                    raise _exception_for_status(retval, minor_status[0], None, out_token)

            self.established = not (retval & C.GSS_S_CONTINUE_NEEDED)
            self.flags = actual_flags[0]

            if (self.flags & C.GSS_C_DELEG_FLAG):
                self.delegated_cred = Credential(delegated_cred_handle)

            if mech_type[0]:
                self.mech_type = OID(mech_type[0][0])

                if src_name_handle[0]:
                    src_name._mech_type = self.mech_type
                    self.peer_name = src_name

            return out_token
        except:
            if self._ctx:
                C.gss_delete_sec_context(
                    minor_status,
                    self._ctx,
                    ffi.cast('gss_buffer_t', C.GSS_C_NO_BUFFER)
                )
                self._reset_flags()
            raise
        finally:
            if output_token_buffer[0].length != 0:
                C.gss_release_buffer(minor_status, output_token_buffer)
            # if self.delegated_cred is present, it will handle gss_release_cred:
            if delegated_cred_handle[0] and not self.delegated_cred:
                C.gss_release_cred(minor_status, delegated_cred_handle)
def step(self, input_token):
        """Performs a step to establish the context as an acceptor.

        This method should be called in a loop and fed input tokens from the initiator, and its
        output tokens should be sent to the initiator, until this context's :attr:`established`
        attribute is True.

        :param input_token: The input token from the initiator (required).
        :type input_token: bytes
        :returns: either a byte string with the next token to send to the initiator,
            or None if there is no further token to send to the initiator.
        :raises: :exc:`~gssapi.error.GSSException` if there is an error establishing the context.
        """
        minor_status = ffi.new('OM_uint32[1]')
        input_token_buffer = ffi.new('gss_buffer_desc[1]')
        input_token_buffer[0].length = len(input_token)
        c_str_import_token = ffi.new('char[]', input_token)
        input_token_buffer[0].value = c_str_import_token

        mech_type = ffi.new('gss_OID[1]')
        output_token_buffer = ffi.new('gss_buffer_desc[1]')
        src_name_handle = ffi.new('gss_name_t[1]')
        actual_flags = ffi.new('OM_uint32[1]')
        time_rec = ffi.new('OM_uint32[1]')
        delegated_cred_handle = ffi.new('gss_cred_id_t[1]')

        if self._cred_object is not None:
            cred = self._cred_object._cred[0]
        else:
            cred = ffi.cast('gss_cred_id_t', C.GSS_C_NO_CREDENTIAL)

        retval = C.gss_accept_sec_context(
            minor_status,
            self._ctx,
            cred,
            input_token_buffer,
            self._channel_bindings,
            src_name_handle,
            mech_type,
            output_token_buffer,
            actual_flags,
            time_rec,
            delegated_cred_handle
        )
        if src_name_handle[0]:
            src_name = MechName(src_name_handle, mech_type[0])  # make sure src_name is GC'd
        try:
            if output_token_buffer[0].length != 0:
                out_token = _buf_to_str(output_token_buffer[0])
            else:
                out_token = None

            if GSS_ERROR(retval):
                if minor_status[0] and mech_type[0]:
                    raise _exception_for_status(retval, minor_status[0], mech_type[0], out_token)
                else:
                    raise _exception_for_status(retval, minor_status[0], None, out_token)

            self.established = not (retval & C.GSS_S_CONTINUE_NEEDED)
            self.flags = actual_flags[0]

            if (self.flags & C.GSS_C_DELEG_FLAG):
                self.delegated_cred = Credential(delegated_cred_handle)

            if mech_type[0]:
                self.mech_type = OID(mech_type[0][0])

                if src_name_handle[0]:
                    src_name._mech_type = self.mech_type
                    self.peer_name = src_name

            return out_token
        except:
            if self._ctx:
                C.gss_delete_sec_context(
                    minor_status,
                    self._ctx,
                    ffi.cast('gss_buffer_t', C.GSS_C_NO_BUFFER)
                )
                self._reset_flags()
            raise
        finally:
            if output_token_buffer[0].length != 0:
                C.gss_release_buffer(minor_status, output_token_buffer)
            # if self.delegated_cred is present, it will handle gss_release_cred:
            if delegated_cred_handle[0] and not self.delegated_cred:
                C.gss_release_cred(minor_status, delegated_cred_handle)
Performs a step to establish the context as an acceptor.

        This method should be called in a loop and fed input tokens from the initiator, and its
        output tokens should be sent to the initiator, until this context's :attr:`established`
        attribute is True.

        :param input_token: The input token from the initiator (required).
        :type input_token: bytes
        :returns: either a byte string with the next token to send to the initiator,
            or None if there is no further token to send to the initiator.
        :raises: :exc:`~gssapi.error.GSSException` if there is an error establishing the context.