@@ -24,6 +24,11 @@ const (
24
24
// ControlTypeSubtreeDelete - https://datatracker.ietf.org/doc/html/draft-armijo-ldap-treedelete-02
25
25
ControlTypeSubtreeDelete = "1.2.840.113556.1.4.805"
26
26
27
+ // ControlTypeServerSideSorting - https://www.ietf.org/rfc/rfc2891.txt
28
+ ControlTypeServerSideSorting = "1.2.840.113556.1.4.473"
29
+ // ControlTypeServerSideSorting - https://www.ietf.org/rfc/rfc2891.txt
30
+ ControlTypeServerSideSortingResult = "1.2.840.113556.1.4.474"
31
+
27
32
// ControlTypeMicrosoftNotification - https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
28
33
ControlTypeMicrosoftNotification = "1.2.840.113556.1.4.528"
29
34
// ControlTypeMicrosoftShowDeleted - https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
@@ -53,18 +58,20 @@ const (
53
58
54
59
// ControlTypeMap maps controls to text descriptions
55
60
var ControlTypeMap = map [string ]string {
56
- ControlTypePaging : "Paging" ,
57
- ControlTypeBeheraPasswordPolicy : "Password Policy - Behera Draft" ,
58
- ControlTypeManageDsaIT : "Manage DSA IT" ,
59
- ControlTypeSubtreeDelete : "Subtree Delete Control" ,
60
- ControlTypeMicrosoftNotification : "Change Notification - Microsoft" ,
61
- ControlTypeMicrosoftShowDeleted : "Show Deleted Objects - Microsoft" ,
62
- ControlTypeMicrosoftServerLinkTTL : "Return TTL-DNs for link values with associated expiry times - Microsoft" ,
63
- ControlTypeDirSync : "DirSync" ,
64
- ControlTypeSyncRequest : "Sync Request" ,
65
- ControlTypeSyncState : "Sync State" ,
66
- ControlTypeSyncDone : "Sync Done" ,
67
- ControlTypeSyncInfo : "Sync Info" ,
61
+ ControlTypePaging : "Paging" ,
62
+ ControlTypeBeheraPasswordPolicy : "Password Policy - Behera Draft" ,
63
+ ControlTypeManageDsaIT : "Manage DSA IT" ,
64
+ ControlTypeSubtreeDelete : "Subtree Delete Control" ,
65
+ ControlTypeMicrosoftNotification : "Change Notification - Microsoft" ,
66
+ ControlTypeMicrosoftShowDeleted : "Show Deleted Objects - Microsoft" ,
67
+ ControlTypeMicrosoftServerLinkTTL : "Return TTL-DNs for link values with associated expiry times - Microsoft" ,
68
+ ControlTypeServerSideSorting : "Server Side Sorting Request - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)" ,
69
+ ControlTypeServerSideSortingResult : "Server Side Sorting Results - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)" ,
70
+ ControlTypeDirSync : "DirSync" ,
71
+ ControlTypeSyncRequest : "Sync Request" ,
72
+ ControlTypeSyncState : "Sync State" ,
73
+ ControlTypeSyncDone : "Sync Done" ,
74
+ ControlTypeSyncInfo : "Sync Info" ,
68
75
}
69
76
70
77
// Control defines an interface controls provide to encode and describe themselves
@@ -521,6 +528,10 @@ func DecodeControl(packet *ber.Packet) (Control, error) {
521
528
return NewControlMicrosoftServerLinkTTL (), nil
522
529
case ControlTypeSubtreeDelete :
523
530
return NewControlSubtreeDelete (), nil
531
+ case ControlTypeServerSideSorting :
532
+ return NewControlServerSideSorting (value )
533
+ case ControlTypeServerSideSortingResult :
534
+ return NewControlServerSideSortingResult (value )
524
535
case ControlTypeDirSync :
525
536
value .Description += " (DirSync)"
526
537
return NewResponseControlDirSync (value )
@@ -716,6 +727,193 @@ func (c *ControlDirSync) SetCookie(cookie []byte) {
716
727
c .Cookie = cookie
717
728
}
718
729
730
+ // ControlServerSideSorting
731
+
732
+ type SortKey struct {
733
+ Reverse bool
734
+ AttributeType string
735
+ MatchingRule string
736
+ }
737
+
738
+ type ControlServerSideSorting struct {
739
+ SortKeys []* SortKey
740
+ }
741
+
742
+ func (c * ControlServerSideSorting ) GetControlType () string {
743
+ return ControlTypeServerSideSorting
744
+ }
745
+
746
+ func NewControlServerSideSorting (value * ber.Packet ) (* ControlServerSideSorting , error ) {
747
+ sortKeys := []* SortKey {}
748
+
749
+ val := value .Children [1 ].Children
750
+
751
+ if len (val ) != 1 {
752
+ return nil , fmt .Errorf ("no sequence value in packet" )
753
+ }
754
+
755
+ sequences := val [0 ].Children
756
+
757
+ for i , sequence := range sequences {
758
+ sortKey := & SortKey {}
759
+
760
+ if len (sequence .Children ) < 2 {
761
+ return nil , fmt .Errorf ("attributeType or matchingRule is missing from sequence %d" , i )
762
+ }
763
+
764
+ sortKey .AttributeType = sequence .Children [0 ].Value .(string )
765
+ sortKey .MatchingRule = sequence .Children [1 ].Value .(string )
766
+
767
+ if len (sequence .Children ) == 3 {
768
+ sortKey .Reverse = sequence .Children [2 ].Value .(bool )
769
+ }
770
+
771
+ sortKeys = append (sortKeys , sortKey )
772
+ }
773
+
774
+ return & ControlServerSideSorting {SortKeys : sortKeys }, nil
775
+ }
776
+
777
+ func NewControlServerSideSortingWithSortKeys (sortKeys []* SortKey ) * ControlServerSideSorting {
778
+ return & ControlServerSideSorting {SortKeys : sortKeys }
779
+ }
780
+
781
+ func (c * ControlServerSideSorting ) Encode () * ber.Packet {
782
+ packet := ber .Encode (ber .ClassUniversal , ber .TypeConstructed , ber .TagSequence , nil , "Control" )
783
+ control := ber .NewString (ber .ClassUniversal , ber .TypePrimitive , ber .TagOctetString , c .GetControlType (), "Control Type" )
784
+
785
+ value := ber .Encode (ber .ClassUniversal , ber .TypePrimitive , ber .TagOctetString , nil , "Control Value" )
786
+ seqs := ber .Encode (ber .ClassUniversal , ber .TypeConstructed , ber .TagSequence , nil , "SortKeyList" )
787
+
788
+ for _ , f := range c .SortKeys {
789
+ seq := ber .Encode (ber .ClassUniversal , ber .TypeConstructed , ber .TagSequence , nil , "" )
790
+
791
+ seq .AppendChild (
792
+ ber .NewString (ber .ClassUniversal , ber .TypePrimitive , ber .TagOctetString , f .AttributeType , "attributeType" ),
793
+ )
794
+ seq .AppendChild (
795
+ ber .NewString (ber .ClassContext , ber .TypePrimitive , 0 , f .MatchingRule , "orderingRule" ),
796
+ )
797
+ if f .Reverse {
798
+ seq .AppendChild (
799
+ ber .NewBoolean (ber .ClassContext , ber .TypePrimitive , 1 , f .Reverse , "reverseOrder" ),
800
+ )
801
+ }
802
+
803
+ seqs .AppendChild (seq )
804
+ }
805
+
806
+ value .AppendChild (seqs )
807
+
808
+ packet .AppendChild (control )
809
+ packet .AppendChild (value )
810
+
811
+ return packet
812
+ }
813
+
814
+ func (c * ControlServerSideSorting ) String () string {
815
+ return fmt .Sprintf (
816
+ "Control Type: %s (%q) Criticality:%t %+v" ,
817
+ "Server Side Sorting" ,
818
+ c .GetControlType (),
819
+ false ,
820
+ c .SortKeys ,
821
+ )
822
+ }
823
+
824
+ // ControlServerSideSortingResponse
825
+
826
+ const (
827
+ ControlServerSideSortingCodeSuccess ControlServerSideSortingCode = 0
828
+ ControlServerSideSortingCodeOperationsError ControlServerSideSortingCode = 1
829
+ ControlServerSideSortingCodeTimeLimitExceeded ControlServerSideSortingCode = 2
830
+ ControlServerSideSortingCodeStrongAuthRequired ControlServerSideSortingCode = 8
831
+ ControlServerSideSortingCodeAdminLimitExceeded ControlServerSideSortingCode = 11
832
+ ControlServerSideSortingCodeNoSuchAttribute ControlServerSideSortingCode = 16
833
+ ControlServerSideSortingCodeInappropriateMatching ControlServerSideSortingCode = 18
834
+ ControlServerSideSortingCodeInsufficientAccessRights ControlServerSideSortingCode = 50
835
+ ControlServerSideSortingCodeBusy ControlServerSideSortingCode = 51
836
+ ControlServerSideSortingCodeUnwillingToPerform ControlServerSideSortingCode = 53
837
+ ControlServerSideSortingCodeOther ControlServerSideSortingCode = 80
838
+ )
839
+
840
+ var ControlServerSideSortingCodes = []ControlServerSideSortingCode {
841
+ ControlServerSideSortingCodeSuccess ,
842
+ ControlServerSideSortingCodeOperationsError ,
843
+ ControlServerSideSortingCodeTimeLimitExceeded ,
844
+ ControlServerSideSortingCodeStrongAuthRequired ,
845
+ ControlServerSideSortingCodeAdminLimitExceeded ,
846
+ ControlServerSideSortingCodeNoSuchAttribute ,
847
+ ControlServerSideSortingCodeInappropriateMatching ,
848
+ ControlServerSideSortingCodeInsufficientAccessRights ,
849
+ ControlServerSideSortingCodeBusy ,
850
+ ControlServerSideSortingCodeUnwillingToPerform ,
851
+ ControlServerSideSortingCodeOther ,
852
+ }
853
+
854
+ type ControlServerSideSortingCode int64
855
+
856
+ // Valid test the code contained in the control against the ControlServerSideSortingCodes slice and return an error if the code is unknown.
857
+ func (c ControlServerSideSortingCode ) Valid () error {
858
+ for _ , validRet := range ControlServerSideSortingCodes {
859
+ if c == validRet {
860
+ return nil
861
+ }
862
+ }
863
+ return fmt .Errorf ("unknown return code : %d" , c )
864
+ }
865
+
866
+ func NewControlServerSideSortingResult (pkt * ber.Packet ) (* ControlServerSideSortingResult , error ) {
867
+ control := & ControlServerSideSortingResult {}
868
+
869
+ if pkt == nil || len (pkt .Children ) == 0 {
870
+ return nil , fmt .Errorf ("bad packet" )
871
+ }
872
+
873
+ codeInt , err := ber .ParseInt64 (pkt .Children [0 ].Data .Bytes ())
874
+ if err != nil {
875
+ return nil , err
876
+ }
877
+
878
+ code := ControlServerSideSortingCode (codeInt )
879
+ if err := code .Valid (); err != nil {
880
+ return nil , err
881
+ }
882
+
883
+ return control , nil
884
+ }
885
+
886
+ type ControlServerSideSortingResult struct {
887
+ Criticality bool
888
+
889
+ Result ControlServerSideSortingCode
890
+
891
+ // Not populated for now. I can't get openldap to send me this value, so I think this is specific to other directory server
892
+ // AttributeType string
893
+ }
894
+
895
+ func (control * ControlServerSideSortingResult ) GetControlType () string {
896
+ return ControlTypeServerSideSortingResult
897
+ }
898
+
899
+ func (c * ControlServerSideSortingResult ) Encode () * ber.Packet {
900
+ packet := ber .Encode (ber .ClassUniversal , ber .TypeConstructed , ber .TagSequence , nil , "SortResult sequence" )
901
+ sortResult := ber .NewInteger (ber .ClassUniversal , ber .TypePrimitive , ber .TagEnumerated , int64 (c .Result ), "SortResult" )
902
+ packet .AppendChild (sortResult )
903
+
904
+ return packet
905
+ }
906
+
907
+ func (c * ControlServerSideSortingResult ) String () string {
908
+ return fmt .Sprintf (
909
+ "Control Type: %s (%q) Criticality:%t ResultCode:%+v" ,
910
+ "Server Side Sorting Result" ,
911
+ c .GetControlType (),
912
+ c .Criticality ,
913
+ c .Result ,
914
+ )
915
+ }
916
+
719
917
// Mode for ControlTypeSyncRequest
720
918
type ControlSyncRequestMode int64
721
919
@@ -752,9 +950,12 @@ func (c *ControlSyncRequest) GetControlType() string {
752
950
func (c * ControlSyncRequest ) Encode () * ber.Packet {
753
951
_mode := int64 (c .Mode )
754
952
mode := ber .NewInteger (ber .ClassUniversal , ber .TypePrimitive , ber .TagEnumerated , _mode , "Mode" )
755
- cookie := ber .Encode (ber .ClassUniversal , ber .TypePrimitive , ber .TagOctetString , nil , "Cookie" )
756
- cookie .Value = c .Cookie
757
- cookie .Data .Write (c .Cookie )
953
+ var cookie * ber.Packet
954
+ if len (c .Cookie ) > 0 {
955
+ cookie = ber .Encode (ber .ClassUniversal , ber .TypePrimitive , ber .TagOctetString , nil , "Cookie" )
956
+ cookie .Value = c .Cookie
957
+ cookie .Data .Write (c .Cookie )
958
+ }
758
959
reloadHint := ber .NewBoolean (ber .ClassUniversal , ber .TypePrimitive , ber .TagBoolean , c .ReloadHint , "Reload Hint" )
759
960
760
961
packet := ber .Encode (ber .ClassUniversal , ber .TypeConstructed , ber .TagSequence , nil , "Control" )
@@ -764,7 +965,9 @@ func (c *ControlSyncRequest) Encode() *ber.Packet {
764
965
val := ber .Encode (ber .ClassUniversal , ber .TypePrimitive , ber .TagOctetString , nil , "Control Value (Sync Request)" )
765
966
seq := ber .Encode (ber .ClassUniversal , ber .TypeConstructed , ber .TagSequence , nil , "Sync Request Value" )
766
967
seq .AppendChild (mode )
767
- seq .AppendChild (cookie )
968
+ if cookie != nil {
969
+ seq .AppendChild (cookie )
970
+ }
768
971
seq .AppendChild (reloadHint )
769
972
val .AppendChild (seq )
770
973
0 commit comments