diff --git a/sambacc/grpc/backend.py b/sambacc/grpc/backend.py index a814378a..c02a1810 100644 --- a/sambacc/grpc/backend.py +++ b/sambacc/grpc/backend.py @@ -16,7 +16,7 @@ # along with this program. If not, see # -from typing import Any, Union +from typing import Any, Union, Optional import dataclasses import json @@ -30,9 +30,22 @@ @dataclasses.dataclass class Versions: - samba_version: str = "foo" - sambacc_version: str = "bar" - container_version: str = "baz" + samba_version: str = "" + sambacc_version: str = "" + container_version: str = "" + + +@dataclasses.dataclass +class SessionCrypto: + cipher: str + degree: str + + @classmethod + def load(cls, json_object: dict[str, Any]) -> Self: + cipher = json_object.get("cipher", "") + cipher = "" if cipher == "-" else cipher + degree = json_object.get("degree", "") + return cls(cipher=cipher, degree=degree) @dataclasses.dataclass @@ -45,9 +58,15 @@ class Session: session_dialect: str uid: int gid: int + encryption: Optional[SessionCrypto] = None + signing: Optional[SessionCrypto] = None @classmethod def load(cls, json_object: dict[str, Any]) -> Self: + _encryption = json_object.get("encryption") + encryption = SessionCrypto.load(_encryption) if _encryption else None + _signing = json_object.get("signing") + signing = SessionCrypto.load(_signing) if _signing else None return cls( session_id=json_object.get("session_id", ""), username=json_object.get("username", ""), @@ -57,6 +76,8 @@ def load(cls, json_object: dict[str, Any]) -> Self: session_dialect=json_object.get("session_dialect", ""), uid=int(json_object.get("uid", -1)), gid=int(json_object.get("gid", -1)), + encryption=encryption, + signing=signing, ) diff --git a/sambacc/grpc/generated/control_pb2.py b/sambacc/grpc/generated/control_pb2.py index 99bd974d..df5c95d9 100644 --- a/sambacc/grpc/generated/control_pb2.py +++ b/sambacc/grpc/generated/control_pb2.py @@ -14,7 +14,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rcontrol.proto\"\r\n\x0bInfoRequest\"/\n\tSambaInfo\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x11\n\tclustered\x18\x02 \x01(\x08\"H\n\x12SambaContainerInfo\x12\x17\n\x0fsambacc_version\x18\x01 \x01(\t\x12\x19\n\x11\x63ontainer_version\x18\x02 \x01(\t\"Z\n\x0bGeneralInfo\x12\x1e\n\nsamba_info\x18\x01 \x01(\x0b\x32\n.SambaInfo\x12+\n\x0e\x63ontainer_info\x18\x02 \x01(\x0b\x32\x13.SambaContainerInfo\"\x0f\n\rStatusRequest\"\xa3\x01\n\x0bSessionInfo\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x11\n\tgroupname\x18\x03 \x01(\t\x12\x16\n\x0eremote_machine\x18\x04 \x01(\t\x12\x10\n\x08hostname\x18\x05 \x01(\t\x12\x17\n\x0fsession_dialect\x18\x06 \x01(\t\x12\x0b\n\x03uid\x18\x07 \x01(\r\x12\x0b\n\x03gid\x18\x08 \x01(\r\"E\n\x08\x43onnInfo\x12\x0f\n\x07tcon_id\x18\x01 \x01(\t\x12\x12\n\nsession_id\x18\x02 \x01(\t\x12\x14\n\x0cservice_name\x18\x03 \x01(\t\"k\n\nStatusInfo\x12\x18\n\x10server_timestamp\x18\x01 \x01(\t\x12\x1e\n\x08sessions\x18\x02 \x03(\x0b\x32\x0c.SessionInfo\x12#\n\x10tree_connections\x18\x03 \x03(\x0b\x32\t.ConnInfo\"=\n\x11\x43loseShareRequest\x12\x12\n\nshare_name\x18\x01 \x01(\t\x12\x14\n\x0c\x64\x65nied_users\x18\x02 \x01(\x08\"\x10\n\x0e\x43loseShareInfo\"\'\n\x11KillClientRequest\x12\x12\n\nip_address\x18\x01 \x01(\t\"\x10\n\x0eKillClientInfo2\xc9\x01\n\x0cSambaControl\x12\"\n\x04Info\x12\x0c.InfoRequest\x1a\x0c.GeneralInfo\x12%\n\x06Status\x12\x0e.StatusRequest\x1a\x0b.StatusInfo\x12\x31\n\nCloseShare\x12\x12.CloseShareRequest\x1a\x0f.CloseShareInfo\x12;\n\x14KillClientConnection\x12\x12.KillClientRequest\x1a\x0f.KillClientInfob\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rcontrol.proto\"\r\n\x0bInfoRequest\"/\n\tSambaInfo\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x11\n\tclustered\x18\x02 \x01(\x08\"H\n\x12SambaContainerInfo\x12\x17\n\x0fsambacc_version\x18\x01 \x01(\t\x12\x19\n\x11\x63ontainer_version\x18\x02 \x01(\t\"Z\n\x0bGeneralInfo\x12\x1e\n\nsamba_info\x18\x01 \x01(\x0b\x32\n.SambaInfo\x12+\n\x0e\x63ontainer_info\x18\x02 \x01(\x0b\x32\x13.SambaContainerInfo\"\x0f\n\rStatusRequest\"/\n\rSessionCrypto\x12\x0e\n\x06\x63ipher\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65gree\x18\x02 \x01(\t\"\xe8\x01\n\x0bSessionInfo\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x11\n\tgroupname\x18\x03 \x01(\t\x12\x16\n\x0eremote_machine\x18\x04 \x01(\t\x12\x10\n\x08hostname\x18\x05 \x01(\t\x12\x17\n\x0fsession_dialect\x18\x06 \x01(\t\x12\x0b\n\x03uid\x18\x07 \x01(\r\x12\x0b\n\x03gid\x18\x08 \x01(\r\x12\"\n\nencryption\x18\t \x01(\x0b\x32\x0e.SessionCrypto\x12\x1f\n\x07signing\x18\n \x01(\x0b\x32\x0e.SessionCrypto\"E\n\x08\x43onnInfo\x12\x0f\n\x07tcon_id\x18\x01 \x01(\t\x12\x12\n\nsession_id\x18\x02 \x01(\t\x12\x14\n\x0cservice_name\x18\x03 \x01(\t\"k\n\nStatusInfo\x12\x18\n\x10server_timestamp\x18\x01 \x01(\t\x12\x1e\n\x08sessions\x18\x02 \x03(\x0b\x32\x0c.SessionInfo\x12#\n\x10tree_connections\x18\x03 \x03(\x0b\x32\t.ConnInfo\"=\n\x11\x43loseShareRequest\x12\x12\n\nshare_name\x18\x01 \x01(\t\x12\x14\n\x0c\x64\x65nied_users\x18\x02 \x01(\x08\"\x10\n\x0e\x43loseShareInfo\"\'\n\x11KillClientRequest\x12\x12\n\nip_address\x18\x01 \x01(\t\"\x10\n\x0eKillClientInfo2\xc9\x01\n\x0cSambaControl\x12\"\n\x04Info\x12\x0c.InfoRequest\x1a\x0c.GeneralInfo\x12%\n\x06Status\x12\x0e.StatusRequest\x1a\x0b.StatusInfo\x12\x31\n\nCloseShare\x12\x12.CloseShareRequest\x1a\x0f.CloseShareInfo\x12;\n\x14KillClientConnection\x12\x12.KillClientRequest\x1a\x0f.KillClientInfob\x06proto3') @@ -23,6 +23,7 @@ _SAMBACONTAINERINFO = DESCRIPTOR.message_types_by_name['SambaContainerInfo'] _GENERALINFO = DESCRIPTOR.message_types_by_name['GeneralInfo'] _STATUSREQUEST = DESCRIPTOR.message_types_by_name['StatusRequest'] +_SESSIONCRYPTO = DESCRIPTOR.message_types_by_name['SessionCrypto'] _SESSIONINFO = DESCRIPTOR.message_types_by_name['SessionInfo'] _CONNINFO = DESCRIPTOR.message_types_by_name['ConnInfo'] _STATUSINFO = DESCRIPTOR.message_types_by_name['StatusInfo'] @@ -65,6 +66,13 @@ }) _sym_db.RegisterMessage(StatusRequest) +SessionCrypto = _reflection.GeneratedProtocolMessageType('SessionCrypto', (_message.Message,), { + 'DESCRIPTOR' : _SESSIONCRYPTO, + '__module__' : 'control_pb2' + # @@protoc_insertion_point(class_scope:SessionCrypto) + }) +_sym_db.RegisterMessage(SessionCrypto) + SessionInfo = _reflection.GeneratedProtocolMessageType('SessionInfo', (_message.Message,), { 'DESCRIPTOR' : _SESSIONINFO, '__module__' : 'control_pb2' @@ -128,20 +136,22 @@ _GENERALINFO._serialized_end=245 _STATUSREQUEST._serialized_start=247 _STATUSREQUEST._serialized_end=262 - _SESSIONINFO._serialized_start=265 - _SESSIONINFO._serialized_end=428 - _CONNINFO._serialized_start=430 - _CONNINFO._serialized_end=499 - _STATUSINFO._serialized_start=501 - _STATUSINFO._serialized_end=608 - _CLOSESHAREREQUEST._serialized_start=610 - _CLOSESHAREREQUEST._serialized_end=671 - _CLOSESHAREINFO._serialized_start=673 - _CLOSESHAREINFO._serialized_end=689 - _KILLCLIENTREQUEST._serialized_start=691 - _KILLCLIENTREQUEST._serialized_end=730 - _KILLCLIENTINFO._serialized_start=732 - _KILLCLIENTINFO._serialized_end=748 - _SAMBACONTROL._serialized_start=751 - _SAMBACONTROL._serialized_end=952 + _SESSIONCRYPTO._serialized_start=264 + _SESSIONCRYPTO._serialized_end=311 + _SESSIONINFO._serialized_start=314 + _SESSIONINFO._serialized_end=546 + _CONNINFO._serialized_start=548 + _CONNINFO._serialized_end=617 + _STATUSINFO._serialized_start=619 + _STATUSINFO._serialized_end=726 + _CLOSESHAREREQUEST._serialized_start=728 + _CLOSESHAREREQUEST._serialized_end=789 + _CLOSESHAREINFO._serialized_start=791 + _CLOSESHAREINFO._serialized_end=807 + _KILLCLIENTREQUEST._serialized_start=809 + _KILLCLIENTREQUEST._serialized_end=848 + _KILLCLIENTINFO._serialized_start=850 + _KILLCLIENTINFO._serialized_end=866 + _SAMBACONTROL._serialized_start=869 + _SAMBACONTROL._serialized_end=1070 # @@protoc_insertion_point(module_scope) diff --git a/sambacc/grpc/generated/control_pb2.pyi b/sambacc/grpc/generated/control_pb2.pyi index d2264cc1..f51a8838 100644 --- a/sambacc/grpc/generated/control_pb2.pyi +++ b/sambacc/grpc/generated/control_pb2.pyi @@ -100,6 +100,23 @@ class StatusRequest(google.protobuf.message.Message): global___StatusRequest = StatusRequest +class SessionCrypto(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + CIPHER_FIELD_NUMBER: builtins.int + DEGREE_FIELD_NUMBER: builtins.int + cipher: builtins.str + degree: builtins.str + def __init__( + self, + *, + cipher: builtins.str = ..., + degree: builtins.str = ..., + ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["cipher", b"cipher", "degree", b"degree"]) -> None: ... + +global___SessionCrypto = SessionCrypto + class SessionInfo(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor @@ -111,6 +128,8 @@ class SessionInfo(google.protobuf.message.Message): SESSION_DIALECT_FIELD_NUMBER: builtins.int UID_FIELD_NUMBER: builtins.int GID_FIELD_NUMBER: builtins.int + ENCRYPTION_FIELD_NUMBER: builtins.int + SIGNING_FIELD_NUMBER: builtins.int session_id: builtins.str username: builtins.str groupname: builtins.str @@ -119,6 +138,10 @@ class SessionInfo(google.protobuf.message.Message): session_dialect: builtins.str uid: builtins.int gid: builtins.int + @property + def encryption(self) -> global___SessionCrypto: ... + @property + def signing(self) -> global___SessionCrypto: ... def __init__( self, *, @@ -130,8 +153,11 @@ class SessionInfo(google.protobuf.message.Message): session_dialect: builtins.str = ..., uid: builtins.int = ..., gid: builtins.int = ..., + encryption: global___SessionCrypto | None = ..., + signing: global___SessionCrypto | None = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["gid", b"gid", "groupname", b"groupname", "hostname", b"hostname", "remote_machine", b"remote_machine", "session_dialect", b"session_dialect", "session_id", b"session_id", "uid", b"uid", "username", b"username"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["encryption", b"encryption", "signing", b"signing"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["encryption", b"encryption", "gid", b"gid", "groupname", b"groupname", "hostname", b"hostname", "remote_machine", b"remote_machine", "session_dialect", b"session_dialect", "session_id", b"session_id", "signing", b"signing", "uid", b"uid", "username", b"username"]) -> None: ... global___SessionInfo = SessionInfo diff --git a/sambacc/grpc/protobufs/control.proto b/sambacc/grpc/protobufs/control.proto index 32f16f3c..1a7e6722 100644 --- a/sambacc/grpc/protobufs/control.proto +++ b/sambacc/grpc/protobufs/control.proto @@ -32,6 +32,11 @@ message GeneralInfo { message StatusRequest {} +message SessionCrypto { + string cipher = 1; + string degree = 2; +} + message SessionInfo { string session_id = 1; string username = 2; @@ -41,6 +46,8 @@ message SessionInfo { string session_dialect = 6; uint32 uid = 7; uint32 gid = 8; + SessionCrypto encryption = 9; + SessionCrypto signing = 10; } message ConnInfo { diff --git a/sambacc/grpc/server.py b/sambacc/grpc/server.py index 134c6d41..d482a972 100644 --- a/sambacc/grpc/server.py +++ b/sambacc/grpc/server.py @@ -72,6 +72,14 @@ def _get_info(backend: Backend) -> pb.GeneralInfo: ) +def _convert_crypto( + crypto: Optional[rbe.SessionCrypto], +) -> Optional[pb.SessionCrypto]: + if not crypto: + return None + return pb.SessionCrypto(cipher=crypto.cipher, degree=crypto.degree) + + def _convert_session(session: rbe.Session) -> pb.SessionInfo: info = pb.SessionInfo( session_id=session.session_id, @@ -80,6 +88,8 @@ def _convert_session(session: rbe.Session) -> pb.SessionInfo: remote_machine=session.remote_machine, hostname=session.hostname, session_dialect=session.session_dialect, + encryption=_convert_crypto(session.encryption), + signing=_convert_crypto(session.signing), ) # python side takes -1 to mean not found uid/gid. in protobufs # that would mean the fields are unset diff --git a/tests/test_grpc_backend.py b/tests/test_grpc_backend.py index 320f0d1b..31f07486 100644 --- a/tests/test_grpc_backend.py +++ b/tests/test_grpc_backend.py @@ -156,6 +156,12 @@ def _status_json1_check(status): assert s1.uid == 103107 assert s1.gid == 102513 assert len(status.tcons) == 1 + assert s1.encryption + assert s1.encryption.cipher == "" + assert s1.encryption.degree == "none" + assert s1.signing + assert s1.signing.cipher == "AES-128-GMAC" + assert s1.signing.degree == "partial" t1 = status.tcons[0] assert t1.tcon_id == "3757739897" assert t1.session_id == "2891148582" diff --git a/tests/test_grpc_server.py b/tests/test_grpc_server.py index 0c7d87c4..8d50e60f 100644 --- a/tests/test_grpc_server.py +++ b/tests/test_grpc_server.py @@ -194,7 +194,18 @@ def test_status(mock_grpc_server): assert mock_grpc_server.backend._counter["get_status"] == 1 assert rsp.server_timestamp == "2025-05-08T20:41:57.273489+0000" - # TODO data assertions + # data assertions + assert len(rsp.sessions) == 1 + assert rsp.sessions[0].session_id == "2891148582" + assert rsp.sessions[0].uid == 103107 + assert rsp.sessions[0].gid == 102513 + assert rsp.sessions[0].username == "DOMAIN1\\bwayne" + assert rsp.sessions[0].encryption + assert rsp.sessions[0].encryption.cipher == "" + assert rsp.sessions[0].encryption.degree == "none" + assert rsp.sessions[0].signing + assert rsp.sessions[0].signing.cipher == "AES-128-GMAC" + assert rsp.sessions[0].signing.degree == "partial" def test_close_share(mock_grpc_server):