Coverage Report

Created: 2025-07-12 07:37

/src/PcapPlusPlus/Packet++/src/LdapLayer.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "LdapLayer.h"
2
#include "GeneralUtils.h"
3
#include <unordered_map>
4
5
namespace pcpp
6
{
7
8
  // region LdapOperationType
9
10
  // clang-format off
11
  static const std::unordered_map<LdapOperationType::Value, std::string, EnumClassHash<LdapOperationType::Value>> LdapOperationTypeToString{
12
    { LdapOperationType::BindRequest,           "BindRequest"           },
13
    { LdapOperationType::BindResponse,          "BindResponse"          },
14
    { LdapOperationType::UnbindRequest,         "UnbindRequest"         },
15
    { LdapOperationType::SearchRequest,         "SearchRequest"         },
16
    { LdapOperationType::SearchResultEntry,     "SearchResultEntry"     },
17
    { LdapOperationType::SearchResultDone,      "SearchResultDone"      },
18
    { LdapOperationType::ModifyRequest,         "ModifyRequest"         },
19
    { LdapOperationType::ModifyResponse,        "ModifyResponse"        },
20
    { LdapOperationType::AddRequest,            "AddRequest"            },
21
    { LdapOperationType::AddResponse,           "AddResponse"           },
22
    { LdapOperationType::DeleteRequest,         "DeleteRequest"         },
23
    { LdapOperationType::DeleteResponse,        "DeleteResponse"        },
24
    { LdapOperationType::ModifyDNRequest,       "ModifyDNRequest"       },
25
    { LdapOperationType::ModifyDNResponse,      "ModifyDNResponse"      },
26
    { LdapOperationType::CompareRequest,        "CompareRequest"        },
27
    { LdapOperationType::CompareResponse,       "CompareResponse"       },
28
    { LdapOperationType::AbandonRequest,        "AbandonRequest"        },
29
    { LdapOperationType::SearchResultReference, "SearchResultReference" },
30
    { LdapOperationType::ExtendedRequest,       "ExtendedRequest"       },
31
    { LdapOperationType::ExtendedResponse,      "ExtendedResponse"      },
32
    { LdapOperationType::IntermediateResponse,  "IntermediateResponse"  },
33
    { LdapOperationType::Unknown,               "Unknown"               }
34
  };
35
  // clang-format on
36
37
  static const std::unordered_map<uint8_t, LdapOperationType> UintToLdapOperationType{
38
    { static_cast<uint8_t>(LdapOperationType::BindRequest),           LdapOperationType::BindRequest           },
39
    { static_cast<uint8_t>(LdapOperationType::BindResponse),          LdapOperationType::BindResponse          },
40
    { static_cast<uint8_t>(LdapOperationType::UnbindRequest),         LdapOperationType::UnbindRequest         },
41
    { static_cast<uint8_t>(LdapOperationType::SearchRequest),         LdapOperationType::SearchRequest         },
42
    { static_cast<uint8_t>(LdapOperationType::SearchResultEntry),     LdapOperationType::SearchResultEntry     },
43
    { static_cast<uint8_t>(LdapOperationType::SearchResultDone),      LdapOperationType::SearchResultDone      },
44
    { static_cast<uint8_t>(LdapOperationType::ModifyResponse),        LdapOperationType::ModifyResponse        },
45
    { static_cast<uint8_t>(LdapOperationType::AddRequest),            LdapOperationType::AddRequest            },
46
    { static_cast<uint8_t>(LdapOperationType::AddResponse),           LdapOperationType::AddResponse           },
47
    { static_cast<uint8_t>(LdapOperationType::DeleteRequest),         LdapOperationType::DeleteRequest         },
48
    { static_cast<uint8_t>(LdapOperationType::DeleteResponse),        LdapOperationType::DeleteResponse        },
49
    { static_cast<uint8_t>(LdapOperationType::ModifyDNRequest),       LdapOperationType::ModifyDNRequest       },
50
    { static_cast<uint8_t>(LdapOperationType::ModifyDNResponse),      LdapOperationType::ModifyDNResponse      },
51
    { static_cast<uint8_t>(LdapOperationType::CompareRequest),        LdapOperationType::CompareRequest        },
52
    { static_cast<uint8_t>(LdapOperationType::CompareResponse),       LdapOperationType::CompareResponse       },
53
    { static_cast<uint8_t>(LdapOperationType::AbandonRequest),        LdapOperationType::AbandonRequest        },
54
    { static_cast<uint8_t>(LdapOperationType::SearchResultReference), LdapOperationType::SearchResultReference },
55
    { static_cast<uint8_t>(LdapOperationType::ExtendedRequest),       LdapOperationType::ExtendedRequest       },
56
    { static_cast<uint8_t>(LdapOperationType::ExtendedResponse),      LdapOperationType::ExtendedResponse      },
57
    { static_cast<uint8_t>(LdapOperationType::IntermediateResponse),  LdapOperationType::IntermediateResponse  }
58
  };
59
60
  std::string LdapOperationType::toString() const
61
6.92k
  {
62
6.92k
    return LdapOperationTypeToString.at(m_Value);
63
6.92k
  }
64
65
  LdapOperationType LdapOperationType::fromUintValue(uint8_t value)
66
27.0k
  {
67
27.0k
    auto result = UintToLdapOperationType.find(value);
68
27.0k
    if (result != UintToLdapOperationType.end())
69
26.6k
    {
70
26.6k
      return result->second;
71
26.6k
    }
72
73
426
    return LdapOperationType::Unknown;
74
27.0k
  }
75
76
  // endregion
77
78
  // region LdapResultCode
79
80
  // clang-format off
81
  static const std::unordered_map<LdapResultCode::Value, std::string, EnumClassHash<LdapResultCode::Value>> LdapResultCodeToString{
82
    { LdapResultCode::Success,                      "Success"                      },
83
    { LdapResultCode::OperationsError,              "OperationsError"              },
84
    { LdapResultCode::ProtocolError,                "ProtocolError"                },
85
    { LdapResultCode::TimeLimitExceeded,            "TimeLimitExceeded"            },
86
    { LdapResultCode::SizeLimitExceeded,            "SizeLimitExceeded"            },
87
    { LdapResultCode::CompareFalse,                 "CompareFalse"                 },
88
    { LdapResultCode::CompareTrue,                  "CompareTrue"                  },
89
    { LdapResultCode::AuthMethodNotSupported,       "AuthMethodNotSupported"       },
90
    { LdapResultCode::StrongerAuthRequired,         "StrongerAuthRequired"         },
91
    { LdapResultCode::Referral,                     "Referral"                     },
92
    { LdapResultCode::AdminLimitExceeded,           "AdminLimitExceeded"           },
93
    { LdapResultCode::UnavailableCriticalExtension, "UnavailableCriticalExtension" },
94
    { LdapResultCode::ConfidentialityRequired,      "ConfidentialityRequired"      },
95
    { LdapResultCode::SaslBindInProgress,           "SaslBindInProgress"           },
96
    { LdapResultCode::NoSuchAttribute,              "NoSuchAttribute"              },
97
    { LdapResultCode::UndefinedAttributeType,       "UndefinedAttributeType"       },
98
    { LdapResultCode::InappropriateMatching,        "InappropriateMatching"        },
99
    { LdapResultCode::ConstraintViolation,          "ConstraintViolation"          },
100
    { LdapResultCode::AttributeOrValueExists,       "AttributeOrValueExists"       },
101
    { LdapResultCode::InvalidAttributeSyntax,       "InvalidAttributeSyntax"       },
102
    { LdapResultCode::NoSuchObject,                 "NoSuchObject"                 },
103
    { LdapResultCode::AliasProblem,                 "AliasProblem"                 },
104
    { LdapResultCode::InvalidDNSyntax,              "InvalidDNSyntax"              },
105
    { LdapResultCode::AliasDereferencingProblem,    "AliasDereferencingProblem"    },
106
    { LdapResultCode::InappropriateAuthentication,  "InappropriateAuthentication"  },
107
    { LdapResultCode::InvalidCredentials,           "InvalidCredentials"           },
108
    { LdapResultCode::InsufficientAccessRights,     "InsufficientAccessRights"     },
109
    { LdapResultCode::Busy,                         "Busy"                         },
110
    { LdapResultCode::Unavailable,                  "Unavailable"                  },
111
    { LdapResultCode::UnwillingToPerform,           "UnwillingToPerform"           },
112
    { LdapResultCode::LoopDetect,                   "LoopDetect"                   },
113
    { LdapResultCode::NamingViolation,              "NamingViolation"              },
114
    { LdapResultCode::ObjectClassViolation,         "ObjectClassViolation"         },
115
    { LdapResultCode::NotAllowedOnNonLeaf,          "NotAllowedOnNonLeaf"          },
116
    { LdapResultCode::NotAllowedOnRDN,              "NotAllowedOnRDN"              },
117
    { LdapResultCode::EntryAlreadyExists,           "EntryAlreadyExists"           },
118
    { LdapResultCode::ObjectClassModsProhibited,    "ObjectClassModsProhibited"    },
119
    { LdapResultCode::AffectsMultipleDSAs,          "AffectsMultipleDSAs"          },
120
    { LdapResultCode::Other,                        "Other"                        }
121
    };
122
  // clang-format on
123
124
  // clang-format off
125
  static const std::unordered_map<uint8_t, LdapResultCode> UintToLdapResultCode{
126
    { static_cast<uint8_t>(LdapResultCode::Success),                   LdapResultCode::Success                   },
127
    { static_cast<uint8_t>(LdapResultCode::OperationsError),           LdapResultCode::OperationsError           },
128
    { static_cast<uint8_t>(LdapResultCode::ProtocolError),             LdapResultCode::ProtocolError             },
129
    { static_cast<uint8_t>(LdapResultCode::TimeLimitExceeded),         LdapResultCode::TimeLimitExceeded         },
130
    { static_cast<uint8_t>(LdapResultCode::SizeLimitExceeded),         LdapResultCode::SizeLimitExceeded         },
131
    { static_cast<uint8_t>(LdapResultCode::CompareFalse),              LdapResultCode::CompareFalse              },
132
    { static_cast<uint8_t>(LdapResultCode::CompareTrue),               LdapResultCode::CompareTrue               },
133
    { static_cast<uint8_t>(LdapResultCode::AuthMethodNotSupported),    LdapResultCode::AuthMethodNotSupported    },
134
    { static_cast<uint8_t>(LdapResultCode::StrongerAuthRequired),      LdapResultCode::StrongerAuthRequired      },
135
    { static_cast<uint8_t>(LdapResultCode::Referral),                  LdapResultCode::Referral                  },
136
    { static_cast<uint8_t>(LdapResultCode::AdminLimitExceeded),        LdapResultCode::AdminLimitExceeded        },
137
    { static_cast<uint8_t>(LdapResultCode::UnavailableCriticalExtension), LdapResultCode::UnavailableCriticalExtension },
138
    { static_cast<uint8_t>(LdapResultCode::ConfidentialityRequired),   LdapResultCode::ConfidentialityRequired   },
139
    { static_cast<uint8_t>(LdapResultCode::SaslBindInProgress),        LdapResultCode::SaslBindInProgress        },
140
    { static_cast<uint8_t>(LdapResultCode::NoSuchAttribute),           LdapResultCode::NoSuchAttribute           },
141
    { static_cast<uint8_t>(LdapResultCode::UndefinedAttributeType),    LdapResultCode::UndefinedAttributeType    },
142
    { static_cast<uint8_t>(LdapResultCode::InappropriateMatching),     LdapResultCode::InappropriateMatching     },
143
    { static_cast<uint8_t>(LdapResultCode::ConstraintViolation),       LdapResultCode::ConstraintViolation       },
144
    { static_cast<uint8_t>(LdapResultCode::AttributeOrValueExists),    LdapResultCode::AttributeOrValueExists    },
145
    { static_cast<uint8_t>(LdapResultCode::InvalidAttributeSyntax),    LdapResultCode::InvalidAttributeSyntax    },
146
    { static_cast<uint8_t>(LdapResultCode::NoSuchObject),              LdapResultCode::NoSuchObject              },
147
    { static_cast<uint8_t>(LdapResultCode::AliasProblem),              LdapResultCode::AliasProblem              },
148
    { static_cast<uint8_t>(LdapResultCode::InvalidDNSyntax),           LdapResultCode::InvalidDNSyntax           },
149
    { static_cast<uint8_t>(LdapResultCode::AliasDereferencingProblem), LdapResultCode::AliasDereferencingProblem },
150
    { static_cast<uint8_t>(LdapResultCode::InappropriateAuthentication),  LdapResultCode::InappropriateAuthentication },
151
    { static_cast<uint8_t>(LdapResultCode::InvalidCredentials),        LdapResultCode::InvalidCredentials        },
152
    { static_cast<uint8_t>(LdapResultCode::InsufficientAccessRights),  LdapResultCode::InsufficientAccessRights  },
153
    { static_cast<uint8_t>(LdapResultCode::Busy),                      LdapResultCode::Busy                      },
154
    { static_cast<uint8_t>(LdapResultCode::Unavailable),               LdapResultCode::Unavailable               },
155
    { static_cast<uint8_t>(LdapResultCode::UnwillingToPerform),        LdapResultCode::UnwillingToPerform        },
156
    { static_cast<uint8_t>(LdapResultCode::LoopDetect),                LdapResultCode::LoopDetect                },
157
    { static_cast<uint8_t>(LdapResultCode::NamingViolation),           LdapResultCode::NamingViolation           },
158
    { static_cast<uint8_t>(LdapResultCode::ObjectClassViolation),      LdapResultCode::ObjectClassViolation      },
159
    { static_cast<uint8_t>(LdapResultCode::NotAllowedOnNonLeaf),       LdapResultCode::NotAllowedOnNonLeaf       },
160
    { static_cast<uint8_t>(LdapResultCode::NotAllowedOnRDN),           LdapResultCode::NotAllowedOnRDN           },
161
    { static_cast<uint8_t>(LdapResultCode::EntryAlreadyExists),        LdapResultCode::EntryAlreadyExists        },
162
    { static_cast<uint8_t>(LdapResultCode::ObjectClassModsProhibited), LdapResultCode::ObjectClassModsProhibited },
163
    { static_cast<uint8_t>(LdapResultCode::AffectsMultipleDSAs),       LdapResultCode::AffectsMultipleDSAs       },
164
    { static_cast<uint8_t>(LdapResultCode::Other),                     LdapResultCode::Other                     }
165
  };
166
  // clang-format on
167
168
  std::string LdapResultCode::toString() const
169
2.31k
  {
170
2.31k
    return LdapResultCodeToString.at(m_Value);
171
2.31k
  }
172
173
  LdapResultCode LdapResultCode::fromUintValue(uint8_t value)
174
2.31k
  {
175
2.31k
    auto result = UintToLdapResultCode.find(value);
176
2.31k
    if (result != UintToLdapResultCode.end())
177
2.31k
    {
178
2.31k
      return result->second;
179
2.31k
    }
180
181
0
    return LdapResultCode::Unknown;
182
2.31k
  }
183
184
  // endregion
185
186
  // region LdapLayer
187
188
  LdapLayer::LdapLayer(uint16_t messageId, LdapOperationType operationType,
189
                       const std::vector<Asn1Record*>& messageRecords, const std::vector<LdapControl>& controls)
190
0
  {
191
0
    init(messageId, operationType, messageRecords, controls);
192
0
  }
193
194
  LdapLayer::LdapLayer(std::unique_ptr<Asn1Record> asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer,
195
                       Packet* packet)
196
20.3k
      : Layer(data, dataLen, prevLayer, packet, LDAP)
197
20.3k
  {
198
20.3k
    m_Asn1Record = std::move(asn1Record);
199
20.3k
  }
200
201
  void LdapLayer::init(uint16_t messageId, LdapOperationType operationType,
202
                       const std::vector<Asn1Record*>& messageRecords, const std::vector<LdapControl>& controls)
203
0
  {
204
0
    Asn1IntegerRecord messageIdRecord(messageId);
205
0
    std::unique_ptr<Asn1Record> messageRootRecord;
206
0
    if (!messageRecords.empty())
207
0
    {
208
0
      messageRootRecord =
209
0
          std::make_unique<Asn1ConstructedRecord>(Asn1TagClass::Application, operationType, messageRecords);
210
0
    }
211
0
    else
212
0
    {
213
0
      messageRootRecord =
214
0
          std::make_unique<Asn1GenericRecord>(Asn1TagClass::Application, false, operationType, "");
215
0
    }
216
217
0
    std::vector<Asn1Record*> rootSubRecords = { &messageIdRecord, messageRootRecord.get() };
218
219
0
    std::unique_ptr<Asn1ConstructedRecord> controlsRecord;
220
0
    if (!controls.empty())
221
0
    {
222
0
      PointerVector<Asn1Record> controlsSubRecords;
223
0
      for (const auto& control : controls)
224
0
      {
225
0
        Asn1OctetStringRecord controlTypeRecord(control.controlType);
226
0
        if (control.controlValue.empty())
227
0
        {
228
0
          controlsSubRecords.pushBack(new Asn1SequenceRecord({ &controlTypeRecord }));
229
0
        }
230
0
        else
231
0
        {
232
0
          auto controlValueSize = static_cast<size_t>(control.controlValue.size() / 2);
233
0
          std::unique_ptr<uint8_t[]> controlValue = std::make_unique<uint8_t[]>(controlValueSize);
234
0
          controlValueSize = hexStringToByteArray(control.controlValue, controlValue.get(), controlValueSize);
235
0
          Asn1OctetStringRecord controlValueRecord(controlValue.get(), controlValueSize);
236
0
          controlsSubRecords.pushBack(new Asn1SequenceRecord({ &controlTypeRecord, &controlValueRecord }));
237
0
        }
238
0
      }
239
0
      controlsRecord =
240
0
          std::make_unique<Asn1ConstructedRecord>(Asn1TagClass::ContextSpecific, 0, controlsSubRecords);
241
0
      rootSubRecords.push_back(controlsRecord.get());
242
0
    }
243
244
0
    Asn1SequenceRecord rootRecord(rootSubRecords);
245
246
0
    auto encodedData = rootRecord.encode();
247
0
    m_DataLen = encodedData.size();
248
0
    m_Data = new uint8_t[m_DataLen];
249
0
    std::copy(encodedData.begin(), encodedData.end(), m_Data);
250
0
    m_Protocol = LDAP;
251
0
    m_Asn1Record = Asn1Record::decode(m_Data, m_DataLen, true);
252
0
  }
253
254
  std::string LdapLayer::toString() const
255
6.92k
  {
256
6.92k
    auto extendedInfo = getExtendedInfoString();
257
6.92k
    return "LDAP Layer, " + getLdapOperationType().toString() + (extendedInfo.empty() ? "" : ", " + extendedInfo);
258
6.92k
  }
259
260
  LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
261
21.7k
  {
262
21.7k
    try
263
21.7k
    {
264
21.7k
      auto asn1Record = Asn1Record::decode(data, dataLen, true);
265
21.7k
      auto operationType = LdapOperationType::fromUintValue(
266
21.7k
          asn1Record->castAs<Asn1SequenceRecord>()->getSubRecords().at(operationTypeIndex)->getTagType());
267
21.7k
      switch (operationType)
268
21.7k
      {
269
2.27k
      case LdapOperationType::BindRequest:
270
2.27k
        return new LdapBindRequestLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
271
1.18k
      case LdapOperationType::BindResponse:
272
1.18k
        return new LdapBindResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
273
1.32k
      case LdapOperationType::UnbindRequest:
274
1.32k
        return new LdapUnbindRequestLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
275
1.60k
      case LdapOperationType::SearchRequest:
276
1.60k
        return new LdapSearchRequestLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
277
493
      case LdapOperationType::SearchResultEntry:
278
493
        return new LdapSearchResultEntryLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
279
2.33k
      case LdapOperationType::SearchResultDone:
280
2.33k
        return new LdapSearchResultDoneLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
281
830
      case LdapOperationType::ModifyResponse:
282
830
        return new LdapModifyResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
283
155
      case LdapOperationType::AddResponse:
284
155
        return new LdapAddResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
285
335
      case LdapOperationType::DeleteResponse:
286
335
        return new LdapDeleteResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
287
715
      case LdapOperationType::ModifyDNResponse:
288
715
        return new LdapModifyDNResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
289
945
      case LdapOperationType::CompareResponse:
290
945
        return new LdapCompareResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
291
310
      case LdapOperationType::Unknown:
292
310
        return nullptr;
293
8.19k
      default:
294
8.19k
        return new LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet);
295
21.7k
      }
296
21.7k
    }
297
21.7k
    catch (...)
298
21.7k
    {
299
1.04k
      return nullptr;
300
1.04k
    }
301
21.7k
  }
302
303
  Asn1SequenceRecord* LdapLayer::getRootAsn1Record() const
304
11.8k
  {
305
11.8k
    return m_Asn1Record->castAs<Asn1SequenceRecord>();
306
11.8k
  }
307
308
  Asn1ConstructedRecord* LdapLayer::getLdapOperationAsn1Record() const
309
11.8k
  {
310
11.8k
    return getRootAsn1Record()->getSubRecords().at(operationTypeIndex)->castAs<Asn1ConstructedRecord>();
311
11.8k
  }
312
313
  uint16_t LdapLayer::getMessageID() const
314
0
  {
315
0
    return getRootAsn1Record()
316
0
        ->getSubRecords()
317
0
        .at(messageIdIndex)
318
0
        ->castAs<Asn1IntegerRecord>()
319
0
        ->getIntValue<uint16_t>();
320
0
  }
321
322
  std::vector<LdapControl> LdapLayer::getControls() const
323
0
  {
324
0
    std::vector<LdapControl> controls;
325
0
    if (getRootAsn1Record()->getSubRecords().size() <= controlsIndex)
326
0
    {
327
0
      return controls;
328
0
    }
329
330
0
    auto controlsRecord = getRootAsn1Record()->getSubRecords().at(controlsIndex)->castAs<Asn1ConstructedRecord>();
331
0
    for (auto controlRecord : controlsRecord->getSubRecords())
332
0
    {
333
0
      auto controlSequence = controlRecord->castAs<Asn1SequenceRecord>();
334
0
      auto controlType =
335
0
          controlSequence->getSubRecords().at(controlTypeIndex)->castAs<Asn1OctetStringRecord>()->getValue();
336
0
      std::string controlValue;
337
0
      if (controlSequence->getSubRecords().size() > controlValueIndex)
338
0
      {
339
0
        controlValue =
340
0
            controlSequence->getSubRecords().at(controlValueIndex)->castAs<Asn1OctetStringRecord>()->getValue();
341
0
      }
342
0
      controls.push_back({ controlType, controlValue });
343
0
    }
344
345
0
    return controls;
346
0
  }
347
348
  LdapOperationType LdapLayer::getLdapOperationType() const
349
6.39k
  {
350
6.39k
    uint8_t tagType;
351
6.39k
    try
352
6.39k
    {
353
6.39k
      tagType = getLdapOperationAsn1Record()->getTagType();
354
6.39k
    }
355
6.39k
    catch (...)
356
6.39k
    {
357
116
      tagType = LdapOperationType::Unknown;
358
116
    }
359
360
6.39k
    return LdapOperationType::fromUintValue(tagType);
361
6.39k
  }
362
363
  void LdapLayer::parseNextLayer()
364
20.3k
  {
365
20.3k
    size_t headerLen = getHeaderLen();
366
20.3k
    if (m_DataLen <= headerLen || headerLen == 0)
367
13.5k
      return;
368
369
6.82k
    uint8_t* payload = m_Data + headerLen;
370
6.82k
    size_t payloadLen = m_DataLen - headerLen;
371
372
6.82k
    m_NextLayer = LdapLayer::parseLdapMessage(payload, payloadLen, this, m_Packet);
373
6.82k
  }
374
  // endregion
375
376
  // region LdapResponseLayer
377
378
  LdapResponseLayer::LdapResponseLayer(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode,
379
                                       const std::string& matchedDN, const std::string& diagnosticMessage,
380
                                       const std::vector<std::string>& referral,
381
                                       const std::vector<LdapControl>& controls)
382
0
  {
383
0
    LdapResponseLayer::init(messageId, operationType, resultCode, matchedDN, diagnosticMessage, referral, {},
384
0
                            controls);
385
0
  }
386
387
  void LdapResponseLayer::init(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode,
388
                               const std::string& matchedDN, const std::string& diagnosticMessage,
389
                               const std::vector<std::string>& referral,
390
                               const std::vector<Asn1Record*>& additionalRecords,
391
                               const std::vector<LdapControl>& controls)
392
0
  {
393
0
    Asn1EnumeratedRecord resultCodeRecord(resultCode);
394
0
    Asn1OctetStringRecord matchedDNRecord(matchedDN);
395
0
    Asn1OctetStringRecord diagnosticMessageRecord(diagnosticMessage);
396
397
0
    std::vector<Asn1Record*> messageRecords = { &resultCodeRecord, &matchedDNRecord, &diagnosticMessageRecord };
398
399
0
    std::unique_ptr<Asn1ConstructedRecord> referralRecord;
400
0
    if (!referral.empty())
401
0
    {
402
0
      PointerVector<Asn1Record> referralSubRecords;
403
0
      for (const auto& uri : referral)
404
0
      {
405
0
        referralSubRecords.pushBack(new Asn1OctetStringRecord(uri));
406
0
      }
407
0
      referralRecord = std::make_unique<Asn1ConstructedRecord>(Asn1TagClass::ContextSpecific, referralTagType,
408
0
                                                               referralSubRecords);
409
0
      messageRecords.push_back(referralRecord.get());
410
0
    }
411
412
0
    if (!additionalRecords.empty())
413
0
    {
414
0
      for (auto additionalRecord : additionalRecords)
415
0
      {
416
0
        messageRecords.push_back(additionalRecord);
417
0
      }
418
0
    }
419
420
0
    LdapLayer::init(messageId, operationType, messageRecords, controls);
421
0
  }
422
423
  LdapResultCode LdapResponseLayer::getResultCode() const
424
2.31k
  {
425
2.31k
    return LdapResultCode::fromUintValue(getLdapOperationAsn1Record()
426
2.31k
                                             ->getSubRecords()
427
2.31k
                                             .at(resultCodeIndex)
428
2.31k
                                             ->castAs<Asn1EnumeratedRecord>()
429
2.31k
                                             ->getIntValue<uint8_t>());
430
2.31k
  }
431
432
  std::string LdapResponseLayer::getMatchedDN() const
433
0
  {
434
0
    return getLdapOperationAsn1Record()
435
0
        ->getSubRecords()
436
0
        .at(matchedDNIndex)
437
0
        ->castAs<Asn1OctetStringRecord>()
438
0
        ->getValue();
439
0
  }
440
441
  std::string LdapResponseLayer::getDiagnosticMessage() const
442
0
  {
443
0
    return getLdapOperationAsn1Record()
444
0
        ->getSubRecords()
445
0
        .at(diagnotsticsMessageIndex)
446
0
        ->castAs<Asn1OctetStringRecord>()
447
0
        ->getValue();
448
0
  }
449
450
  std::vector<std::string> LdapResponseLayer::getReferral() const
451
0
  {
452
0
    std::vector<std::string> result;
453
0
    if (getLdapOperationAsn1Record()->getSubRecords().size() <= referralIndex)
454
0
    {
455
0
      return result;
456
0
    }
457
458
0
    auto referralRecord = getLdapOperationAsn1Record()->getSubRecords().at(referralIndex);
459
0
    if (referralRecord->getTagClass() != Asn1TagClass::ContextSpecific ||
460
0
        referralRecord->getTagType() != referralTagType)
461
0
    {
462
0
      return result;
463
0
    }
464
465
0
    for (auto uriRecord : referralRecord->castAs<Asn1ConstructedRecord>()->getSubRecords())
466
0
    {
467
0
      result.push_back(uriRecord->castAs<Asn1OctetStringRecord>()->getValue());
468
0
    }
469
470
0
    return result;
471
0
  }
472
473
  std::string LdapResponseLayer::getExtendedInfoString() const
474
2.31k
  {
475
2.31k
    return getResultCode().toString();
476
2.31k
  }
477
  // endregion
478
479
  // region LdapBindRequestLayer
480
481
  LdapBindRequestLayer::LdapBindRequestLayer(uint16_t messageId, uint8_t version, const std::string& name,
482
                                             const std::string& simpleAuthentication,
483
                                             const std::vector<LdapControl>& controls)
484
0
  {
485
0
    Asn1IntegerRecord versionRecord(version);
486
0
    Asn1OctetStringRecord nameRecord(name);
487
0
    std::vector<Asn1Record*> messageRecords = { &versionRecord, &nameRecord };
488
0
    std::unique_ptr<Asn1GenericRecord> simpleAuthenticationRecord;
489
0
    if (!simpleAuthentication.empty())
490
0
    {
491
0
      auto data = reinterpret_cast<const uint8_t*>(simpleAuthentication.data());
492
0
      simpleAuthenticationRecord = std::make_unique<Asn1GenericRecord>(
493
0
          Asn1TagClass::ContextSpecific, false,
494
0
          static_cast<uint8_t>(LdapBindRequestLayer::AuthenticationType::Simple), data,
495
0
          simpleAuthentication.size());
496
0
      messageRecords.push_back(simpleAuthenticationRecord.get());
497
0
    }
498
499
0
    LdapLayer::init(messageId, LdapOperationType::BindRequest, messageRecords, controls);
500
0
  }
501
502
  LdapBindRequestLayer::LdapBindRequestLayer(uint16_t messageId, uint8_t version, const std::string& name,
503
                                             const SaslAuthentication& saslAuthentication,
504
                                             const std::vector<LdapControl>& controls)
505
0
  {
506
0
    Asn1IntegerRecord versionRecord(version);
507
0
    Asn1OctetStringRecord nameRecord(name);
508
0
    std::vector<Asn1Record*> messageRecords = { &versionRecord, &nameRecord };
509
0
    std::unique_ptr<Asn1ConstructedRecord> saslAuthenticationRecord;
510
0
    if (!saslAuthentication.mechanism.empty())
511
0
    {
512
0
      PointerVector<Asn1Record> saslAuthenticationRecords;
513
0
      saslAuthenticationRecords.pushBack(new Asn1OctetStringRecord(saslAuthentication.mechanism));
514
0
      if (!saslAuthentication.credentials.empty())
515
0
      {
516
0
        auto credentialsRecord = new Asn1OctetStringRecord(saslAuthentication.credentials.data(),
517
0
                                                           saslAuthentication.credentials.size());
518
0
        saslAuthenticationRecords.pushBack(credentialsRecord);
519
0
      }
520
521
0
      saslAuthenticationRecord = std::make_unique<Asn1ConstructedRecord>(
522
0
          Asn1TagClass::ContextSpecific, static_cast<uint8_t>(LdapBindRequestLayer::AuthenticationType::Sasl),
523
0
          saslAuthenticationRecords);
524
0
      messageRecords.push_back(saslAuthenticationRecord.get());
525
0
    }
526
527
0
    LdapLayer::init(messageId, LdapOperationType::BindRequest, messageRecords, controls);
528
0
  }
529
530
  uint32_t LdapBindRequestLayer::getVersion() const
531
0
  {
532
0
    return getLdapOperationAsn1Record()
533
0
        ->getSubRecords()
534
0
        .at(versionIndex)
535
0
        ->castAs<Asn1IntegerRecord>()
536
0
        ->getIntValue<uint32_t>();
537
0
  }
538
539
  std::string LdapBindRequestLayer::getName() const
540
0
  {
541
0
    return getLdapOperationAsn1Record()->getSubRecords().at(nameIndex)->castAs<Asn1OctetStringRecord>()->getValue();
542
0
  }
543
544
  LdapBindRequestLayer::AuthenticationType LdapBindRequestLayer::getAuthenticationType() const
545
910
  {
546
910
    if (getLdapOperationAsn1Record()->getSubRecords().size() <= credentialIndex)
547
0
    {
548
0
      return LdapBindRequestLayer::AuthenticationType::NotApplicable;
549
0
    }
550
551
910
    auto authType = getLdapOperationAsn1Record()->getSubRecords().at(credentialIndex)->getTagType();
552
910
    switch (authType)
553
910
    {
554
604
    case 0:
555
604
      return LdapBindRequestLayer::AuthenticationType::Simple;
556
304
    case 3:
557
304
      return LdapBindRequestLayer::AuthenticationType::Sasl;
558
2
    default:
559
2
      return LdapBindRequestLayer::AuthenticationType::NotApplicable;
560
910
    }
561
910
  }
562
563
  std::string LdapBindRequestLayer::getSimpleAuthentication() const
564
0
  {
565
0
    if (getAuthenticationType() != LdapBindRequestLayer::AuthenticationType::Simple)
566
0
    {
567
0
      throw std::invalid_argument("Authentication type is not simple");
568
0
    }
569
570
0
    auto authRecord =
571
0
        getLdapOperationAsn1Record()->getSubRecords().at(credentialIndex)->castAs<Asn1GenericRecord>();
572
0
    return { reinterpret_cast<const char*>(authRecord->getValue()), authRecord->getValueLength() };
573
0
  }
574
575
  LdapBindRequestLayer::SaslAuthentication LdapBindRequestLayer::getSaslAuthentication() const
576
0
  {
577
0
    if (getAuthenticationType() != LdapBindRequestLayer::AuthenticationType::Sasl)
578
0
    {
579
0
      throw std::invalid_argument("Authentication type is not sasl");
580
0
    }
581
582
0
    auto authRecord =
583
0
        getLdapOperationAsn1Record()->getSubRecords().at(credentialIndex)->castAs<Asn1ConstructedRecord>();
584
0
    std::string mechanism;
585
0
    std::vector<uint8_t> credentials;
586
0
    if (authRecord->getSubRecords().size() > saslMechanismIndex)
587
0
    {
588
0
      mechanism = authRecord->getSubRecords().at(saslMechanismIndex)->castAs<Asn1OctetStringRecord>()->getValue();
589
0
    }
590
0
    if (authRecord->getSubRecords().size() > saslCredentialsIndex)
591
0
    {
592
0
      auto credentialsAsString =
593
0
          authRecord->getSubRecords().at(saslCredentialsIndex)->castAs<Asn1OctetStringRecord>()->getValue();
594
0
      credentials.resize(credentialsAsString.size() / 2);
595
0
      hexStringToByteArray(credentialsAsString, credentials.data(), credentials.size());
596
0
    }
597
598
0
    return { mechanism, credentials };
599
0
  }
600
601
  std::string LdapBindRequestLayer::getExtendedInfoString() const
602
910
  {
603
910
    switch (getAuthenticationType())
604
910
    {
605
604
    case AuthenticationType::Simple:
606
604
      return "simple";
607
304
    case AuthenticationType::Sasl:
608
304
      return "sasl";
609
2
    default:
610
2
      return "Unknown";
611
910
    }
612
910
  }
613
614
  // endregion
615
616
  // region LdapBindResponseLayer
617
618
  LdapBindResponseLayer::LdapBindResponseLayer(uint16_t messageId, LdapResultCode resultCode,
619
                                               const std::string& matchedDN, const std::string& diagnosticMessage,
620
                                               const std::vector<std::string>& referral,
621
                                               const std::vector<uint8_t>& serverSaslCredentials,
622
                                               const std::vector<LdapControl>& controls)
623
0
  {
624
0
    std::vector<Asn1Record*> additionalRecords;
625
0
    std::unique_ptr<Asn1Record> serverSaslCredentialsRecord;
626
0
    if (!serverSaslCredentials.empty())
627
0
    {
628
0
      serverSaslCredentialsRecord =
629
0
          std::make_unique<Asn1GenericRecord>(Asn1TagClass::ContextSpecific, false, serverSaslCredentialsTagType,
630
0
                                              serverSaslCredentials.data(), serverSaslCredentials.size());
631
0
      additionalRecords.push_back(serverSaslCredentialsRecord.get());
632
0
    }
633
634
0
    LdapResponseLayer::init(messageId, LdapOperationType::BindResponse, resultCode, matchedDN, diagnosticMessage,
635
0
                            referral, additionalRecords, controls);
636
0
  }
637
638
  std::vector<uint8_t> LdapBindResponseLayer::getServerSaslCredentials() const
639
0
  {
640
0
    try
641
0
    {
642
0
      auto serverSaslCredentialsRecord =
643
0
          getLdapOperationAsn1Record()->getSubRecords().back()->castAs<Asn1GenericRecord>();
644
0
      return { serverSaslCredentialsRecord->getValue(),
645
0
             serverSaslCredentialsRecord->getValue() + serverSaslCredentialsRecord->getValueLength() };
646
0
    }
647
0
    catch (const std::exception&)
648
0
    {
649
0
      return {};
650
0
    }
651
0
  }
652
653
  // endregion
654
655
  // region LdapUnbindRequestLayer
656
657
  LdapUnbindRequestLayer::LdapUnbindRequestLayer(uint16_t messageId, const std::vector<LdapControl>& controls)
658
0
  {
659
0
    LdapLayer::init(messageId, LdapOperationType::UnbindRequest, {}, controls);
660
0
  }
661
662
  // endregion
663
664
  // region LdapSearchRequestLayer
665
666
  const std::unordered_map<LdapSearchRequestLayer::SearchRequestScope::Value, std::string,
667
                           EnumClassHash<LdapSearchRequestLayer::SearchRequestScope::Value>>
668
      SearchRequestScopeToString{
669
        { LdapSearchRequestLayer::SearchRequestScope::BaseObject,   "BaseObject"   },
670
        { LdapSearchRequestLayer::SearchRequestScope::SingleLevel,  "SingleLevel"  },
671
        { LdapSearchRequestLayer::SearchRequestScope::WholeSubtree, "WholeSubtree" },
672
        { LdapSearchRequestLayer::SearchRequestScope::Unknown,      "Unknown"      }
673
    };
674
675
  const std::unordered_map<LdapSearchRequestLayer::DerefAliases::Value, std::string,
676
                           EnumClassHash<LdapSearchRequestLayer::DerefAliases::Value>>
677
      DerefAliasesToString{
678
        { LdapSearchRequestLayer::DerefAliases::NeverDerefAliases,   "NeverDerefAliases"   },
679
        { LdapSearchRequestLayer::DerefAliases::DerefInSearching,    "DerefInSearching"    },
680
        { LdapSearchRequestLayer::DerefAliases::DerefFindingBaseObj, "DerefFindingBaseObj" },
681
        { LdapSearchRequestLayer::DerefAliases::DerefAlways,         "DerefAlways"         },
682
        { LdapSearchRequestLayer::DerefAliases::Unknown,             "Unknown"             }
683
    };
684
685
  std::string LdapSearchRequestLayer::SearchRequestScope::toString() const
686
640
  {
687
640
    return SearchRequestScopeToString.at(m_Value);
688
640
  }
689
690
  LdapSearchRequestLayer::SearchRequestScope LdapSearchRequestLayer::SearchRequestScope::fromUintValue(uint8_t value)
691
640
  {
692
640
    if (value <= 2)
693
570
    {
694
570
      return static_cast<LdapSearchRequestLayer::SearchRequestScope::Value>(value);
695
570
    }
696
697
70
    return LdapSearchRequestLayer::SearchRequestScope::Unknown;
698
640
  }
699
700
  std::string LdapSearchRequestLayer::DerefAliases::toString() const
701
0
  {
702
0
    return DerefAliasesToString.at(m_Value);
703
0
  }
704
705
  LdapSearchRequestLayer::DerefAliases LdapSearchRequestLayer::DerefAliases::fromUintValue(uint8_t value)
706
0
  {
707
0
    if (value <= 3)
708
0
    {
709
0
      return static_cast<LdapSearchRequestLayer::DerefAliases::Value>(value);
710
0
    }
711
712
0
    return LdapSearchRequestLayer::DerefAliases::Unknown;
713
0
  }
714
715
  LdapSearchRequestLayer::LdapSearchRequestLayer(uint16_t messageId, const std::string& baseObject,
716
                                                 SearchRequestScope scope, DerefAliases derefAliases,
717
                                                 uint8_t sizeLimit, uint8_t timeLimit, bool typesOnly,
718
                                                 Asn1Record* filterRecord, const std::vector<std::string>& attributes,
719
                                                 const std::vector<LdapControl>& controls)
720
0
  {
721
0
    Asn1OctetStringRecord baseObjectRecord(baseObject);
722
0
    Asn1EnumeratedRecord scopeRecord(scope);
723
0
    Asn1EnumeratedRecord derefAliasesRecord(derefAliases);
724
0
    Asn1IntegerRecord sizeLimitRecord(sizeLimit);
725
0
    Asn1IntegerRecord timeLimitRecord(timeLimit);
726
0
    Asn1BooleanRecord typeOnlyRecord(typesOnly);
727
728
0
    PointerVector<Asn1Record> attributeSubRecords;
729
0
    for (const auto& attribute : attributes)
730
0
    {
731
0
      attributeSubRecords.pushBack(new Asn1OctetStringRecord(attribute));
732
0
    }
733
0
    Asn1SequenceRecord attributesRecord(attributeSubRecords);
734
735
0
    LdapLayer::init(messageId, LdapOperationType::SearchRequest,
736
0
                    { &baseObjectRecord, &scopeRecord, &derefAliasesRecord, &sizeLimitRecord, &timeLimitRecord,
737
0
                      &typeOnlyRecord, filterRecord, &attributesRecord },
738
0
                    controls);
739
0
  }
740
741
  std::string LdapSearchRequestLayer::getBaseObject() const
742
640
  {
743
640
    return getLdapOperationAsn1Record()
744
640
        ->getSubRecords()
745
640
        .at(baseObjectIndex)
746
640
        ->castAs<Asn1OctetStringRecord>()
747
640
        ->getValue();
748
640
  }
749
750
  LdapSearchRequestLayer::SearchRequestScope LdapSearchRequestLayer::getScope() const
751
640
  {
752
640
    return LdapSearchRequestLayer::SearchRequestScope::fromUintValue(getLdapOperationAsn1Record()
753
640
                                                                         ->getSubRecords()
754
640
                                                                         .at(scopeIndex)
755
640
                                                                         ->castAs<Asn1EnumeratedRecord>()
756
640
                                                                         ->getIntValue<uint8_t>());
757
640
  }
758
759
  LdapSearchRequestLayer::DerefAliases LdapSearchRequestLayer::getDerefAlias() const
760
0
  {
761
0
    return LdapSearchRequestLayer::DerefAliases::fromUintValue(getLdapOperationAsn1Record()
762
0
                                                                   ->getSubRecords()
763
0
                                                                   .at(derefAliasIndex)
764
0
                                                                   ->castAs<Asn1EnumeratedRecord>()
765
0
                                                                   ->getIntValue<uint8_t>());
766
0
  }
767
768
  uint8_t LdapSearchRequestLayer::getSizeLimit() const
769
0
  {
770
0
    return getLdapOperationAsn1Record()
771
0
        ->getSubRecords()
772
0
        .at(sizeLimitIndex)
773
0
        ->castAs<Asn1IntegerRecord>()
774
0
        ->getIntValue<uint8_t>();
775
0
  }
776
777
  uint8_t LdapSearchRequestLayer::getTimeLimit() const
778
0
  {
779
0
    return getLdapOperationAsn1Record()
780
0
        ->getSubRecords()
781
0
        .at(timeLimitIndex)
782
0
        ->castAs<Asn1IntegerRecord>()
783
0
        ->getIntValue<uint8_t>();
784
0
  }
785
786
  bool LdapSearchRequestLayer::getTypesOnly() const
787
0
  {
788
0
    return getLdapOperationAsn1Record()
789
0
        ->getSubRecords()
790
0
        .at(typesOnlyIndex)
791
0
        ->castAs<Asn1BooleanRecord>()
792
0
        ->getValue();
793
0
  }
794
795
  Asn1Record* LdapSearchRequestLayer::getFilter() const
796
0
  {
797
0
    return getLdapOperationAsn1Record()->getSubRecords().at(filterIndex);
798
0
  }
799
800
  std::vector<std::string> LdapSearchRequestLayer::getAttributes() const
801
0
  {
802
0
    std::vector<std::string> result;
803
0
    if (getLdapOperationAsn1Record()->getSubRecords().size() <= attributesIndex)
804
0
    {
805
0
      return result;
806
0
    }
807
808
0
    auto attributesRecord =
809
0
        getLdapOperationAsn1Record()->getSubRecords().at(attributesIndex)->castAs<Asn1SequenceRecord>();
810
0
    for (auto attribute : attributesRecord->getSubRecords())
811
0
    {
812
0
      result.push_back(attribute->castAs<Asn1OctetStringRecord>()->getValue());
813
0
    }
814
815
0
    return result;
816
0
  }
817
818
  std::string LdapSearchRequestLayer::getExtendedInfoString() const
819
640
  {
820
640
    auto baseObject = getBaseObject();
821
640
    if (baseObject.empty())
822
0
    {
823
0
      baseObject = "ROOT";
824
0
    }
825
826
640
    return "\"" + baseObject + "\", " + getScope().toString();
827
640
  }
828
829
  // endregion
830
831
  // region LdapSearchResultEntryLayer
832
833
  LdapSearchResultEntryLayer::LdapSearchResultEntryLayer(uint16_t messageId, const std::string& objectName,
834
                                                         const std::vector<LdapAttribute>& attributes,
835
                                                         const std::vector<LdapControl>& controls)
836
0
  {
837
0
    PointerVector<Asn1Record> attributesSubRecords;
838
0
    for (const auto& attribute : attributes)
839
0
    {
840
0
      PointerVector<Asn1Record> valuesSubRecords;
841
0
      for (const auto& value : attribute.values)
842
0
      {
843
0
        valuesSubRecords.pushBack(new Asn1OctetStringRecord(value));
844
0
      }
845
846
0
      Asn1OctetStringRecord typeRecord(attribute.type);
847
0
      Asn1SetRecord valuesRecord(valuesSubRecords);
848
849
0
      attributesSubRecords.pushBack(new Asn1SequenceRecord({ &typeRecord, &valuesRecord }));
850
0
    }
851
852
0
    Asn1OctetStringRecord objectNameRecord(objectName);
853
0
    Asn1SequenceRecord attributesRecord(attributesSubRecords);
854
855
0
    LdapLayer::init(messageId, LdapOperationType::SearchResultEntry, { &objectNameRecord, &attributesRecord },
856
0
                    controls);
857
0
  }
858
859
  std::string LdapSearchResultEntryLayer::getObjectName() const
860
0
  {
861
0
    return getLdapOperationAsn1Record()
862
0
        ->getSubRecords()
863
0
        .at(objectNameIndex)
864
0
        ->castAs<Asn1OctetStringRecord>()
865
0
        ->getValue();
866
0
  }
867
868
  std::vector<LdapAttribute> LdapSearchResultEntryLayer::getAttributes() const
869
0
  {
870
0
    std::vector<LdapAttribute> result;
871
872
0
    auto attributes =
873
0
        getLdapOperationAsn1Record()->getSubRecords().at(attributesIndex)->castAs<Asn1SequenceRecord>();
874
0
    for (auto attributeRecord : attributes->getSubRecords())
875
0
    {
876
0
      auto attrAsSequence = attributeRecord->castAs<Asn1SequenceRecord>();
877
878
0
      auto type =
879
0
          attrAsSequence->getSubRecords().at(attributeTypeIndex)->castAs<Asn1OctetStringRecord>()->getValue();
880
881
0
      std::vector<std::string> values;
882
0
      auto valuesRecord = attrAsSequence->getSubRecords().at(attributeValueIndex)->castAs<Asn1SetRecord>();
883
884
0
      for (auto valueRecord : valuesRecord->getSubRecords())
885
0
      {
886
0
        values.push_back(valueRecord->castAs<Asn1OctetStringRecord>()->getValue());
887
0
      }
888
889
0
      LdapAttribute ldapAttribute = { type, values };
890
0
      result.push_back(ldapAttribute);
891
0
    }
892
893
0
    return result;
894
0
  }
895
896
  // endregion
897
}  // namespace pcpp