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