LDAPConfigCheck.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include "LDAPConfigCheck.h"
  18. LDAPConfigCheck::LDAPConfigCheck(const char *lpszConfigFile) : ECConfigCheck("LDAP Configuration file", lpszConfigFile)
  19. {
  20. }
  21. void LDAPConfigCheck::loadChecks()
  22. {
  23. // TODO: add check for ldap_host is resolvable IP address
  24. // TODO: add check for ldap_port on ldap_host is reachable
  25. addCheck("ldap_bind_user", CONFIG_MANDATORY);
  26. addCheck("ldap_last_modification_attribute", CONFIG_MANDATORY);
  27. addCheck("ldap_server_charset", 0, &testCharset);
  28. addCheck("ldap_search_base", CONFIG_MANDATORY);
  29. addCheck("ldap_object_type_attribute", CONFIG_MANDATORY);
  30. addCheck("ldap_user_type_attribute_value", CONFIG_MANDATORY);
  31. addCheck("ldap_group_type_attribute_value", CONFIG_MANDATORY);
  32. addCheck("ldap_company_type_attribute_value", CONFIG_MANDATORY | CONFIG_HOSTED_USED);
  33. addCheck("ldap_contact_type_attribute_value", 0);
  34. addCheck("ldap_addresslist_type_attribute_value", 0);
  35. addCheck("ldap_dynamicgroup_type_attribute_value", 0);
  36. addCheck("ldap_server_type_attribute_value", CONFIG_MULTI_USED);
  37. addCheck("ldap_user_search_filter", 0, &testLdapQuery);
  38. addCheck("ldap_group_search_filter", 0, &testLdapQuery);
  39. addCheck("ldap_company_search_filter", 0, &testLdapQuery);
  40. addCheck("ldap_user_unique_attribute", CONFIG_MANDATORY);
  41. addCheck("ldap_user_unique_attribute_type", 0, &testLdapType);
  42. addCheck("ldap_group_unique_attribute", CONFIG_MANDATORY);
  43. addCheck("ldap_group_unique_attribute_type", 0, &testLdapType);
  44. addCheck("ldap_groupmembers_attribute_type", 0, &testLdapType);
  45. addCheck("ldap_company_unique_attribute", CONFIG_HOSTED_USED | CONFIG_MANDATORY);
  46. addCheck("ldap_company_unique_attribute_type", CONFIG_HOSTED_USED, &testLdapType);
  47. addCheck("ldap_company_view_attribute_type", CONFIG_HOSTED_USED, &testLdapType);
  48. addCheck("ldap_company_admin_attribute_type", CONFIG_HOSTED_USED, &testLdapType);
  49. addCheck("ldap_company_system_admin_attribute_type", CONFIG_HOSTED_USED, &testLdapType);
  50. addCheck("ldap_quota_userwarning_recipients_attribute_type", 0, &testLdapType);
  51. addCheck("ldap_quota_companywarning_recipients_attribute_type", 0, &testLdapType);
  52. }
  53. int LDAPConfigCheck::testLdapScope(const config_check_t *check)
  54. {
  55. if (check->value1.empty() ||
  56. check->value1 == "base" ||
  57. check->value1 == "one" ||
  58. check->value1 == "sub")
  59. return CHECK_OK;
  60. printError(check->option1, "contains unknown scope \"" + check->value1 + "\"");
  61. return CHECK_ERROR;
  62. }
  63. int LDAPConfigCheck::testLdapType(const config_check_t *check)
  64. {
  65. if (check->value1.empty() ||
  66. check->value1 == "text" ||
  67. check->value1 == "binary" ||
  68. check->value1 == "dn" ||
  69. check->value1 == "attribute")
  70. return CHECK_OK;
  71. printError(check->option1, "contains unknown type \"" + check->value1 + "\"");
  72. return CHECK_ERROR;
  73. }
  74. int LDAPConfigCheck::testLdapQuery(const config_check_t *check)
  75. {
  76. std::string stack;
  77. bool contains_data; /* '(' was followed by attribute comparison */
  78. bool contains_check; /* '=' found */
  79. /* Empty queries are always correct */
  80. if (check->value1.empty())
  81. return CHECK_OK;
  82. /* If the query contains any of the following characters it is broken */
  83. if (check->value1.find_first_of("{}") != std::string::npos) {
  84. printError(check->option1, "contains invalid character: \"" + check->value1 + "\"");
  85. return CHECK_ERROR;
  86. }
  87. /* Queries _must_ always be enclosed by '(' and ')',
  88. * note that this check will pass '(a=1)(b=2)' as correct,
  89. * we will block this in the for loop.
  90. */
  91. if (*check->value1.begin() != '(' || *check->value1.rbegin() != ')')
  92. goto error_exit;
  93. /* Since we already checked the first character, we can add it to the stack */
  94. stack += check->value1[0];
  95. contains_data = false;
  96. contains_check = false;
  97. /* Loop through the string, the following queries must be marked broken:
  98. * (a=1)(a=2) => Must be enclosed by '(' and ')'
  99. * ((a=1) => Requires equal number '(' and ')'
  100. * (a=1)) => Requires equal number '(' and ')'
  101. * (a) => A check consists of attribute=value comparison
  102. * ((a=1)(a=2)) => Requires '|' or '&' to combine the 2 queries
  103. * (&a=1) => '|' and '&' should only be present in front of '('
  104. */
  105. for (auto i = check->value1.cbegin() + 1; i != check->value1.cend(); ++i) {
  106. if (stack.empty())
  107. goto error_exit;
  108. switch (*i) {
  109. case '(':
  110. if (contains_data)
  111. goto error_exit;
  112. if (*stack.rbegin() != '|' &&
  113. *stack.rbegin() != '&')
  114. goto error_exit;
  115. stack += *i;
  116. break;
  117. case ')':
  118. if (!contains_data || !contains_check)
  119. goto error_exit;
  120. stack.erase(stack.end() - 1);
  121. contains_data = false;
  122. contains_check = false;
  123. break;
  124. case '|':
  125. case '&':
  126. if (contains_data)
  127. goto error_exit;
  128. stack += *i;
  129. break;
  130. case '=':
  131. if (!contains_data)
  132. goto error_exit;
  133. contains_check = true;
  134. break;
  135. default:
  136. if (*stack.rbegin() == '|' ||
  137. *stack.rbegin() == '&')
  138. goto error_exit;
  139. contains_data = true;
  140. break;
  141. }
  142. }
  143. return CHECK_OK;
  144. error_exit:
  145. printError(check->option1, "contains malformatted string: \"" + check->value1 + "\"");
  146. return CHECK_ERROR;
  147. }