Exemple #1
0
 def fail_xor(self, in1, in2):
     try:
         xor_str(in1, in2)
     except Exception:
         pass
     else:
         raise Exception("xor_str did not fail on %s / %s" %
                         (h(in1), h(in2)))
 def process_delta(self, raw_data, width, height, rowstride, options):
     """
         Can be called from any thread, decompresses and xors the rgb raw_data,
         then stores it for later xoring if needed.
     """
     img_data = raw_data
     if options:
         #check for one of the compressors:
         comp = [x for x in compression.ALL_COMPRESSORS if options.intget(x, 0)]
         if comp:
             assert len(comp)==1, "more than one compressor specified: %s" % str(comp)
             img_data = compression.decompress_by_name(raw_data, algo=comp[0])
     if len(img_data)!=rowstride * height:
         log.error("invalid img data %s: %s", type(img_data), str(img_data)[:256])
         raise Exception("expected %s bytes for %sx%s with rowstride=%s but received %s (%s compressed)" %
                             (rowstride * height, width, height, rowstride, len(img_data), len(raw_data)))
     delta = options.intget("delta", -1)
     bucket = options.intget("bucket", 0)
     rgb_data = img_data
     if delta>=0:
         assert bucket>=0 and bucket<DELTA_BUCKETS, "invalid delta bucket number: %s" % bucket
         if self._delta_pixel_data[bucket] is None:
             raise Exception("delta region bucket %s references pixmap data we do not have!" % bucket)
         lwidth, lheight, seq, ldata = self._delta_pixel_data[bucket]
         assert width==lwidth and height==lheight and delta==seq, "delta bucket %s data does not match: expected %s but got %s" % (bucket, (width, height, delta), (lwidth, lheight, seq))
         deltalog("delta: xoring with bucket %i", bucket)
         rgb_data = xor_str(img_data, ldata)
     #store new pixels for next delta:
     store = options.intget("store", -1)
     if store>=0:
         deltalog("delta: storing sequence %i in bucket %i", store, bucket)
         self._delta_pixel_data[bucket] =  width, height, store, rgb_data
     return rgb_data
Exemple #3
0
 def _process_challenge(self, packet):
     authlog("processing challenge: %s", packet[1:])
     def warn_server_and_exit(code, message, server_message="authentication failed"):
         authlog.error("Error: authentication failed:")
         authlog.error(" %s", message)
         self.disconnect_and_quit(code, server_message)
     if not self.password_file and not os.environ.get('XPRA_PASSWORD'):
         warn_server_and_exit(EXIT_PASSWORD_REQUIRED, "this server requires authentication, please provide a password", "no password available")
         return
     password = self.load_password()
     if not password:
         warn_server_and_exit(EXIT_PASSWORD_FILE_ERROR, "failed to load password from file %s" % self.password_file, "no password available")
         return
     salt = packet[1]
     if self.encryption:
         assert len(packet)>=3, "challenge does not contain encryption details to use for the response"
         server_cipher = typedict(packet[2])
         key = self.get_encryption_key()
         if key is None:
             warn_server_and_exit(EXIT_ENCRYPTION, "the server does not use any encryption", "client requires encryption")
             return
         if not self.set_server_encryption(server_cipher, key):
             return
     #all server versions support a client salt,
     #they also tell us which digest to use:
     digest = packet[3]
     client_salt = get_hex_uuid()+get_hex_uuid()
     #TODO: use some key stretching algorigthm? (meh)
     try:
         from xpra.codecs.xor.cyxor import xor_str           #@UnresolvedImport
         salt = xor_str(salt, client_salt)
     except:
         salt = xor(salt, client_salt)
     if digest==b"hmac":
         import hmac, hashlib
         def s(v):
             try:
                 return v.encode()
             except:
                 return str(v)
         password = s(password)
         salt = s(salt)
         challenge_response = hmac.HMAC(password, salt, digestmod=hashlib.md5).hexdigest()
     elif digest==b"xor":
         #don't send XORed password unencrypted:
         if not self._protocol.cipher_out and not ALLOW_UNENCRYPTED_PASSWORDS:
             warn_server_and_exit(EXIT_ENCRYPTION, "server requested digest %s, cowardly refusing to use it without encryption" % digest, "invalid digest")
             return
         challenge_response = xor(password, salt)
     else:
         warn_server_and_exit(EXIT_PASSWORD_REQUIRED, "server requested an unsupported digest: %s" % digest, "invalid digest")
         return
     if digest:
         authlog("%s(%s, %s)=%s", digest, binascii.hexlify(password), binascii.hexlify(salt), challenge_response)
     self.password_sent = True
     self.remove_packet_handlers("challenge")
     self.send_hello(challenge_response, client_salt)
 def process_delta(self, raw_data, width, height, rowstride, options):
     """
         Can be called from any thread, decompresses and xors the rgb raw_data,
         then stores it for later xoring if needed.
     """
     img_data = raw_data
     if options:
         #check for one of the compressors:
         comp = [
             x for x in compression.ALL_COMPRESSORS if options.intget(x, 0)
         ]
         if comp:
             assert len(
                 comp
             ) == 1, "more than one compressor specified: %s" % str(comp)
             img_data = compression.decompress_by_name(raw_data,
                                                       algo=comp[0])
     if len(img_data) != rowstride * height:
         deltalog.error(
             "Error: invalid img data length: expected %s but got %s (%s: %s)",
             rowstride * height, len(img_data), type(img_data),
             repr_ellipsized(img_data))
         raise Exception(
             "expected %s bytes for %sx%s with rowstride=%s but received %s (%s compressed)"
             % (rowstride * height, width, height, rowstride, len(img_data),
                len(raw_data)))
     delta = options.intget(b"delta", -1)
     bucket = options.intget(b"bucket", 0)
     rgb_format = options.strget(b"rgb_format")
     rgb_data = img_data
     if delta >= 0:
         assert 0 <= bucket < DELTA_BUCKETS, "invalid delta bucket number: %s" % bucket
         if self._delta_pixel_data[bucket] is None:
             raise Exception(
                 "delta region bucket %s references pixmap data we do not have!"
                 % bucket)
         lwidth, lheight, lrgb_format, seq, ldata = self._delta_pixel_data[
             bucket]
         assert width==lwidth and height==lheight and delta==seq, \
             "delta bucket %s data does not match: expected %s but got %s" % (
                 bucket, (width, height, delta), (lwidth, lheight, seq))
         assert lrgb_format == rgb_format, "delta region uses %s format, was expecting %s" % (
             rgb_format, lrgb_format)
         deltalog("delta: xoring with bucket %i", bucket)
         rgb_data = xor_str(img_data, ldata)
     #store new pixels for next delta:
     store = options.intget("store", -1)
     if store >= 0:
         deltalog("delta: storing sequence %i in bucket %i", store, bucket)
         self._delta_pixel_data[
             bucket] = width, height, rgb_format, store, rgb_data
     return rgb_data
Exemple #5
0
def gendigest(digest, password, salt):
    assert password and salt
    salt = memoryview_to_bytes(salt)
    password = strtobytes(password)
    if digest == "des":
        from xpra.net.d3des import generate_response
        password = password.ljust(8, b"\x00")[:8]
        salt = salt.ljust(16, b"\x00")[:16]
        v = generate_response(password, salt)
        return hexstr(v)
    if digest in ("xor", "kerberos", "gss"):
        #kerberos and gss use xor because we need to use the actual token
        #at the other end
        salt = salt.ljust(len(password), b"\x00")[:len(password)]
        from xpra.codecs.xor.cyxor import xor_str  #@UnresolvedImport
        v = xor_str(password, salt)
        return memoryview_to_bytes(v)
    digestmod = get_digest_module(digest)
    if not digestmod:
        log("invalid digest module '%s'", digest)
        return None
        #warn_server_and_exit(EXIT_UNSUPPORTED, "server requested digest '%s' but it is not supported" % digest, "invalid digest")
    v = hmac.HMAC(password, salt, digestmod=digestmod).hexdigest()
    return v
Exemple #6
0
 def check_xor(self, in1, in2, expected):
     out = xor_str(in1, in2)
     #print("xor_str(%s, %s)=%s" % (h(in1), h(in2), h(out)))
     assert out == expected
Exemple #7
0
 def fail_xor(self, in1, in2):
     try:
         xor_str(in1, in2)
     except:
         return
     raise Exception("xor_str did not fail on %s / %s", h(in1), h(in2))
 def process_server_packet(self, proto, packet):
     packet_type = packet[0]
     log("process_server_packet: %s", packet_type)
     if packet_type==Protocol.CONNECTION_LOST:
         self.stop("server connection lost", proto)
         return
     elif packet_type=="disconnect":
         log("got disconnect from server: %s", packet[1])
         if self.exit:
             self.server_protocol.close()
         else:
             self.stop("disconnect from server: %s" % packet[1])
     elif packet_type=="hello":
         c = typedict(packet[1])
         maxw, maxh = c.intpair("max_desktop_size", (4096, 4096))
         caps = self.filter_server_caps(c)
         #add new encryption caps:
         if self.cipher:
             from xpra.net.crypto import crypto_backend_init, new_cipher_caps, DEFAULT_PADDING
             crypto_backend_init()
             padding_options = self.caps.strlistget("cipher.padding.options", [DEFAULT_PADDING])
             auth_caps = new_cipher_caps(self.client_protocol, self.cipher, self.encryption_key, padding_options)
             caps.update(auth_caps)
         #may need to bump packet size:
         proto.max_packet_size = maxw*maxh*4*4
         file_transfer = self.caps.boolget("file-transfer") and c.boolget("file-transfer")
         file_size_limit = max(self.caps.intget("file-size-limit"), c.intget("file-size-limit"))
         file_max_packet_size = int(file_transfer) * (1024 + file_size_limit*1024*1024)
         self.client_protocol.max_packet_size = max(self.client_protocol.max_packet_size, file_max_packet_size)
         self.server_protocol.max_packet_size = max(self.server_protocol.max_packet_size, file_max_packet_size)
         packet = ("hello", caps)
     elif packet_type=="info-response":
         #adds proxy info:
         #note: this is only seen by the client application
         #"xpra info" is a new connection, which talks to the proxy server...
         info = packet[1]
         info.update(self.get_proxy_info(proto))
     elif packet_type=="lost-window":
         wid = packet[1]
         #mark it as lost so we can drop any current/pending frames
         self.lost_windows.add(wid)
         #queue it so it gets cleaned safely (for video encoders mostly):
         self.encode_queue.put(packet)
         #and fall through so tell the client immediately
     elif packet_type=="draw":
         #use encoder thread:
         self.encode_queue.put(packet)
         #which will queue the packet itself when done:
         return
     #we do want to reformat cursor packets...
     #as they will have been uncompressed by the network layer already:
     elif packet_type=="cursor":
         #packet = ["cursor", x, y, width, height, xhot, yhot, serial, pixels, name]
         #or:
         #packet = ["cursor", "png", x, y, width, height, xhot, yhot, serial, pixels, name]
         #or:
         #packet = ["cursor", ""]
         if len(packet)>=8:
             #hard to distinguish png cursors from normal cursors...
             try:
                 int(packet[1])
                 self._packet_recompress(packet, 8, "cursor")
             except:
                 self._packet_recompress(packet, 9, "cursor")
     elif packet_type=="window-icon":
         self._packet_recompress(packet, 5, "icon")
     elif packet_type=="send-file":
         if packet[6]:
             packet[6] = Compressed("file-data", packet[6])
     elif packet_type=="send-file-chunk":
         if packet[3]:
             packet[3] = Compressed("file-chunk-data", packet[3])
     elif packet_type=="challenge":
         from xpra.net.crypto import get_salt
         #client may have already responded to the challenge,
         #so we have to handle authentication from this end
         salt = packet[1]
         digest = packet[3]
         client_salt = get_salt(len(salt))
         salt = xor_str(salt, client_salt)
         if digest!=b"hmac":
             self.stop("digest mode '%s' not supported", std(digest))
             return
         password = self.disp_desc.get("password", self.session_options.get("password"))
         log("password from %s / %s = %s", self.disp_desc, self.session_options, password)
         if not password:
             self.stop("authentication requested by the server, but no password available for this session")
             return
         import hmac, hashlib
         password = strtobytes(password)
         salt = strtobytes(salt)
         challenge_response = hmac.HMAC(password, salt, digestmod=hashlib.md5).hexdigest()
         log.info("sending %s challenge response", digest)
         self.send_hello(challenge_response, client_salt)
         return
     self.queue_client_packet(packet)
Exemple #9
0
 def check_xor(self, in1, in2, expected):
     out = xor_str(in1, in2)
     #print("xor_str(%s, %s)=%s" % (h(in1), h(in2), h(out)))
     assert out==expected
Exemple #10
0
 def fail_xor(self, in1, in2):
     try:
         xor_str(in1, in2)
     except:
         return
     raise Exception("xor_str did not fail on %s / %s", h(in1), h(in2))
 def process_server_packet(self, proto, packet):
     packet_type = packet[0]
     log("process_server_packet: %s", packet_type)
     if packet_type==Protocol.CONNECTION_LOST:
         self.stop("server connection lost", proto)
         return
     elif packet_type=="disconnect":
         log("got disconnect from server: %s", packet[1])
         if self.exit:
             self.server_protocol.close()
         else:
             self.stop("disconnect from server: %s" % packet[1])
     elif packet_type=="hello":
         c = typedict(packet[1])
         maxw, maxh = c.intpair("max_desktop_size", (4096, 4096))
         caps = self.filter_server_caps(c)
         #add new encryption caps:
         if self.cipher:
             from xpra.net.crypto import crypto_backend_init, new_cipher_caps, DEFAULT_PADDING
             crypto_backend_init()
             padding_options = self.caps.strlistget("cipher.padding.options", [DEFAULT_PADDING])
             auth_caps = new_cipher_caps(self.client_protocol, self.cipher, self.encryption_key, padding_options)
             caps.update(auth_caps)
         #may need to bump packet size:
         proto.max_packet_size = maxw*maxh*4*4
         file_transfer = self.caps.boolget("file-transfer") and c.boolget("file-transfer")
         file_size_limit = max(self.caps.intget("file-size-limit"), c.intget("file-size-limit"))
         file_max_packet_size = int(file_transfer) * (1024 + file_size_limit*1024*1024)
         self.client_protocol.max_packet_size = max(self.client_protocol.max_packet_size, file_max_packet_size)
         self.server_protocol.max_packet_size = max(self.server_protocol.max_packet_size, file_max_packet_size)
         packet = ("hello", caps)
     elif packet_type=="info-response":
         #adds proxy info:
         #note: this is only seen by the client application
         #"xpra info" is a new connection, which talks to the proxy server...
         info = packet[1]
         info.update(self.get_proxy_info(proto))
     elif packet_type=="lost-window":
         wid = packet[1]
         #mark it as lost so we can drop any current/pending frames
         self.lost_windows.add(wid)
         #queue it so it gets cleaned safely (for video encoders mostly):
         self.encode_queue.put(packet)
         #and fall through so tell the client immediately
     elif packet_type=="draw":
         #use encoder thread:
         self.encode_queue.put(packet)
         #which will queue the packet itself when done:
         return
     #we do want to reformat cursor packets...
     #as they will have been uncompressed by the network layer already:
     elif packet_type=="cursor":
         #packet = ["cursor", x, y, width, height, xhot, yhot, serial, pixels, name]
         #or:
         #packet = ["cursor", "png", x, y, width, height, xhot, yhot, serial, pixels, name]
         #or:
         #packet = ["cursor", ""]
         if len(packet)>=8:
             #hard to distinguish png cursors from normal cursors...
             try:
                 int(packet[1])
                 self._packet_recompress(packet, 8, "cursor")
             except:
                 self._packet_recompress(packet, 9, "cursor")
     elif packet_type=="window-icon":
         self._packet_recompress(packet, 5, "icon")
     elif packet_type=="send-file":
         if packet[6]:
             packet[6] = Compressed("file-data", packet[6])
     elif packet_type=="send-file-chunk":
         if packet[3]:
             packet[3] = Compressed("file-chunk-data", packet[3])
     elif packet_type=="challenge":
         from xpra.net.crypto import get_salt
         #client may have already responded to the challenge,
         #so we have to handle authentication from this end
         salt = packet[1]
         digest = packet[3]
         client_salt = get_salt(len(salt))
         salt = xor_str(salt, client_salt)
         if digest!=b"hmac":
             self.stop("digest mode '%s' not supported", std(digest))
             return
         password = self.session_options.get("password")
         if not password:
             self.stop("authentication requested by the server, but no password available for this session")
             return
         import hmac, hashlib
         password = strtobytes(password)
         salt = strtobytes(salt)
         challenge_response = hmac.HMAC(password, salt, digestmod=hashlib.md5).hexdigest()
         log.info("sending %s challenge response", digest)
         self.send_hello(challenge_response, client_salt)
         return
     self.queue_client_packet(packet)
Exemple #12
0
    def _process_challenge(self, packet):
        authlog("processing challenge: %s", packet[1:])

        def warn_server_and_exit(code,
                                 message,
                                 server_message="authentication failed"):
            authlog.error("Error: authentication failed:")
            authlog.error(" %s", message)
            self.disconnect_and_quit(code, server_message)

        if not self.has_password():
            warn_server_and_exit(
                EXIT_PASSWORD_REQUIRED,
                "this server requires authentication, please provide a password",
                "no password available")
            return
        password = self.load_password()
        if not password:
            warn_server_and_exit(
                EXIT_PASSWORD_FILE_ERROR,
                "failed to load password from file %s" % self.password_file,
                "no password available")
            return
        salt = packet[1]
        if self.encryption:
            assert len(
                packet
            ) >= 3, "challenge does not contain encryption details to use for the response"
            server_cipher = typedict(packet[2])
            key = self.get_encryption_key()
            if key is None:
                warn_server_and_exit(EXIT_ENCRYPTION,
                                     "the server does not use any encryption",
                                     "client requires encryption")
                return
            if not self.set_server_encryption(server_cipher, key):
                return
        #all server versions support a client salt,
        #they also tell us which digest to use:
        digest = packet[3]
        client_salt = get_salt(len(salt))
        #TODO: use some key stretching algorigthm? (meh)
        try:
            from xpra.codecs.xor.cyxor import xor_str  #@UnresolvedImport
            salt = xor_str(salt, client_salt)
        except:
            salt = xor(salt, client_salt)
        if digest == b"hmac":
            import hmac, hashlib
            password = strtobytes(password)
            salt = strtobytes(salt)
            challenge_response = hmac.HMAC(password,
                                           salt,
                                           digestmod=hashlib.md5).hexdigest()
        elif digest == b"xor":
            #don't send XORed password unencrypted:
            if not self._protocol.cipher_out and not ALLOW_UNENCRYPTED_PASSWORDS:
                warn_server_and_exit(
                    EXIT_ENCRYPTION,
                    "server requested digest %s, cowardly refusing to use it without encryption"
                    % digest, "invalid digest")
                return
            salt = salt[:len(password)]
            challenge_response = strtobytes(xor(password, salt))
        else:
            warn_server_and_exit(
                EXIT_PASSWORD_REQUIRED,
                "server requested an unsupported digest: %s" % digest,
                "invalid digest")
            return
        if digest:
            authlog("%s(%s, %s)=%s", digest, binascii.hexlify(password),
                    binascii.hexlify(salt), challenge_response)
        self.password_sent = True
        self.remove_packet_handlers("challenge")
        self.send_hello(challenge_response, client_salt)