/ src / ldap_comunication.cpp
ldap_comunication.cpp
  1  /**
  2   * @file ldap_comunication.cpp
  3   * @author Rene Ceska xceska06 (xceska06@stud.fit.vutbr.cz)
  4   * @date 2023-11-19
  5   */
  6  #include "inc/ldap_comunication.h"
  7  #define DEBUG
  8  
  9  BerObject *InitSearchResultEntry(BerObject *searchRequest,
 10                                   std::vector<unsigned char> LDAPDN) {
 11    std::vector<unsigned char> DNprefix = {'u', 'i', 'd', '='};
 12    DNprefix.insert(DNprefix.end(), LDAPDN.begin(), LDAPDN.end());
 13    BerSequenceObject *envelope = new BerSequenceObject();
 14    envelope->objects.push_back(new BerIntObject(
 15        static_cast<BerIntObject *>(
 16            static_cast<BerSequenceObject *>(searchRequest)->objects[0])
 17            ->getValue())); // copy message ID
 18    BerSequenceObject *PartialAttributeList =
 19        new BerSequenceObject(BER_SEARCH_RESULT_ENTRY_C);
 20    envelope->objects.push_back(PartialAttributeList);
 21    PartialAttributeList->objects.push_back(new BerStringObject(DNprefix));
 22    PartialAttributeList->objects.push_back(new BerSequenceObject());
 23    return envelope;
 24  }
 25  
 26  int AddToSearchResultEntry(BerObject *envelope,
 27                             std::vector<unsigned char> &attributeDescription,
 28                             std::vector<unsigned char> &attributeValue) {
 29    BerSequenceObject *SearchResultEntry =
 30        (BerSequenceObject *)(((BerSequenceObject *)envelope)->objects[1]);
 31    BerSequenceObject *PartialAttributeList =
 32        (BerSequenceObject *)(((BerSequenceObject *)SearchResultEntry)
 33                                  ->objects[1]);
 34    BerSequenceObject *attributeValueSequence = new BerSequenceObject();
 35    attributeValueSequence->objects.push_back(
 36        new BerStringObject(attributeDescription));
 37    BerSetObject *attributeValueSet = new BerSetObject();
 38    attributeValueSet->objects.push_back(new BerStringObject(attributeValue));
 39    attributeValueSequence->objects.push_back(attributeValueSet);
 40  
 41    PartialAttributeList->objects.push_back(attributeValueSequence);
 42    return 0;
 43  }
 44  
 45  BerObject *CreateBindResponse(BerObject *bindRequest, int resultCode) {
 46    BerSequenceObject *envelope = new BerSequenceObject();
 47    envelope->objects.push_back(((BerSequenceObject *)(bindRequest))->objects[0]);
 48    BerSequenceObject *bindResponseSequence =
 49        new BerSequenceObject(BER_BIND_RESPONSE_C);
 50    envelope->objects.push_back(bindResponseSequence);
 51    bindResponseSequence->objects.push_back(new BerEnumObject(resultCode));
 52    bindResponseSequence->objects.push_back(new BerStringObject());
 53    bindResponseSequence->objects.push_back(new BerStringObject());
 54    return envelope;
 55  }
 56  
 57  int sendSearchResultDone(BerSequenceObject *searchRequest, int comm_socket,
 58                           unsigned int result_code) {
 59    BerSequenceObject *envelope = new BerSequenceObject();
 60    envelope->objects.push_back(
 61        new BerIntObject(dynamic_cast<BerIntObject *>(searchRequest->objects[0])
 62                             ->getValue())); // copy message ID
 63    BerSequenceObject *searchResultDoneSequence =
 64        new BerSequenceObject(BER_SEARCH_RESULT_DONE_C);
 65    envelope->objects.push_back(searchResultDoneSequence);
 66    searchResultDoneSequence->objects.push_back(new BerEnumObject(result_code));
 67    searchResultDoneSequence->objects.push_back(new BerStringObject(""));
 68    searchResultDoneSequence->objects.push_back(new BerStringObject(""));
 69  
 70    std::vector<unsigned char> envelopeBer = envelope->getBerRepresentation();
 71    send(comm_socket, &envelopeBer[0], envelopeBer.size(), MSG_NOSIGNAL);
 72    delete envelope;
 73    return 0;
 74  }
 75  
 76  int checkSearchRequest(BerObject *searchRequest) {
 77  
 78    // use dynamic casts
 79    BerSequenceObject *envelope =
 80        dynamic_cast<BerSequenceObject *>(searchRequest);
 81    if (envelope == nullptr) {
 82      return -2;
 83    }
 84    // check count of object inside envelope
 85    if (envelope->objects.size() != 2) {
 86      return -1;
 87    }
 88    BerIntObject *messageID = dynamic_cast<BerIntObject *>(envelope->objects[0]);
 89    if (messageID == nullptr) {
 90      return -2;
 91    }
 92  
 93    BerSequenceObject *searchRequestSequence =
 94        dynamic_cast<BerSequenceObject *>(envelope->objects[1]);
 95    if (searchRequestSequence == nullptr) {
 96      return -1;
 97    }
 98    // check count of object inside searchRequestSequence
 99    if (searchRequestSequence->objects.size() != 8) {
100      return -1;
101    }
102    BerStringObject *baseObject =
103        dynamic_cast<BerStringObject *>(searchRequestSequence->objects[0]);
104    BerEnumObject *scope =
105        dynamic_cast<BerEnumObject *>(searchRequestSequence->objects[1]);
106    BerEnumObject *derefAliases =
107        dynamic_cast<BerEnumObject *>(searchRequestSequence->objects[2]);
108    BerIntObject *sizeLimit =
109        dynamic_cast<BerIntObject *>(searchRequestSequence->objects[3]);
110    BerIntObject *timeLimit =
111        dynamic_cast<BerIntObject *>(searchRequestSequence->objects[4]);
112    BerBoolObject *typesOnly =
113        dynamic_cast<BerBoolObject *>(searchRequestSequence->objects[5]);
114    BerUndefinedObject *filter =
115        dynamic_cast<BerUndefinedObject *>(searchRequestSequence->objects[6]);
116    BerSequenceObject *attributes =
117        dynamic_cast<BerSequenceObject *>(searchRequestSequence->objects[7]);
118  
119    if (messageID == nullptr || baseObject == nullptr || scope == nullptr ||
120        derefAliases == nullptr || sizeLimit == nullptr || timeLimit == nullptr ||
121        typesOnly == nullptr || filter == nullptr || attributes == nullptr) {
122      return -1;
123    }
124    return 0;
125  }
126  
127  int sendNoticeOfDisconnection(int comSocket, char errCode) {
128    BerSequenceObject *envelope = new BerSequenceObject();
129    envelope->objects.push_back(new BerIntObject(0));
130    BerSequenceObject *extendedResp =
131        new BerSequenceObject(BER_EXTENDED_RESPONSE_C);
132    envelope->objects.push_back(extendedResp);
133    extendedResp->objects.push_back(new BerEnumObject(errCode));
134    extendedResp->objects.push_back(
135        new BerStringObject("1.3.6.1.4.1.1466.20036"));
136    extendedResp->objects.push_back(new BerStringObject(""));
137    std::vector<unsigned char> envelopeBer = envelope->getBerRepresentation();
138    send(comSocket, &envelopeBer[0], envelopeBer.size(), MSG_NOSIGNAL);
139    return 0;
140  }
141  
142  int searchRequestHandler(BerObject *searchRequest, int comm_socket,
143                           const char *dbPath) {
144  
145    // checks if search request is valid
146    int err = checkSearchRequest(searchRequest);
147    BerSequenceObject *envelope =
148        dynamic_cast<BerSequenceObject *>(searchRequest);
149    if (err == -2) {
150      sendNoticeOfDisconnection(comm_socket, BER_LDAP_PROTOCOL_ERROR);
151      return -1;
152    }
153    if (err == -1) {
154      sendSearchResultDone((BerSequenceObject *)envelope, comm_socket,
155                           BER_LDAP_SIZE_LIMIT_EXCEEDED);
156      return -1;
157    }
158    // extracting searchRequestSequence from envelope
159    BerSequenceObject *searchRequestSequence =
160        (BerSequenceObject *)envelope->objects[1];
161  
162    // inicialization of searchRequestType
163    searchRequestType sr;
164    sr.sizeLimit = 0;
165    sr.attributes.cn = false;
166    sr.attributes.email = false;
167    sr.attributes.uid = false;
168  
169    // cn
170    std::vector<unsigned char> cn = {'c', 'n'};
171    // CommonName
172    std::vector<unsigned char> CommonName = {'c', 'o', 'm', 'm', 'o',
173                                             'n', 'n', 'a', 'm', 'e'};
174    // email
175    std::vector<unsigned char> email = {'e', 'm', 'a', 'i', 'l'};
176    // email
177    std::vector<unsigned char> mail = {'m', 'a', 'i', 'l'};
178    // uid
179    std::vector<unsigned char> uid = {'u', 'i', 'd'};
180    // UserID
181    std::vector<unsigned char> UserID = {'u', 's', 'e', 'r', 'i', 'd'};
182  
183    // getting size limit
184    sr.sizeLimit =
185        ((BerIntObject *)searchRequestSequence->objects[3])->getValue();
186    // getting filters and converting them to FilterObject
187    std::vector<unsigned char> filtersBer =
188        (searchRequestSequence->objects[6])->getBerRepresentation();
189    FilterObject *f = convertToFilterObject(filtersBer.begin(), filtersBer.end());
190  
191    // filtering database
192    std::vector<DatabaseObject> result;
193    err = 0;
194    result = filterHandler(f, &err, dbPath, sr.sizeLimit);
195  
196    result = removeDuplicates(result);
197    bool sizeLimitExceeded = false;
198    if (err == 1) {
199      sizeLimitExceeded = true;
200    }
201  
202    // getting attributes which should be returned
203    BerSequenceObject *attributesSequence =
204        (BerSequenceObject *)searchRequestSequence->objects[7];
205  
206    for (long unsigned int i = 0; i < attributesSequence->objects.size(); i++) {
207  
208      if (ToLowerCase(
209              ((BerStringObject *)attributesSequence->objects[i])->value) == cn ||
210          ToLowerCase(
211              ((BerStringObject *)attributesSequence->objects[i])->value) ==
212              CommonName) {
213        sr.attributes.cn = true;
214      }
215      if (ToLowerCase(
216              ((BerStringObject *)attributesSequence->objects[i])->value) ==
217              email ||
218          ToLowerCase(
219              ((BerStringObject *)attributesSequence->objects[i])->value) ==
220              mail) {
221        sr.attributes.email = true;
222      }
223      if (ToLowerCase(
224              ((BerStringObject *)attributesSequence->objects[i])->value) ==
225              uid ||
226          ToLowerCase(
227              ((BerStringObject *)attributesSequence->objects[i])->value) ==
228              UserID) {
229        sr.attributes.uid = true;
230      }
231    }
232    // if no attributes specified, return all
233    if (!sr.attributes.cn && !sr.attributes.email && !sr.attributes.uid) {
234      sr.attributes.cn = true;
235      sr.attributes.email = true;
236      sr.attributes.uid = true;
237    }
238    // send search result entry for each entry in result
239    for (unsigned long int i = 0; i < result.size(); i++) {
240      BerObject *searchResultEntry =
241          InitSearchResultEntry(envelope, result[i].get_uid());
242  
243      std::vector<unsigned char> resCN = result[i].get_name();
244      std::vector<unsigned char> resEmail = result[i].get_email();
245      std::vector<unsigned char> resUID = result[i].get_uid();
246  
247      if (sr.attributes.cn) {
248        AddToSearchResultEntry(searchResultEntry, cn, resCN);
249      }
250      if (sr.attributes.email) {
251        AddToSearchResultEntry(searchResultEntry, email, resEmail);
252      }
253      if (sr.attributes.uid) {
254        AddToSearchResultEntry(searchResultEntry, uid, resUID);
255      }
256  
257      std::vector<unsigned char> searchResultEntryBer =
258          searchResultEntry->getBerRepresentation();
259      send(comm_socket, &searchResultEntryBer[0], searchResultEntryBer.size(),
260           MSG_NOSIGNAL);
261      delete searchResultEntry;
262    }
263  
264    // send search result done
265    if (sizeLimitExceeded) {
266  
267      sendSearchResultDone((BerSequenceObject *)envelope, comm_socket,
268                           BER_LDAP_SIZE_LIMIT_EXCEEDED);
269    } else {
270      sendSearchResultDone((BerSequenceObject *)envelope, comm_socket,
271                           BER_LDAP_SUCCESS);
272    }
273    delete f;
274    return 0;
275  }
276  
277  int loadEnvelope(std::vector<unsigned char> &bindRequest, int comm_socket) {
278    unsigned char buff[1024];
279    int lenghtOfMessage = 0;
280    int err;
281    int resNow = 0;
282    int resAll = 0;
283    for (;;) { // loads lenght of message
284      int returnCode = recv(comm_socket, buff + resNow, 1024, 0);
285      if (returnCode == 0)
286        return -1;
287      resNow += returnCode;
288  
289      if (resNow >= 2) {
290        if ((buff[1] < 0x80) ||
291            (buff[1] & 0x7F) <= resNow) { // checks if bytes containing lenght of
292          // message are complete
293          bindRequest.insert(bindRequest.end(), buff, buff + resNow);
294          lenghtOfMessage =
295              GetLength(bindRequest.begin() + 1, &err, bindRequest.end()) +
296              GetLengthOfLength(bindRequest.begin() + 1, &err,
297                                bindRequest.end()) +
298              1;
299          break;
300        }
301      }
302    }
303    resAll = resNow;
304    for (;;) {
305      resNow = 0;
306      if (resAll < lenghtOfMessage) {
307        int returnCode = recv(comm_socket, buff, 1024, 0);
308        if (returnCode == 0)
309          return -1;
310        resNow += returnCode;
311        resAll += resNow;
312      }
313  
314      if (resAll > 0) {
315        // check if message is envelope
316        if (bindRequest[0] != 0x30) {
317          sendNoticeOfDisconnection(comm_socket, BER_LDAP_PROTOCOL_ERROR);
318          err = -1;
319          break;
320        }
321        int length = 0;
322        length = buff[1];
323  
324        bindRequest.insert(bindRequest.end(), buff, buff + resNow);
325        // if whole message received, return response
326        if (resAll >= lenghtOfMessage) {
327          return length + 2;
328        }
329      } else // error or end of connection
330        break;
331    }
332    return -1;
333  }