ldap_client_proto/
controls.rs1use ldap_client_ber::tag::Tag;
4use ldap_client_ber::{BerReader, BerWriter};
5
6use crate::ProtoError;
7use crate::result_code::ResultCode;
8
9pub const PAGED_RESULTS_OID: &str = "1.2.840.113556.1.4.319";
10pub const MANAGE_DSA_IT_OID: &str = "2.16.840.1.113730.3.4.2";
11pub const SERVER_SORT_REQUEST_OID: &str = "1.2.840.113556.1.4.473";
12pub const SERVER_SORT_RESPONSE_OID: &str = "1.2.840.113556.1.4.474";
13pub const DOMAIN_SCOPE_OID: &str = "1.2.840.113556.1.4.1339";
14
15pub const SERVER_SORT_OID: &str = SERVER_SORT_REQUEST_OID;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Control {
20 pub oid: String,
21 pub critical: bool,
22 pub value: Option<Vec<u8>>,
23}
24
25#[derive(Debug, Clone)]
27pub struct PagedResultsControl {
28 pub size: i32,
29 pub cookie: Vec<u8>,
30}
31
32impl PagedResultsControl {
33 pub fn new(size: i32) -> Self {
34 Self {
35 size,
36 cookie: Vec::new(),
37 }
38 }
39
40 pub fn with_cookie(mut self, cookie: Vec<u8>) -> Self {
41 self.cookie = cookie;
42 self
43 }
44
45 pub fn to_control(&self) -> Control {
46 let mut w = BerWriter::new();
47 w.write_sequence(Tag::sequence(), |inner| {
48 inner.write_integer(self.size as i64);
49 inner.write_bytes(&self.cookie);
50 });
51 Control {
52 oid: PAGED_RESULTS_OID.to_string(),
53 critical: false,
54 value: Some(w.into_bytes()),
55 }
56 }
57
58 pub fn from_control(control: &Control) -> Result<Self, ProtoError> {
59 let value = control
60 .value
61 .as_deref()
62 .ok_or_else(|| ProtoError::Protocol("paged results control missing value".into()))?;
63 let mut r = BerReader::new(value);
64 r.read_sequence(Tag::sequence(), |inner| {
65 let size = inner.read_integer()? as i32;
66 let cookie = inner.read_octet_string()?.to_vec();
67 Ok(Self { size, cookie })
68 })
69 .map_err(Into::into)
70 }
71}
72
73#[derive(Debug, Clone)]
74pub struct ManageDsaItControl {
75 pub critical: bool,
76}
77
78impl ManageDsaItControl {
79 pub fn new(critical: bool) -> Self {
80 Self { critical }
81 }
82
83 pub fn to_control(&self) -> Control {
84 Control {
85 oid: MANAGE_DSA_IT_OID.to_string(),
86 critical: self.critical,
87 value: None,
88 }
89 }
90}
91
92#[derive(Debug, Clone)]
93pub struct DomainScopeControl {
94 pub critical: bool,
95}
96
97impl DomainScopeControl {
98 pub fn new(critical: bool) -> Self {
99 Self { critical }
100 }
101
102 pub fn to_control(&self) -> Control {
103 Control {
104 oid: DOMAIN_SCOPE_OID.to_string(),
105 critical: self.critical,
106 value: None,
107 }
108 }
109}
110
111#[derive(Debug, Clone)]
113pub struct SortKey {
114 pub attribute_type: String,
115 pub ordering_rule: Option<String>,
116 pub reverse_order: bool,
117}
118
119impl SortKey {
120 pub fn new(attribute_type: impl Into<String>) -> Self {
121 Self {
122 attribute_type: attribute_type.into(),
123 ordering_rule: None,
124 reverse_order: false,
125 }
126 }
127
128 pub fn reverse(mut self) -> Self {
129 self.reverse_order = true;
130 self
131 }
132
133 pub fn ordering_rule(mut self, rule: impl Into<String>) -> Self {
134 self.ordering_rule = Some(rule.into());
135 self
136 }
137}
138
139#[derive(Debug, Clone)]
141pub struct SortKeyList {
142 pub keys: Vec<SortKey>,
143}
144
145impl SortKeyList {
146 pub fn new(keys: Vec<SortKey>) -> Self {
147 Self { keys }
148 }
149
150 pub fn to_control(&self, critical: bool) -> Control {
151 let mut w = BerWriter::new();
152 w.write_sequence(Tag::sequence(), |seq| {
153 for key in &self.keys {
154 seq.write_sequence(Tag::sequence(), |inner| {
155 inner.write_bytes(key.attribute_type.as_bytes());
156 if let Some(rule) = &key.ordering_rule {
157 inner.write_octet_string(Tag::context(0), rule.as_bytes());
158 }
159 if key.reverse_order {
160 inner.write_octet_string(Tag::context(1), &[0xFF]);
161 }
162 });
163 }
164 });
165 Control {
166 oid: SERVER_SORT_REQUEST_OID.to_string(),
167 critical,
168 value: Some(w.into_bytes()),
169 }
170 }
171}
172
173#[derive(Debug, Clone)]
175pub struct SortResult {
176 pub result_code: ResultCode,
177 pub attribute_type: Option<String>,
178}
179
180impl SortResult {
181 pub fn from_control(control: &Control) -> Result<Self, ProtoError> {
182 let value = control
183 .value
184 .as_deref()
185 .ok_or_else(|| ProtoError::Protocol("sort response control missing value".into()))?;
186 let mut r = BerReader::new(value);
187 r.read_sequence(Tag::sequence(), |inner| {
188 let code = ResultCode::from_i64(inner.read_enumerated()?);
189 let attr = if !inner.is_empty() {
190 let tag = inner.peek_tag()?;
191 if tag.class == ldap_client_ber::Class::Context && tag.number == 0 {
192 Some(
193 String::from_utf8_lossy(inner.read_tagged_implicit_octet_string(0)?)
194 .into_owned(),
195 )
196 } else {
197 None
198 }
199 } else {
200 None
201 };
202 Ok(Self {
203 result_code: code,
204 attribute_type: attr,
205 })
206 })
207 .map_err(Into::into)
208 }
209}
210
211pub fn encode_controls(w: &mut BerWriter, controls: &[Control]) {
212 w.write_sequence(Tag::context_constructed(0), |outer| {
213 for ctrl in controls {
214 outer.write_sequence(Tag::sequence(), |inner| {
215 inner.write_bytes(ctrl.oid.as_bytes());
216 if ctrl.critical {
217 inner.write_boolean(true);
218 }
219 if let Some(val) = &ctrl.value {
220 inner.write_bytes(val);
221 }
222 });
223 }
224 });
225}
226
227pub fn decode_controls(r: &mut BerReader<'_>) -> Result<Vec<Control>, ldap_client_ber::BerError> {
228 let mut controls = Vec::new();
229 r.read_sequence_lax(Tag::context_constructed(0), |outer| {
230 while !outer.is_empty() {
231 outer.read_sequence(Tag::sequence(), |inner| {
232 let oid = String::from_utf8_lossy(inner.read_octet_string()?).into_owned();
233 let mut critical = false;
234 let mut value = None;
235
236 while !inner.is_empty() {
237 let tag = inner.peek_tag()?;
238 if tag == Tag::universal(ldap_client_ber::tag::BOOLEAN) {
239 critical = inner.read_boolean()?;
240 } else {
241 value = Some(inner.read_octet_string()?.to_vec());
242 }
243 }
244
245 controls.push(Control {
246 oid,
247 critical,
248 value,
249 });
250 Ok(())
251 })?;
252 }
253 Ok(())
254 })?;
255 Ok(controls)
256}