1use crate::error::Result;
4use crate::filter::*;
5use asn1_rs::{FromBer, ToStatic};
6use rusticata_macros::newtype_enum;
7use std::borrow::Cow;
8
9pub const MAX_FILTER_DEPTH: usize = 32;
11
12#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, ToStatic)]
13pub struct ProtocolOpTag(pub u32);
14
15newtype_enum! {
16impl display ProtocolOpTag {
17 BindRequest = 0,
18 BindResponse = 1,
19 UnbindRequest = 2,
20 SearchRequest = 3,
21 SearchResultEntry = 4,
22 SearchResultDone = 5,
23 ModifyRequest = 6,
24 ModifyResponse = 7,
25 AddRequest = 8,
26 AddResponse = 9,
27 DelRequest = 10,
28 DelResponse = 11,
29 ModDnRequest = 12,
30 ModDnResponse = 13,
31 CompareRequest = 14,
32 CompareResponse = 15,
33 AbandonRequest = 16,
34 SearchResultReference = 19,
35 ExtendedRequest = 23,
36 ExtendedResponse = 24,
37 IntermediateResponse = 25,
38}
39}
40
41#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, ToStatic)]
42pub struct ResultCode(pub u32);
43
44newtype_enum! {
45impl debug ResultCode {
46 Success = 0,
47 OperationsError = 1,
48 ProtocolError = 2,
49 TimeLimitExceeded = 3,
50 SizeLimitExceeded = 4,
51 CompareFalse = 5,
52 CompareTrue = 6,
53 AuthMethodNotSupported = 7,
54 StrongerAuthRequired = 8,
55 Referral = 10,
57 AdminLimitExceeded = 11,
58 UnavailableCriticalExtension = 12,
59 ConfidentialityRequired = 13,
60 SaslBindInProgress = 14,
61 NoSuchAttribute = 16,
62 UndefinedAttributeType = 17,
63 InappropriateMatching = 18,
64 ConstraintViolation = 19,
65 AttributeOrValueExists = 20,
66 InvalidAttributeSyntax = 21,
67 NoSuchObject = 32,
69 AliasProblem = 33,
70 InvalidDNSyntax = 34,
71 AliasDereferencingProblem = 36,
73 InappropriateAuthentication = 48,
75 InvalidCredentials = 49,
76 InsufficientAccessRights = 50,
77 Busy = 51,
78 Unavailable = 52,
79 UnwillingToPerform = 53,
80 LoopDetect = 54,
81 NamingViolation = 64,
83 ObjectClassViolation = 65,
84 NotAllowedOnNonLeaf = 66,
85 NotAllowedOnRDN = 67,
86 EntryAlreadyExists = 68,
87 ObjectClassModsProhibited = 69,
88 AffectsMultipleDSAs = 71,
90 Other = 80,
92}
93}
94
95#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, ToStatic)]
96pub struct MessageID(pub u32);
97
98#[derive(PartialEq, Eq, Clone, Copy, ToStatic)]
99pub struct SearchScope(pub u32);
100
101newtype_enum! {
102impl debug SearchScope {
103 BaseObject = 0,
104 SingleLevel = 1,
105 WholeSubtree = 2,
106}
107}
108
109#[derive(PartialEq, Eq, Clone, Copy, ToStatic)]
110pub struct DerefAliases(pub u32);
111
112newtype_enum! {
113impl debug DerefAliases {
114 NeverDerefAliases = 0,
115 DerefInSearching = 1,
116 DerefFindingBaseObj = 2,
117 DerefAlways = 3,
118}
119}
120
121#[derive(PartialEq, Eq, Clone, Copy, ToStatic)]
122pub struct Operation(pub u32);
123
124newtype_enum! {
125impl debug Operation {
126 Add = 0,
127 Delete = 1,
128 Replace = 2,
129}
130}
131
132#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
133pub struct LdapString<'a>(pub Cow<'a, str>);
134
135#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
136pub struct LdapDN<'a>(pub Cow<'a, str>);
137
138#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
139pub struct RelativeLdapDN<'a>(pub Cow<'a, str>);
140
141#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
142pub struct LdapOID<'a>(pub Cow<'a, str>);
143
144#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
145pub struct LdapResult<'a> {
146 pub result_code: ResultCode,
147 pub matched_dn: LdapDN<'a>,
148 pub diagnostic_message: LdapString<'a>,
149 }
151
152#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
153pub struct BindRequest<'a> {
154 pub version: u8,
155 pub name: LdapDN<'a>,
156 pub authentication: AuthenticationChoice<'a>,
157}
158
159#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
160pub struct SaslCredentials<'a> {
161 pub mechanism: LdapString<'a>,
162 pub credentials: Option<Cow<'a, [u8]>>,
163}
164
165#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
166pub enum AuthenticationChoice<'a> {
167 Simple(Cow<'a, [u8]>),
168 Sasl(SaslCredentials<'a>),
169}
170
171#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
172pub struct BindResponse<'a> {
173 pub result: LdapResult<'a>,
174 pub server_sasl_creds: Option<Cow<'a, [u8]>>,
175}
176
177#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
178pub struct SearchRequest<'a> {
179 pub base_object: LdapDN<'a>,
180 pub scope: SearchScope,
181 pub deref_aliases: DerefAliases,
182 pub size_limit: u32,
183 pub time_limit: u32,
184 pub types_only: bool,
185 pub filter: Filter<'a>,
186 pub attributes: Vec<LdapString<'a>>,
187}
188
189#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
190pub struct SearchResultEntry<'a> {
191 pub object_name: LdapDN<'a>,
192 pub attributes: Vec<PartialAttribute<'a>>,
193}
194
195#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
196pub struct ModifyRequest<'a> {
197 pub object: LdapDN<'a>,
198 pub changes: Vec<Change<'a>>,
199}
200
201#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
202pub struct ModifyResponse<'a> {
203 pub result: LdapResult<'a>,
204}
205
206#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
207pub struct Change<'a> {
208 pub operation: Operation,
209 pub modification: PartialAttribute<'a>,
210}
211
212#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
213pub struct AddRequest<'a> {
214 pub entry: LdapDN<'a>,
215 pub attributes: Vec<Attribute<'a>>,
216}
217
218#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
219pub struct ModDnRequest<'a> {
220 pub entry: LdapDN<'a>,
221 pub newrdn: RelativeLdapDN<'a>,
222 pub deleteoldrdn: bool,
223 pub newsuperior: Option<LdapDN<'a>>,
224}
225
226#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
227pub struct CompareRequest<'a> {
228 pub entry: LdapDN<'a>,
229 pub ava: AttributeValueAssertion<'a>,
230}
231
232#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
233pub struct ExtendedRequest<'a> {
234 pub request_name: LdapOID<'a>,
235 pub request_value: Option<Cow<'a, [u8]>>,
236}
237
238#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
239pub struct ExtendedResponse<'a> {
240 pub result: LdapResult<'a>,
241 pub response_name: Option<LdapOID<'a>>,
242 pub response_value: Option<Cow<'a, [u8]>>,
243}
244
245#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
246pub struct IntermediateResponse<'a> {
247 pub response_name: Option<LdapOID<'a>>,
248 pub response_value: Option<Cow<'a, [u8]>>,
249}
250
251#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
252pub enum ProtocolOp<'a> {
253 BindRequest(BindRequest<'a>),
254 BindResponse(BindResponse<'a>),
255 UnbindRequest,
256 SearchRequest(SearchRequest<'a>),
257 SearchResultEntry(SearchResultEntry<'a>),
258 SearchResultDone(LdapResult<'a>),
259 SearchResultReference(Vec<LdapString<'a>>),
260 ModifyRequest(ModifyRequest<'a>),
261 ModifyResponse(ModifyResponse<'a>),
262 AddRequest(AddRequest<'a>),
263 AddResponse(LdapResult<'a>),
264 DelRequest(LdapDN<'a>),
265 DelResponse(LdapResult<'a>),
266 ModDnRequest(ModDnRequest<'a>),
267 ModDnResponse(LdapResult<'a>),
268 CompareRequest(CompareRequest<'a>),
269 CompareResponse(LdapResult<'a>),
270 AbandonRequest(MessageID),
272 ExtendedRequest(ExtendedRequest<'a>),
273 ExtendedResponse(ExtendedResponse<'a>),
274 IntermediateResponse(IntermediateResponse<'a>),
275}
276
277impl ProtocolOp<'_> {
278 pub fn tag(&self) -> ProtocolOpTag {
280 let op = match self {
281 ProtocolOp::BindRequest(_) => 0,
282 ProtocolOp::BindResponse(_) => 1,
283 ProtocolOp::UnbindRequest => 2,
284 ProtocolOp::SearchRequest(_) => 3,
285 ProtocolOp::SearchResultEntry(_) => 4,
286 ProtocolOp::SearchResultDone(_) => 5,
287 ProtocolOp::ModifyRequest(_) => 6,
288 ProtocolOp::ModifyResponse(_) => 7,
289 ProtocolOp::AddRequest(_) => 8,
290 ProtocolOp::AddResponse(_) => 9,
291 ProtocolOp::DelRequest(_) => 10,
292 ProtocolOp::DelResponse(_) => 11,
293 ProtocolOp::ModDnRequest(_) => 12,
294 ProtocolOp::ModDnResponse(_) => 13,
295 ProtocolOp::CompareRequest(_) => 14,
296 ProtocolOp::CompareResponse(_) => 15,
297 ProtocolOp::AbandonRequest(_) => 16,
298 ProtocolOp::SearchResultReference(_) => 19,
299 ProtocolOp::ExtendedRequest(_) => 23,
300 ProtocolOp::ExtendedResponse(_) => 24,
301 ProtocolOp::IntermediateResponse(_) => 25,
302 };
303 ProtocolOpTag(op)
304 }
305
306 pub fn result(&self) -> Option<&LdapResult<'_>> {
308 match self {
309 ProtocolOp::BindResponse(r) => Some(&r.result),
310 ProtocolOp::ModifyResponse(r) => Some(&r.result),
311 ProtocolOp::ExtendedResponse(r) => Some(&r.result),
312 ProtocolOp::SearchResultDone(ref r)
313 | ProtocolOp::AddResponse(ref r)
314 | ProtocolOp::DelResponse(ref r)
315 | ProtocolOp::ModDnResponse(ref r)
316 | ProtocolOp::CompareResponse(ref r) => Some(r),
317 _ => None,
318 }
319 }
320}
321
322#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
323pub struct Control<'a> {
324 pub control_type: LdapOID<'a>,
325 pub criticality: bool,
326 pub control_value: Option<Cow<'a, [u8]>>,
327}
328
329#[derive(Clone, Debug, Eq, PartialEq, ToStatic)]
385pub struct LdapMessage<'a> {
386 pub message_id: MessageID,
392 pub protocol_op: ProtocolOp<'a>,
394 pub controls: Option<Vec<Control<'a>>>,
400}
401
402impl<'a> LdapMessage<'a> {
403 #[deprecated(
405 since = "0.3.0",
406 note = "Parsing functions are deprecated. Users should instead use the FromBer trait"
407 )]
408 #[inline]
409 pub fn parse(i: &'a [u8]) -> Result<'a, LdapMessage<'a>> {
410 Self::from_ber(i)
411 }
412}
413
414#[cfg(test)]
415mod tests {
416 use super::*;
417
418 struct LDAPTransaction {
419 s: LdapString<'static>,
420 }
421
422 #[test]
423 fn test_transaction_lifetime() {
424 let s = "test";
425 let ldap_string = LdapString(s.into());
426 assert!(matches!(ldap_string.0, Cow::Borrowed(_)));
427
428 let ldap_string_owned = ldap_string.to_static();
429 assert!(matches!(ldap_string_owned.0, Cow::Owned(_)));
430
431 let tx = LDAPTransaction {
432 s: ldap_string_owned,
433 };
434 assert!(matches!(tx.s.0, Cow::Owned(_)));
435 }
436}