@@ -208,7 +208,7 @@ class ASN1_Class_LDAP(ASN1_Class):
208208
209209
210210# Bind operation
211- # https://datatracker.ietf.org/doc/html/rfc1777 #section-4.1
211+ # https://datatracker.ietf.org/doc/html/rfc4511 #section-4.2
212212
213213
214214class ASN1_Class_LDAP_Authentication (ASN1_Class ):
@@ -397,7 +397,7 @@ def serverSaslCredsData(self):
397397
398398
399399# Unbind operation
400- # https://datatracker.ietf.org/doc/html/rfc1777 #section-4.2
400+ # https://datatracker.ietf.org/doc/html/rfc4511 #section-4.3
401401
402402
403403class LDAP_UnbindRequest (ASN1_Packet ):
@@ -409,7 +409,7 @@ class LDAP_UnbindRequest(ASN1_Packet):
409409
410410
411411# Search operation
412- # https://datatracker.ietf.org/doc/html/rfc1777 #section-4.3
412+ # https://datatracker.ietf.org/doc/html/rfc4511 #section-4.5
413413
414414
415415class LDAP_SubstringFilterInitial (ASN1_Packet ):
@@ -759,16 +759,16 @@ class LDAP_SearchRequest(ASN1_Packet):
759759 )
760760
761761
762- class LDAP_SearchResponseEntryAttributeValue (ASN1_Packet ):
762+ class LDAP_AttributeValue (ASN1_Packet ):
763763 ASN1_codec = ASN1_Codecs .BER
764764 ASN1_root = AttributeValue ("value" , "" )
765765
766766
767- class LDAP_SearchResponseEntryAttribute (ASN1_Packet ):
767+ class LDAP_PartialAttribute (ASN1_Packet ):
768768 ASN1_codec = ASN1_Codecs .BER
769769 ASN1_root = ASN1F_SEQUENCE (
770770 AttributeType ("type" , "" ),
771- ASN1F_SET_OF ("values" , [], LDAP_SearchResponseEntryAttributeValue ),
771+ ASN1F_SET_OF ("values" , [], LDAP_AttributeValue ),
772772 )
773773
774774
@@ -778,8 +778,8 @@ class LDAP_SearchResponseEntry(ASN1_Packet):
778778 LDAPDN ("objectName" , "" ),
779779 ASN1F_SEQUENCE_OF (
780780 "attributes" ,
781- LDAP_SearchResponseEntryAttribute (),
782- LDAP_SearchResponseEntryAttribute ,
781+ LDAP_PartialAttribute (),
782+ LDAP_PartialAttribute ,
783783 ),
784784 implicit_tag = ASN1_Class_LDAP .SearchResultEntry ,
785785 )
@@ -793,14 +793,6 @@ class LDAP_SearchResponseResultDone(ASN1_Packet):
793793 )
794794
795795
796- class LDAP_AbandonRequest (ASN1_Packet ):
797- ASN1_codec = ASN1_Codecs .BER
798- ASN1_root = ASN1F_SEQUENCE (
799- ASN1F_INTEGER ("messageID" , 0 ),
800- implicit_tag = ASN1_Class_LDAP .AbandonRequest ,
801- )
802-
803-
804796class LDAP_SearchResponseReference (ASN1_Packet ):
805797 ASN1_codec = ASN1_Codecs .BER
806798 ASN1_root = ASN1F_SEQUENCE_OF (
@@ -811,6 +803,106 @@ class LDAP_SearchResponseReference(ASN1_Packet):
811803 )
812804
813805
806+ # Modify Operation
807+ # https://datatracker.ietf.org/doc/html/rfc4511#section-4.6
808+
809+
810+ class LDAP_ModifyRequestChange (ASN1_Packet ):
811+ ASN1_codec = ASN1_Codecs .BER
812+ ASN1_root = ASN1F_SEQUENCE (
813+ ASN1F_ENUMERATED (
814+ "operation" ,
815+ 0 ,
816+ {
817+ 0 : "add" ,
818+ 1 : "delete" ,
819+ 2 : "replace" ,
820+ },
821+ ),
822+ ASN1F_PACKET ("modification" , LDAP_PartialAttribute (), LDAP_PartialAttribute ),
823+ )
824+
825+
826+ class LDAP_ModifyRequest (ASN1_Packet ):
827+ ASN1_codec = ASN1_Codecs .BER
828+ ASN1_root = ASN1F_SEQUENCE (
829+ LDAPDN ("object" , "" ),
830+ ASN1F_SEQUENCE_OF ("changes" , [], LDAP_ModifyRequestChange ),
831+ implicit_tag = ASN1_Class_LDAP .ModifyRequest ,
832+ )
833+
834+
835+ class LDAP_ModifyResponse (ASN1_Packet ):
836+ ASN1_codec = ASN1_Codecs .BER
837+ ASN1_root = ASN1F_SEQUENCE (
838+ * LDAPResult ,
839+ implicit_tag = ASN1_Class_LDAP .ModifyResponse ,
840+ )
841+
842+
843+ # Add Operation
844+ # https://datatracker.ietf.org/doc/html/rfc4511#section-4.7
845+
846+
847+ class LDAP_Attribute (ASN1_Packet ):
848+ ASN1_codec = ASN1_Codecs .BER
849+ ASN1_root = LDAP_PartialAttribute .ASN1_root
850+
851+
852+ class LDAP_AddRequest (ASN1_Packet ):
853+ ASN1_codec = ASN1_Codecs .BER
854+ ASN1_root = ASN1F_SEQUENCE (
855+ LDAPDN ("entry" , "" ),
856+ ASN1F_SEQUENCE_OF (
857+ "attributes" ,
858+ LDAP_Attribute (),
859+ LDAP_Attribute ,
860+ ),
861+ implicit_tag = ASN1_Class_LDAP .AddRequest ,
862+ )
863+
864+
865+ class LDAP_AddResponse (ASN1_Packet ):
866+ ASN1_codec = ASN1_Codecs .BER
867+ ASN1_root = ASN1F_SEQUENCE (
868+ * LDAPResult ,
869+ implicit_tag = ASN1_Class_LDAP .AddResponse ,
870+ )
871+
872+
873+ # Delete Operation
874+ # https://datatracker.ietf.org/doc/html/rfc4511#section-4.8
875+
876+
877+ class LDAP_DelRequest (ASN1_Packet ):
878+ ASN1_codec = ASN1_Codecs .BER
879+ ASN1_root = LDAPDN (
880+ "entry" ,
881+ "" ,
882+ implicit_tag = ASN1_Class_LDAP .DelRequest ,
883+ )
884+
885+
886+ class LDAP_DelResponse (ASN1_Packet ):
887+ ASN1_codec = ASN1_Codecs .BER
888+ ASN1_root = ASN1F_SEQUENCE (
889+ * LDAPResult ,
890+ implicit_tag = ASN1_Class_LDAP .DelResponse ,
891+ )
892+
893+
894+ # Abandon Operation
895+ # https://datatracker.ietf.org/doc/html/rfc4511#section-4.11
896+
897+
898+ class LDAP_AbandonRequest (ASN1_Packet ):
899+ ASN1_codec = ASN1_Codecs .BER
900+ ASN1_root = ASN1F_SEQUENCE (
901+ ASN1F_INTEGER ("messageID" , 0 ),
902+ implicit_tag = ASN1_Class_LDAP .AbandonRequest ,
903+ )
904+
905+
814906# LDAP v3
815907
816908# RFC 4511 sect 4.12 - Extended Operation
@@ -926,6 +1018,12 @@ class LDAP(ASN1_Packet):
9261018 LDAP_SearchResponseResultDone ,
9271019 LDAP_AbandonRequest ,
9281020 LDAP_SearchResponseReference ,
1021+ LDAP_ModifyRequest ,
1022+ LDAP_ModifyResponse ,
1023+ LDAP_AddRequest ,
1024+ LDAP_AddResponse ,
1025+ LDAP_DelRequest ,
1026+ LDAP_DelResponse ,
9291027 LDAP_UnbindRequest ,
9301028 LDAP_ExtendedResponse ,
9311029 ),
@@ -966,8 +1064,8 @@ def tcp_reassemble(cls, data, *args, **kwargs):
9661064 pkt = cls (data )
9671065 # Packet can be a whole response yet still miss some content.
9681066 if (
969- LDAP_SearchResponseEntry in pkt and
970- LDAP_SearchResponseResultDone not in pkt
1067+ LDAP_SearchResponseEntry in pkt
1068+ and LDAP_SearchResponseResultDone not in pkt
9711069 ):
9721070 return None
9731071 return pkt
@@ -1242,9 +1340,9 @@ def make_reply(self, req):
12421340 / CLDAP (
12431341 protocolOp = LDAP_SearchResponseEntry (
12441342 attributes = [
1245- LDAP_SearchResponseEntryAttribute (
1343+ LDAP_PartialAttribute (
12461344 values = [
1247- LDAP_SearchResponseEntryAttributeValue (
1345+ LDAP_AttributeValue (
12481346 value = ASN1_STRING (
12491347 val = bytes (
12501348 NETLOGON_SAM_LOGON_RESPONSE_EX (
@@ -2146,6 +2244,34 @@ def _ssafe(x):
21462244 break
21472245 return entries
21482246
2247+ def modify (
2248+ self ,
2249+ object : str ,
2250+ changes : List [LDAP_ModifyRequestChange ],
2251+ controls : List [LDAP_Control ] = [],
2252+ ) -> None :
2253+ """
2254+ Perform a LDAP modify request.
2255+
2256+ :returns:
2257+ """
2258+ resp = self .sr1 (
2259+ LDAP_ModifyRequest (
2260+ object = object ,
2261+ changes = changes ,
2262+ ),
2263+ controls = controls ,
2264+ timeout = 3 ,
2265+ )
2266+ if (
2267+ LDAP_ModifyResponse not in resp .protocolOp
2268+ or resp .protocolOp .resultCode != 0
2269+ ):
2270+ raise LDAP_Exception (
2271+ "LDAP modify failed !" ,
2272+ resp = resp ,
2273+ )
2274+
21492275 def close (self ):
21502276 if self .verb :
21512277 print ("X Connection closed\n " )
0 commit comments