memberof_config.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2008 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. /*
  41. * memberof_config.c - configuration-related code for memberOf plug-in
  42. *
  43. */
  44. #include <plstr.h>
  45. #include "memberof.h"
  46. #define MEMBEROF_CONFIG_FILTER "(objectclass=*)"
  47. /*
  48. * The configuration attributes are contained in the plugin entry e.g.
  49. * cn=MemberOf Plugin,cn=plugins,cn=config
  50. *
  51. * Configuration is a two step process. The first pass is a validation step which
  52. * occurs pre-op - check inputs and error out if bad. The second pass actually
  53. * applies the changes to the run time config.
  54. */
  55. /*
  56. * function prototypes
  57. */
  58. static int memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  59. int *returncode, char *returntext, void *arg);
  60. static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  61. int *returncode, char *returntext, void *arg)
  62. {
  63. return SLAPI_DSE_CALLBACK_OK;
  64. }
  65. /*
  66. * static variables
  67. */
  68. /* This is the main configuration which is updated from dse.ldif. The
  69. * config will be copied when it is used by the plug-in to prevent it
  70. * being changed out from under a running memberOf operation. */
  71. static MemberOfConfig theConfig = {NULL, NULL,0, NULL, NULL, NULL, NULL};
  72. static Slapi_RWLock *memberof_config_lock = 0;
  73. static int inited = 0;
  74. static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  75. int *returncode, char *returntext, void *arg)
  76. {
  77. *returncode = LDAP_UNWILLING_TO_PERFORM;
  78. return SLAPI_DSE_CALLBACK_ERROR;
  79. }
  80. /*
  81. * memberof_config()
  82. *
  83. * Read configuration and create a configuration data structure.
  84. * This is called after the server has configured itself so we can
  85. * perform checks with regards to suffixes if it ever becomes
  86. * necessary.
  87. * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
  88. */
  89. int
  90. memberof_config(Slapi_Entry *config_e, Slapi_PBlock *pb)
  91. {
  92. int returncode = LDAP_SUCCESS;
  93. char returntext[SLAPI_DSE_RETURNTEXT_SIZE];
  94. if ( inited ) {
  95. slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
  96. "only one memberOf plugin instance can be used\n" );
  97. return( LDAP_PARAM_ERROR );
  98. }
  99. /* initialize the RW lock to protect the main config */
  100. memberof_config_lock = slapi_new_rwlock();
  101. /* initialize fields */
  102. if (SLAPI_DSE_CALLBACK_OK == memberof_validate_config(NULL, NULL, config_e,
  103. &returncode, returntext, NULL))
  104. {
  105. memberof_apply_config(NULL, NULL, config_e, &returncode, returntext, NULL);
  106. }
  107. /*
  108. * config DSE must be initialized before we get here we only need the dse callbacks
  109. * for the plugin entry, but not the shared config entry.
  110. */
  111. if (returncode == LDAP_SUCCESS) {
  112. const char *config_dn = slapi_sdn_get_dn(memberof_get_plugin_area());
  113. slapi_config_register_callback_plugin(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP | DSE_FLAG_PLUGIN,
  114. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  115. memberof_validate_config, NULL,pb);
  116. slapi_config_register_callback_plugin(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP | DSE_FLAG_PLUGIN,
  117. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  118. memberof_apply_config, NULL, pb);
  119. slapi_config_register_callback_plugin(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP | DSE_FLAG_PLUGIN,
  120. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  121. dont_allow_that, NULL, pb);
  122. slapi_config_register_callback_plugin(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP | DSE_FLAG_PLUGIN,
  123. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  124. dont_allow_that, NULL, pb);
  125. slapi_config_register_callback_plugin(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP | DSE_FLAG_PLUGIN,
  126. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  127. memberof_search, NULL, pb);
  128. }
  129. inited = 1;
  130. if (returncode != LDAP_SUCCESS) {
  131. slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
  132. "Error %d: %s\n", returncode, returntext);
  133. }
  134. return returncode;
  135. }
  136. void
  137. memberof_release_config()
  138. {
  139. const char *config_dn = slapi_sdn_get_dn(memberof_get_plugin_area());
  140. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
  141. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  142. memberof_validate_config);
  143. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP,
  144. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  145. memberof_apply_config);
  146. slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP,
  147. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  148. dont_allow_that);
  149. slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP,
  150. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  151. dont_allow_that);
  152. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
  153. config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
  154. memberof_search);
  155. slapi_destroy_rwlock(memberof_config_lock);
  156. memberof_config_lock = NULL;
  157. inited = 0;
  158. }
  159. /*
  160. * memberof_validate_config()
  161. *
  162. * Validate the pending changes in the e entry.
  163. */
  164. static int
  165. memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  166. int *returncode, char *returntext, void *arg)
  167. {
  168. Slapi_Attr *memberof_attr = NULL;
  169. Slapi_Attr *group_attr = NULL;
  170. Slapi_DN *config_sdn = NULL;
  171. char *syntaxoid = NULL;
  172. char *config_dn = NULL;
  173. char *skip_nested = NULL;
  174. int not_dn_syntax = 0;
  175. *returncode = LDAP_UNWILLING_TO_PERFORM; /* be pessimistic */
  176. /* Make sure both the group attr and the memberOf attr
  177. * config atributes are supplied. We don't care about &attr
  178. * here, but slapi_entry_attr_find() requires us to pass it. */
  179. if (!slapi_entry_attr_find(e, MEMBEROF_GROUP_ATTR, &group_attr) &&
  180. !slapi_entry_attr_find(e, MEMBEROF_ATTR, &memberof_attr))
  181. {
  182. Slapi_Attr *test_attr = NULL;
  183. Slapi_Value *value = NULL;
  184. int hint = 0;
  185. /* Loop through each group attribute to see if the syntax is correct. */
  186. hint = slapi_attr_first_value(group_attr, &value);
  187. while (value && (not_dn_syntax == 0))
  188. {
  189. /* We need to create an attribute to find the syntax. */
  190. test_attr = slapi_attr_new();
  191. slapi_attr_init(test_attr, slapi_value_get_string(value));
  192. /* Get the syntax OID and see if it's the Distinguished Name or
  193. * Name and Optional UID syntax. */
  194. slapi_attr_get_syntax_oid_copy(test_attr, &syntaxoid );
  195. not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID) & strcmp(syntaxoid, NAME_OPT_UID_SYNTAX_OID);
  196. slapi_ch_free_string(&syntaxoid);
  197. /* Print an error if the current attribute is not using the Distinguished
  198. * Name syntax, otherwise get the next group attribute. */
  199. if (not_dn_syntax)
  200. {
  201. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  202. "The %s configuration attribute must be set to "
  203. "an attribute defined to use either the Distinguished "
  204. "Name or Name and Optional UID syntax. (illegal value: %s)",
  205. slapi_value_get_string(value), MEMBEROF_GROUP_ATTR);
  206. }
  207. else
  208. {
  209. hint = slapi_attr_next_value(group_attr, hint, &value);
  210. }
  211. /* Free the group attribute. */
  212. slapi_attr_free(&test_attr);
  213. }
  214. if (not_dn_syntax == 0)
  215. {
  216. /* Check the syntax of the memberof attribute. */
  217. slapi_attr_first_value(memberof_attr, &value);
  218. test_attr = slapi_attr_new();
  219. slapi_attr_init(test_attr, slapi_value_get_string(value));
  220. slapi_attr_get_syntax_oid_copy(test_attr, &syntaxoid );
  221. not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID);
  222. slapi_ch_free_string(&syntaxoid);
  223. slapi_attr_free(&test_attr);
  224. if (not_dn_syntax)
  225. {
  226. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  227. "The %s configuration attribute must be set to "
  228. "an attribute defined to use the Distinguished "
  229. "Name syntax. (illegal value: %s)",
  230. slapi_value_get_string(value), MEMBEROF_ATTR);
  231. goto done;
  232. }
  233. else
  234. {
  235. *returncode = LDAP_SUCCESS;
  236. }
  237. }
  238. } else {
  239. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  240. "The %s and %s configuration attributes must be provided",
  241. MEMBEROF_GROUP_ATTR, MEMBEROF_ATTR);
  242. goto done;
  243. }
  244. if ((skip_nested = slapi_entry_attr_get_charptr(e, MEMBEROF_SKIP_NESTED_ATTR))){
  245. if(strcasecmp(skip_nested, "on") != 0 && strcasecmp(skip_nested, "off") != 0){
  246. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  247. "The %s configuration attribute must be set to "
  248. "\"on\" or \"off\". (illegal value: %s)",
  249. MEMBEROF_SKIP_NESTED_ATTR, skip_nested);
  250. goto done;
  251. }
  252. }
  253. if ((config_dn = slapi_entry_attr_get_charptr(e, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){
  254. /* Now check the shared config attribute, validate it now */
  255. Slapi_Entry *e = NULL;
  256. int rc = 0;
  257. rc = slapi_dn_syntax_check(pb, config_dn, 1);
  258. if (rc) { /* syntax check failed */
  259. slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_validate_config: "
  260. "%s does not contain a valid DN (%s)\n",
  261. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_dn);
  262. *returncode = LDAP_INVALID_DN_SYNTAX;
  263. goto done;
  264. }
  265. config_sdn = slapi_sdn_new_dn_byval(config_dn);
  266. slapi_search_internal_get_entry(config_sdn, NULL, &e, memberof_get_plugin_id());
  267. if(e){
  268. slapi_entry_free(e);
  269. *returncode = LDAP_SUCCESS;
  270. } else {
  271. /* config area does not exist! */
  272. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  273. "The %s configuration attribute points to an entry that "
  274. "can not be found. (%s)",
  275. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_dn);
  276. *returncode = LDAP_UNWILLING_TO_PERFORM;
  277. }
  278. }
  279. done:
  280. slapi_sdn_free(&config_sdn);
  281. slapi_ch_free_string(&config_dn);
  282. slapi_ch_free_string(&skip_nested);
  283. if (*returncode != LDAP_SUCCESS)
  284. {
  285. return SLAPI_DSE_CALLBACK_ERROR;
  286. }
  287. else
  288. {
  289. return SLAPI_DSE_CALLBACK_OK;
  290. }
  291. }
  292. /*
  293. * memberof_apply_config()
  294. *
  295. * Apply the pending changes in the e entry to our config struct.
  296. * memberof_validate_config() must have already been called.
  297. */
  298. int
  299. memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  300. int *returncode, char *returntext, void *arg)
  301. {
  302. Slapi_Entry *config_entry = NULL;
  303. Slapi_DN *config_sdn = NULL;
  304. char **groupattrs = NULL;
  305. char *memberof_attr = NULL;
  306. char *filter_str = NULL;
  307. int num_groupattrs = 0;
  308. int groupattr_name_len = 0;
  309. char *allBackends = NULL;
  310. char *entryScope = NULL;
  311. char *entryScopeExcludeSubtree = NULL;
  312. char *sharedcfg = NULL;
  313. char *skip_nested = NULL;
  314. *returncode = LDAP_SUCCESS;
  315. /*
  316. * Check if this is a shared config entry
  317. */
  318. sharedcfg = slapi_entry_attr_get_charptr(e, SLAPI_PLUGIN_SHARED_CONFIG_AREA);
  319. if(sharedcfg){
  320. if((config_sdn = slapi_sdn_new_dn_byval(sharedcfg))){
  321. slapi_search_internal_get_entry(config_sdn, NULL, &config_entry, memberof_get_plugin_id());
  322. if(config_entry){
  323. /* Set the entry to be the shared config entry. Validation was done in preop */
  324. e = config_entry;
  325. } else {
  326. /* This should of been checked in preop validation */
  327. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  328. "memberof_apply_config: Failed to locate shared config entry (%s)",
  329. sharedcfg);
  330. slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,"%s\n",returntext);
  331. *returncode = LDAP_UNWILLING_TO_PERFORM;
  332. goto done;
  333. }
  334. }
  335. }
  336. /*
  337. * Apply the config settings
  338. */
  339. groupattrs = slapi_entry_attr_get_charray(e, MEMBEROF_GROUP_ATTR);
  340. memberof_attr = slapi_entry_attr_get_charptr(e, MEMBEROF_ATTR);
  341. allBackends = slapi_entry_attr_get_charptr(e, MEMBEROF_BACKEND_ATTR);
  342. entryScope = slapi_entry_attr_get_charptr(e, MEMBEROF_ENTRY_SCOPE_ATTR);
  343. entryScopeExcludeSubtree = slapi_entry_attr_get_charptr(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE);
  344. skip_nested = slapi_entry_attr_get_charptr(e, MEMBEROF_SKIP_NESTED_ATTR);
  345. /*
  346. * We want to be sure we don't change the config in the middle of
  347. * a memberOf operation, so we obtain an exclusive lock here
  348. */
  349. memberof_wlock_config();
  350. if (groupattrs)
  351. {
  352. int i = 0;
  353. slapi_ch_array_free(theConfig.groupattrs);
  354. theConfig.groupattrs = groupattrs;
  355. groupattrs = NULL; /* config now owns memory */
  356. /*
  357. * We allocate a list of Slapi_Attr using the groupattrs for
  358. * convenience in our memberOf comparison functions
  359. */
  360. for (i = 0; theConfig.group_slapiattrs && theConfig.group_slapiattrs[i]; i++)
  361. {
  362. slapi_attr_free(&theConfig.group_slapiattrs[i]);
  363. }
  364. /* Count the number of groupattrs. */
  365. for (num_groupattrs = 0; theConfig.groupattrs && theConfig.groupattrs[num_groupattrs]; num_groupattrs++)
  366. {
  367. /*
  368. * Add up the total length of all attribute names. We need
  369. * to know this for building the group check filter later.
  370. */
  371. groupattr_name_len += strlen(theConfig.groupattrs[num_groupattrs]);
  372. }
  373. /* Realloc the list of Slapi_Attr if necessary. */
  374. if (i < num_groupattrs)
  375. {
  376. theConfig.group_slapiattrs = (Slapi_Attr **)slapi_ch_realloc((char *)theConfig.group_slapiattrs,
  377. sizeof(Slapi_Attr *) * (num_groupattrs + 1));
  378. }
  379. /* Build the new list */
  380. for (i = 0; theConfig.groupattrs[i]; i++)
  381. {
  382. theConfig.group_slapiattrs[i] = slapi_attr_new();
  383. slapi_attr_init(theConfig.group_slapiattrs[i], theConfig.groupattrs[i]);
  384. }
  385. /* Terminate the list. */
  386. theConfig.group_slapiattrs[i] = NULL;
  387. /* The filter is based off of the groupattr, so we update it here too. */
  388. slapi_filter_free(theConfig.group_filter, 1);
  389. if (num_groupattrs > 1)
  390. {
  391. int bytes_out = 0;
  392. int filter_str_len = groupattr_name_len + (num_groupattrs * 4) + 4;
  393. /* Allocate enough space for the filter */
  394. filter_str = slapi_ch_malloc(filter_str_len);
  395. /* Add beginning of filter. */
  396. bytes_out = snprintf(filter_str, filter_str_len - bytes_out, "(|");
  397. /* Add filter section for each groupattr. */
  398. for (i = 0; theConfig.groupattrs[i]; i++)
  399. {
  400. bytes_out += snprintf(filter_str + bytes_out, filter_str_len - bytes_out, "(%s=*)", theConfig.groupattrs[i]);
  401. }
  402. /* Add end of filter. */
  403. snprintf(filter_str + bytes_out, filter_str_len - bytes_out, ")");
  404. }
  405. else
  406. {
  407. filter_str = slapi_ch_smprintf("(%s=*)", theConfig.groupattrs[0]);
  408. }
  409. /*
  410. * Log an error if we were unable to build the group filter for some
  411. * reason. If this happens, the memberOf plugin will not be able to
  412. * check if an entry is a group, causing it to not catch changes. This
  413. * shouldn't happen, but there may be some garbage configuration that
  414. * could trigger this.
  415. */
  416. if ((theConfig.group_filter = slapi_str2filter(filter_str)) == NULL)
  417. {
  418. slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
  419. "Unable to create the group check filter. The memberOf "
  420. "plug-in will not operate on changes to groups. Please check "
  421. "your %s configuration settings. (filter: %s)\n",
  422. MEMBEROF_GROUP_ATTR, filter_str );
  423. }
  424. slapi_ch_free_string(&filter_str);
  425. }
  426. if (memberof_attr)
  427. {
  428. slapi_ch_free_string(&theConfig.memberof_attr);
  429. theConfig.memberof_attr = memberof_attr;
  430. memberof_attr = NULL; /* config now owns memory */
  431. }
  432. if (skip_nested){
  433. if(strcasecmp(skip_nested,"on") == 0){
  434. theConfig.skip_nested = 1;
  435. } else {
  436. theConfig.skip_nested = 0;
  437. }
  438. }
  439. if (allBackends)
  440. {
  441. if(strcasecmp(allBackends,"on")==0){
  442. theConfig.allBackends = 1;
  443. } else {
  444. theConfig.allBackends = 0;
  445. }
  446. } else {
  447. theConfig.allBackends = 0;
  448. }
  449. slapi_sdn_free(&theConfig.entryScope);
  450. if (entryScope)
  451. {
  452. if (slapi_dn_syntax_check(NULL, entryScope, 1) == 1) {
  453. slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
  454. "Error: Ignoring invalid DN used as plugin entry scope: [%s]\n",
  455. entryScope);
  456. theConfig.entryScope = NULL;
  457. slapi_ch_free_string(&entryScope);
  458. } else {
  459. theConfig.entryScope = slapi_sdn_new_dn_passin(entryScope);
  460. }
  461. } else {
  462. theConfig.entryScope = NULL;
  463. }
  464. slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
  465. if (entryScopeExcludeSubtree)
  466. {
  467. if (theConfig.entryScope == NULL) {
  468. slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
  469. "Error: Ignoring ExcludeSubtree (%s) because entryScope is not define\n",
  470. entryScopeExcludeSubtree);
  471. theConfig.entryScopeExcludeSubtree = NULL;
  472. slapi_ch_free_string(&entryScopeExcludeSubtree);
  473. } else if (slapi_dn_syntax_check(NULL, entryScopeExcludeSubtree, 1) == 1) {
  474. slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
  475. "Error: Ignoring invalid DN used as plugin entry exclude subtree: [%s]\n",
  476. entryScopeExcludeSubtree);
  477. theConfig.entryScopeExcludeSubtree = NULL;
  478. slapi_ch_free_string(&entryScopeExcludeSubtree);
  479. } else {
  480. theConfig.entryScopeExcludeSubtree = slapi_sdn_new_dn_passin(entryScopeExcludeSubtree);
  481. }
  482. } else {
  483. theConfig.entryScopeExcludeSubtree = NULL;
  484. }
  485. if (theConfig.entryScopeExcludeSubtree && theConfig.entryScope && !slapi_sdn_issuffix(theConfig.entryScopeExcludeSubtree, theConfig.entryScope)) {
  486. slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
  487. "Error: Ignoring ExcludeSubtree (%s) that is out of the scope (%s)\n",
  488. slapi_sdn_get_dn(theConfig.entryScopeExcludeSubtree),
  489. slapi_sdn_get_dn(theConfig.entryScope));
  490. slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
  491. }
  492. /* release the lock */
  493. memberof_unlock_config();
  494. done:
  495. slapi_sdn_free(&config_sdn);
  496. slapi_entry_free(config_entry);
  497. slapi_ch_array_free(groupattrs);
  498. slapi_ch_free_string(&sharedcfg);
  499. slapi_ch_free_string(&memberof_attr);
  500. slapi_ch_free_string(&allBackends);
  501. slapi_ch_free_string(&skip_nested);
  502. if (*returncode != LDAP_SUCCESS)
  503. {
  504. return SLAPI_DSE_CALLBACK_ERROR;
  505. }
  506. else
  507. {
  508. return SLAPI_DSE_CALLBACK_OK;
  509. }
  510. }
  511. /*
  512. * memberof_copy_config()
  513. *
  514. * Makes a copy of the config in src. This function will free the
  515. * elements of dest if they already exist. This should only be called
  516. * if you hold the memberof config lock if src was obtained with
  517. * memberof_get_config().
  518. */
  519. void
  520. memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
  521. {
  522. if (dest && src)
  523. {
  524. /* Check if the copy is already up to date */
  525. if (src->groupattrs)
  526. {
  527. int i = 0, j = 0;
  528. /* Copy group attributes string list. */
  529. slapi_ch_array_free(dest->groupattrs);
  530. dest->groupattrs = slapi_ch_array_dup(src->groupattrs);
  531. /* Copy group check filter. */
  532. slapi_filter_free(dest->group_filter, 1);
  533. dest->group_filter = slapi_filter_dup(src->group_filter);
  534. /* Copy group attributes Slapi_Attr list.
  535. * First free the old list. */
  536. for (i = 0; dest->group_slapiattrs && dest->group_slapiattrs[i]; i++)
  537. {
  538. slapi_attr_free(&dest->group_slapiattrs[i]);
  539. }
  540. /* Count how many values we have in the source list. */
  541. for (j = 0; src->group_slapiattrs[j]; j++)
  542. {
  543. /* Do nothing. */
  544. }
  545. /* Realloc dest if necessary. */
  546. if (i < j)
  547. {
  548. dest->group_slapiattrs = (Slapi_Attr **)slapi_ch_realloc((char *)dest->group_slapiattrs, sizeof(Slapi_Attr *) * (j + 1));
  549. }
  550. /* Copy the attributes. */
  551. for (i = 0; src->group_slapiattrs[i]; i++)
  552. {
  553. dest->group_slapiattrs[i] = slapi_attr_dup(src->group_slapiattrs[i]);
  554. }
  555. /* Terminate the array. */
  556. dest->group_slapiattrs[i] = NULL;
  557. }
  558. if (src->memberof_attr)
  559. {
  560. slapi_ch_free_string(&dest->memberof_attr);
  561. dest->memberof_attr = slapi_ch_strdup(src->memberof_attr);
  562. }
  563. if(src->skip_nested){
  564. dest->skip_nested = src->skip_nested;
  565. }
  566. if(src->allBackends)
  567. {
  568. dest->allBackends = src->allBackends;
  569. }
  570. }
  571. }
  572. /*
  573. * memberof_free_config()
  574. *
  575. * Free's the contents of a config structure.
  576. */
  577. void
  578. memberof_free_config(MemberOfConfig *config)
  579. {
  580. if (config)
  581. {
  582. int i = 0;
  583. slapi_ch_array_free(config->groupattrs);
  584. slapi_filter_free(config->group_filter, 1);
  585. for (i = 0; config->group_slapiattrs && config->group_slapiattrs[i]; i++)
  586. {
  587. slapi_attr_free(&config->group_slapiattrs[i]);
  588. }
  589. slapi_ch_free((void **)&config->group_slapiattrs);
  590. slapi_ch_free_string(&config->memberof_attr);
  591. }
  592. }
  593. /*
  594. * memberof_get_config()
  595. *
  596. * Returns a pointer to the main config. You should call
  597. * memberof_rlock_config() first so the main config doesn't
  598. * get modified out from under you.
  599. */
  600. MemberOfConfig *
  601. memberof_get_config()
  602. {
  603. return &theConfig;
  604. }
  605. /*
  606. * memberof_rlock_config()
  607. *
  608. * Gets a non-exclusive lock on the main config. This will
  609. * prevent the config from being changed out from under you
  610. * while you read it, but it will still allow other threads
  611. * to read the config at the same time.
  612. */
  613. void
  614. memberof_rlock_config()
  615. {
  616. slapi_rwlock_rdlock(memberof_config_lock);
  617. }
  618. /*
  619. * memberof_wlock_config()
  620. *
  621. * Gets an exclusive lock on the main config. This should
  622. * be called if you need to write to the main config.
  623. */
  624. void
  625. memberof_wlock_config()
  626. {
  627. slapi_rwlock_wrlock(memberof_config_lock);
  628. }
  629. /*
  630. * memberof_unlock_config()
  631. *
  632. * Unlocks the main config.
  633. */
  634. void
  635. memberof_unlock_config()
  636. {
  637. slapi_rwlock_unlock(memberof_config_lock);
  638. }
  639. int
  640. memberof_config_get_all_backends()
  641. {
  642. int all_backends;
  643. slapi_rwlock_rdlock(memberof_config_lock);
  644. all_backends = theConfig.allBackends;
  645. slapi_rwlock_unlock(memberof_config_lock);
  646. return all_backends;
  647. }
  648. Slapi_DN *
  649. memberof_config_get_entry_scope()
  650. {
  651. Slapi_DN *entry_scope;
  652. slapi_rwlock_rdlock(memberof_config_lock);
  653. entry_scope = theConfig.entryScope;
  654. slapi_rwlock_unlock(memberof_config_lock);
  655. return entry_scope;
  656. }
  657. Slapi_DN *
  658. memberof_config_get_entry_scope_exclude_subtree()
  659. {
  660. Slapi_DN *entry_exclude_subtree;
  661. slapi_rwlock_rdlock(memberof_config_lock);
  662. entry_exclude_subtree = theConfig.entryScopeExcludeSubtree;
  663. slapi_rwlock_unlock(memberof_config_lock);
  664. return entry_exclude_subtree;
  665. }
  666. /*
  667. * Check if we are modifying the config, or changing the shared config entry
  668. */
  669. int
  670. memberof_shared_config_validate(Slapi_PBlock *pb)
  671. {
  672. Slapi_Entry *e = 0;
  673. Slapi_Entry *resulting_e = 0;
  674. Slapi_Entry *config_entry = NULL;
  675. Slapi_DN *sdn = NULL;
  676. Slapi_DN *config_sdn = NULL;
  677. Slapi_Mods *smods = 0;
  678. Slapi_Mod *smod = NULL, *nextmod = NULL;
  679. LDAPMod **mods = NULL;
  680. char returntext[SLAPI_DSE_RETURNTEXT_SIZE];
  681. char *configarea_dn = NULL;
  682. int ret = SLAPI_PLUGIN_SUCCESS;
  683. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  684. if (slapi_sdn_compare(sdn, memberof_get_plugin_area()) == 0 ||
  685. slapi_sdn_compare(sdn, memberof_get_config_area()) == 0)
  686. {
  687. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
  688. if(e){
  689. /*
  690. * Create a copy of the entry and apply the
  691. * mods to create the resulting entry.
  692. */
  693. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  694. smods = slapi_mods_new();
  695. slapi_mods_init_byref(smods, mods);
  696. resulting_e = slapi_entry_dup(e);
  697. if (mods && (slapi_entry_apply_mods(resulting_e, mods) != LDAP_SUCCESS)) {
  698. /* we don't care about this, the update is invalid and will be caught later */
  699. goto bail;
  700. }
  701. if (slapi_sdn_compare(sdn, memberof_get_plugin_area())){
  702. /*
  703. * This entry is a plugin config area entry, validate it.
  704. */
  705. if( SLAPI_DSE_CALLBACK_ERROR == memberof_validate_config (pb, NULL, resulting_e, &ret, returntext,0)) {
  706. ret = LDAP_UNWILLING_TO_PERFORM;
  707. }
  708. } else {
  709. /*
  710. * This is the memberOf plugin entry, check if we are adding/replacing the
  711. * plugin config area.
  712. */
  713. nextmod = slapi_mod_new();
  714. for (smod = slapi_mods_get_first_smod(smods, nextmod);
  715. smod != NULL;
  716. smod = slapi_mods_get_next_smod(smods, nextmod) )
  717. {
  718. if ( PL_strcasecmp(SLAPI_PLUGIN_SHARED_CONFIG_AREA, slapi_mod_get_type(smod)) == 0 )
  719. {
  720. /*
  721. * Okay, we are modifying the plugin config area, we only care about
  722. * adds and replaces.
  723. */
  724. if(SLAPI_IS_MOD_REPLACE(slapi_mod_get_operation(smod)) ||
  725. SLAPI_IS_MOD_ADD(slapi_mod_get_operation(smod)))
  726. {
  727. struct berval *bv = NULL;
  728. int rc = 0;
  729. bv = slapi_mod_get_first_value(smod);
  730. configarea_dn = slapi_ch_strdup(bv->bv_val);
  731. if(configarea_dn){
  732. /* Check the DN syntax */
  733. rc = slapi_dn_syntax_check(pb, configarea_dn, 1);
  734. if (rc) { /* syntax check failed */
  735. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  736. "%s does not contain a valid DN (%s)",
  737. SLAPI_PLUGIN_SHARED_CONFIG_AREA, configarea_dn);
  738. ret = LDAP_UNWILLING_TO_PERFORM;
  739. goto bail;
  740. }
  741. /* Check if the plugin config area entry exists */
  742. if((config_sdn = slapi_sdn_new_dn_byval(configarea_dn))){
  743. rc = slapi_search_internal_get_entry(config_sdn, NULL, &config_entry,
  744. memberof_get_plugin_id());
  745. if(config_entry){
  746. int err = 0;
  747. /*
  748. * Validate the settings from the new config area.
  749. */
  750. if ( memberof_validate_config(pb, NULL, config_entry, &err, returntext,0)
  751. == SLAPI_DSE_CALLBACK_ERROR )
  752. {
  753. ret = LDAP_UNWILLING_TO_PERFORM;
  754. goto bail;
  755. }
  756. } else {
  757. /* The config area does not exist */
  758. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  759. "Unable to locate shared config entry (%s) error %d",
  760. slapi_sdn_get_dn(memberof_get_config_area()), rc);
  761. ret = LDAP_UNWILLING_TO_PERFORM;
  762. goto bail;
  763. }
  764. }
  765. }
  766. slapi_ch_free_string(&configarea_dn);
  767. slapi_sdn_free(&config_sdn);
  768. }
  769. }
  770. }
  771. }
  772. } else {
  773. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,"Unable to locate shared config entry (%s)",
  774. slapi_sdn_get_dn(memberof_get_config_area()));
  775. ret = LDAP_UNWILLING_TO_PERFORM;
  776. }
  777. }
  778. bail:
  779. if (ret){
  780. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  781. slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, returntext);
  782. slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_shared_config_validate: %s/n",
  783. returntext);
  784. }
  785. slapi_sdn_free(&config_sdn);
  786. if(nextmod)
  787. slapi_mod_free(&nextmod);
  788. slapi_mods_free(&smods);
  789. slapi_entry_free(resulting_e);
  790. slapi_entry_free(config_entry);
  791. slapi_ch_free_string(&configarea_dn);
  792. return ret;
  793. }