posix-group-func.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /** Author: Carsten Grzemba [email protected]>
  2. *
  3. * Copyright (C) 2011 contac Datentechnik GmbH
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; version 2 only
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. $Id: posix-group-func.c 28 2011-05-13 14:35:29Z grzemba $
  18. */
  19. #include "slapi-plugin.h"
  20. #include "slapi-private.h"
  21. #include <string.h>
  22. #include <nspr.h>
  23. #include "posix-wsp-ident.h"
  24. #define MAX_RECURSION_DEPTH (5)
  25. Slapi_Value **
  26. valueset_get_valuearray(const Slapi_ValueSet *vs); /* stolen from proto-slap.h */
  27. static PRMonitor *memberuid_operation_lock = 0;
  28. void
  29. memberUidLock()
  30. {
  31. PR_EnterMonitor(memberuid_operation_lock);
  32. }
  33. void
  34. memberUidUnlock()
  35. {
  36. PR_ExitMonitor(memberuid_operation_lock);
  37. }
  38. int
  39. memberUidLockInit()
  40. {
  41. return (memberuid_operation_lock = PR_NewMonitor()) != NULL;
  42. }
  43. void
  44. addDynamicGroupIfNecessary(Slapi_Entry *entry, Slapi_Mods *smods) {
  45. Slapi_Attr *oc_attr = NULL;
  46. Slapi_Value *voc = slapi_value_new();
  47. slapi_value_init_string(voc, "dynamicGroup");
  48. slapi_entry_attr_find(entry, "objectClass", &oc_attr);
  49. if (slapi_attr_value_find(oc_attr, slapi_value_get_berval(voc)) != 0) {
  50. if (smods) {
  51. slapi_mods_add_string(smods, LDAP_MOD_ADD, "objectClass", "dynamicGroup");
  52. }
  53. else {
  54. smods = slapi_mods_new();
  55. slapi_mods_add_string(smods, LDAP_MOD_ADD, "objectClass", "dynamicGroup");
  56. Slapi_PBlock *mod_pb = slapi_pblock_new();
  57. slapi_modify_internal_set_pb_ext(mod_pb, slapi_entry_get_sdn(entry), slapi_mods_get_ldapmods_passout(smods), 0, 0,
  58. posix_winsync_get_plugin_identity(), 0);
  59. slapi_modify_internal_pb(mod_pb);
  60. slapi_pblock_destroy(mod_pb);
  61. slapi_mods_free(&smods);
  62. }
  63. }
  64. slapi_value_free(&voc);
  65. }
  66. Slapi_Entry *
  67. getEntry(const char *udn, char **attrs)
  68. {
  69. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "getEntry: search %s\n", udn);
  70. Slapi_DN *udn_sdn = slapi_sdn_new_dn_byval(udn);
  71. Slapi_Entry *result = NULL;
  72. int rc = slapi_search_internal_get_entry(udn_sdn, attrs, &result, posix_winsync_get_plugin_identity());
  73. slapi_sdn_free(&udn_sdn);
  74. if (rc == 0) {
  75. if (result != NULL) {
  76. return result; /* Must be freed */
  77. }
  78. else {
  79. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  80. "getEntry: %s not found\n", udn);
  81. }
  82. }
  83. else {
  84. slapi_log_error(SLAPI_LOG_FATAL, POSIX_WINSYNC_PLUGIN_NAME,
  85. "getEntry: error searching for uid: %d", rc);
  86. }
  87. return NULL;
  88. }
  89. /* search the user with DN udn and returns uid*/
  90. char *
  91. searchUid(const char *udn)
  92. {
  93. char *attrs[] = { "uid", "objectclass", NULL };
  94. Slapi_Entry *entry = getEntry(udn,
  95. /* "(|(objectclass=posixAccount)(objectclass=ldapsubentry))", */
  96. attrs);
  97. char *uid = NULL;
  98. if (entry) {
  99. Slapi_Attr *attr = NULL;
  100. Slapi_Value *v = NULL;
  101. if (slapi_entry_attr_find(entry, "uid", &attr) == 0 && hasObjectClass(entry, "posixAccount")) {
  102. slapi_attr_first_value(attr, &v);
  103. uid = slapi_ch_strdup(slapi_value_get_string(v));
  104. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  105. "searchUid: return uid %s\n", uid);
  106. } else {
  107. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  108. "searchUid: uid in %s not found\n", udn);
  109. }
  110. if (uid && posix_winsync_config_get_lowercase()) {
  111. uid = slapi_dn_ignore_case(uid);
  112. }
  113. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  114. "searchUid: About to free entry\n", udn);
  115. slapi_entry_free(entry);
  116. }
  117. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  118. "searchUid: <==\n", udn);
  119. return uid;
  120. }
  121. int
  122. dn_in_set(const char* uid, char **uids)
  123. {
  124. int i;
  125. Slapi_DN *sdn_uid = NULL;
  126. Slapi_DN *sdn_ul = NULL;
  127. if (uids == NULL || uid == NULL)
  128. return false;
  129. sdn_uid = slapi_sdn_new_dn_byval(uid);
  130. sdn_ul = slapi_sdn_new();
  131. for (i = 0; uids[i]; i++) {
  132. slapi_sdn_set_dn_byref(sdn_ul, uids[i]);
  133. if (slapi_sdn_compare(sdn_uid, sdn_ul) == 0) {
  134. slapi_sdn_free(&sdn_ul);
  135. slapi_sdn_free(&sdn_uid);
  136. return true;
  137. }
  138. slapi_sdn_done(sdn_ul);
  139. }
  140. slapi_sdn_free(&sdn_ul);
  141. slapi_sdn_free(&sdn_uid);
  142. return false;
  143. }
  144. int
  145. uid_in_set(const char* uid, char **uids)
  146. {
  147. int i;
  148. if (uid == NULL)
  149. return false;
  150. for (i = 0; uids != NULL && uids[i] != NULL; i++) {
  151. Slapi_RDN *i_rdn = NULL;
  152. char *i_uid = NULL;
  153. char *t = NULL;
  154. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "uid_in_set: comp %s %s \n",
  155. uid, uids[i]);
  156. i_rdn = slapi_rdn_new_dn(uids[i]);
  157. if (slapi_rdn_get_first(i_rdn, &t, &i_uid) == 1) {
  158. if (strncasecmp(uid, i_uid, 256) == 0) {
  159. slapi_rdn_free(&i_rdn);
  160. return true;
  161. }
  162. }
  163. slapi_rdn_free(&i_rdn);
  164. }
  165. return false;
  166. }
  167. int
  168. uid_in_valueset(const char* uid, Slapi_ValueSet *uids)
  169. {
  170. int i;
  171. Slapi_Value *v = NULL;
  172. if (uid == NULL)
  173. return false;
  174. for (i = slapi_valueset_first_value(uids, &v); i != -1;
  175. i = slapi_valueset_next_value(uids, i, &v)) {
  176. Slapi_RDN *i_rdn = NULL;
  177. char *i_uid = NULL;
  178. char *t = NULL;
  179. const char *uid_i = slapi_value_get_string(v);
  180. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "uid_in_valueset: comp %s %s \n",
  181. uid, uid_i);
  182. i_rdn = slapi_rdn_new_dn(uid_i);
  183. if (slapi_rdn_get_first(i_rdn, &t, &i_uid) == 1) {
  184. if (strncasecmp(uid, i_uid, 256) == 0) {
  185. slapi_rdn_free(&i_rdn);
  186. return true;
  187. }
  188. }
  189. slapi_rdn_free(&i_rdn);
  190. }
  191. return false;
  192. }
  193. /* return 1 if smods already has the given mod - 0 otherwise */
  194. static int
  195. smods_has_mod(Slapi_Mods *smods, int modtype, const char *type, const char *val)
  196. {
  197. int rc = 0;
  198. Slapi_Mod *smod = slapi_mod_new(), *smodp = NULL;
  199. for (smodp = slapi_mods_get_first_smod(smods, smod);
  200. (rc == 0) && smods && (smodp != NULL);
  201. smodp = slapi_mods_get_next_smod(smods, smod)) {
  202. if (slapi_attr_types_equivalent(slapi_mod_get_type(smod), type)
  203. && ((slapi_mod_get_operation(smod) | LDAP_MOD_BVALUES) == (modtype | LDAP_MOD_BVALUES))) {
  204. /* type and op are equal - see if val is in the mod's list of values */
  205. Slapi_Value *sval = slapi_value_new_string((char *) val);
  206. Slapi_Attr *attr = slapi_attr_new();
  207. struct berval *bvp = NULL;
  208. slapi_attr_init(attr, type);
  209. for (bvp = slapi_mod_get_first_value(smodp); (rc == 0) && (bvp != NULL);
  210. bvp = slapi_mod_get_next_value(smodp)) {
  211. Slapi_Value *modval = slapi_value_new_berval(bvp);
  212. rc = (slapi_value_compare(attr, sval, modval) == 0);
  213. slapi_value_free(&modval);
  214. }
  215. slapi_value_free(&sval);
  216. slapi_attr_free(&attr);
  217. }
  218. }
  219. slapi_mod_free(&smod);
  220. return rc;
  221. }
  222. int
  223. hasObjectClass(Slapi_Entry *entry, const char *objectClass)
  224. {
  225. int rc = 0;
  226. int i;
  227. Slapi_Attr *obj_attr = NULL;
  228. Slapi_Value *value = NULL;
  229. rc = slapi_entry_attr_find(entry, "objectclass", &obj_attr);
  230. if (rc != 0) {
  231. return 0; /* Doesn't have any objectclasses */
  232. }
  233. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  234. "Scanning objectclasses\n");
  235. for (
  236. i = slapi_attr_first_value(obj_attr, &value);
  237. i != -1;
  238. i = slapi_attr_next_value(obj_attr, i, &value)
  239. ) {
  240. const char *oc = NULL;
  241. oc = slapi_value_get_string(value);
  242. if (strcasecmp(oc, objectClass) == 0) {
  243. return 1; /* Entry has the desired objectclass */
  244. }
  245. }
  246. return 0; /* Doesn't have desired objectclass */
  247. }
  248. void
  249. posix_winsync_foreach_parent(Slapi_Entry *entry, char **attrs, plugin_search_entry_callback callback, void *callback_data)
  250. {
  251. char *cookie = NULL;
  252. Slapi_Backend *be = NULL;
  253. const char *value = slapi_entry_get_ndn(entry);
  254. size_t vallen = value ? strlen(value) : 0;
  255. char *filter_escaped_value = slapi_ch_calloc(sizeof(char), vallen*3+1);
  256. char *filter = slapi_ch_smprintf("(uniqueMember=%s)", escape_filter_value(value, vallen, filter_escaped_value));
  257. slapi_ch_free_string(&filter_escaped_value);
  258. Slapi_PBlock *search_pb = slapi_pblock_new();
  259. for (be = slapi_get_first_backend(&cookie); be;
  260. be = slapi_get_next_backend(cookie)) {
  261. const Slapi_DN *base_sdn = slapi_be_getsuffix(be, 0);
  262. if (base_sdn == NULL) {
  263. continue;
  264. }
  265. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  266. "posix_winsync_foreach_parent: Searching subtree %s for %s\n",
  267. slapi_sdn_get_dn(base_sdn),
  268. filter);
  269. slapi_search_internal_set_pb(search_pb,
  270. slapi_sdn_get_dn(base_sdn),
  271. LDAP_SCOPE_SUBTREE,
  272. filter,
  273. attrs, 0, NULL, NULL,
  274. posix_winsync_get_plugin_identity(), 0);
  275. slapi_search_internal_callback_pb(search_pb, callback_data, 0, callback, 0);
  276. slapi_pblock_init(search_pb);
  277. }
  278. slapi_pblock_destroy(search_pb);
  279. slapi_ch_free((void**)&cookie);
  280. slapi_ch_free_string(&filter);
  281. }
  282. /* Retrieve nested membership from chains of groups.
  283. * Muid_vs in => any preexisting membership list
  284. * out => the union of the input list and the total membership
  285. * Muid_nested_vs out => the members of muid_vs "out" that weren't in muid_vs "in"
  286. * deletions in => Any elements to NOT consider if members of base_sdn
  287. */
  288. void
  289. getMembershipFromDownward(Slapi_Entry *entry, Slapi_ValueSet *muid_vs, Slapi_ValueSet *muid_nested_vs, Slapi_ValueSet *deletions, const Slapi_DN *base_sdn, int depth)
  290. {
  291. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  292. "getMembershipFromDownward: ==>\n");
  293. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  294. "getMembershipFromDownward: entry name: %s\n",
  295. slapi_entry_get_dn_const(entry));
  296. int rc = 0;
  297. Slapi_Attr *um_attr = NULL; /* Entry attributes uniqueMember */
  298. Slapi_Value *uid_value = NULL; /* uniqueMember attribute values */
  299. if (depth >= MAX_RECURSION_DEPTH) {
  300. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  301. "getMembershipFromDownward: recursion limit reached: %d\n", depth);
  302. return;
  303. }
  304. rc = slapi_entry_attr_find(entry, "uniquemember", &um_attr);
  305. if (rc != 0 || um_attr == NULL) {
  306. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  307. "getMembershipFromDownward end: attribute uniquemember not found\n");
  308. return;
  309. }
  310. int i;
  311. for (i = slapi_attr_first_value(um_attr, &uid_value); i != -1;
  312. i = slapi_attr_next_value(um_attr, i, &uid_value)) {
  313. char *attrs[] = { "uniqueMember", "memberUid", "uid", "objectClass", NULL };
  314. const char *uid_dn = slapi_value_get_string(uid_value);
  315. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  316. "getMembershipFromDownward: iterating uniqueMember: %s\n",
  317. uid_dn);
  318. if (deletions && !slapi_sdn_compare(slapi_entry_get_sdn_const(entry), base_sdn)) {
  319. if (slapi_valueset_find(um_attr, deletions, uid_value)) {
  320. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  321. "getMembershipFromDownward: Skipping iteration because of deletion\n");
  322. continue;
  323. }
  324. }
  325. Slapi_Entry *child = getEntry(uid_dn, attrs);
  326. if (!child) {
  327. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  328. "getMembershipFromDownward end: child not found: %s\n", uid_dn);
  329. }
  330. else {
  331. /* PosixGroups except for the top one are already fully mapped out */
  332. if ((!hasObjectClass(entry, "posixGroup") || depth == 0) &&
  333. (hasObjectClass(child, "ntGroup") || hasObjectClass(child, "posixGroup"))) {
  334. /* Recurse downward */
  335. getMembershipFromDownward(child, muid_vs, muid_nested_vs, deletions, base_sdn, depth + 1);
  336. }
  337. if (hasObjectClass(child, "posixAccount")) {
  338. Slapi_Attr *uid_attr = NULL;
  339. Slapi_Value *v = NULL;
  340. if (slapi_entry_attr_find(child, "uid", &uid_attr) == 0) {
  341. slapi_attr_first_value(uid_attr, &v);
  342. if (v && !slapi_valueset_find(uid_attr, muid_vs, v)) {
  343. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  344. "getMembershipFromDownward: adding member: %s\n",
  345. slapi_value_get_string(v));
  346. slapi_valueset_add_value(muid_vs, v);
  347. slapi_valueset_add_value(muid_nested_vs, v);
  348. }
  349. }
  350. }
  351. slapi_entry_free(child);
  352. }
  353. }
  354. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  355. "getMembershipFromDownward: <==\n");
  356. }
  357. struct propogateMembershipUpwardArgs {
  358. Slapi_ValueSet *muid_vs;
  359. int depth;
  360. };
  361. /* Forward declaration for next function */
  362. void propogateMembershipUpward(Slapi_Entry *, Slapi_ValueSet *, int);
  363. int
  364. propogateMembershipUpwardCallback(Slapi_Entry *child, void *callback_data)
  365. {
  366. struct propogateMembershipUpwardArgs *args = (struct propogateMembershipUpwardArgs *)(callback_data);
  367. propogateMembershipUpward(child, args->muid_vs, args->depth);
  368. return 0;
  369. }
  370. void
  371. propogateMembershipUpward(Slapi_Entry *entry, Slapi_ValueSet *muid_vs, int depth)
  372. {
  373. if (depth >= MAX_RECURSION_DEPTH) {
  374. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  375. "propogateMembershipUpward: recursion limit reached: %d\n", depth);
  376. return;
  377. }
  378. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  379. "propogateMembershipUpward: ==>\n");
  380. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  381. "propogateMembershipUpward: entry name: %s\n",
  382. slapi_entry_get_dn_const(entry));
  383. Slapi_ValueSet *muid_here_vs = NULL;
  384. Slapi_ValueSet *muid_upward_vs = NULL;
  385. /* Get the memberUids at this location, and figure out local changes to memberUid (if any)
  386. * and changes to send upward.
  387. */
  388. if (depth > 0 && hasObjectClass(entry, "posixGroup")) {
  389. int addDynamicGroup = 0;
  390. Slapi_Attr *muid_old_attr = NULL;
  391. Slapi_ValueSet *muid_old_vs = NULL;
  392. int rc = slapi_entry_attr_find(entry, "memberUid", &muid_old_attr);
  393. if (rc != 0 || muid_old_attr == NULL) { /* Found no memberUid list, so create */
  394. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  395. "propogateMembershipUpward: no attribute memberUid\n");
  396. /* There's no values from this entry to add */
  397. muid_upward_vs = muid_vs;
  398. muid_here_vs = muid_vs;
  399. }
  400. else {
  401. int i = 0;
  402. Slapi_Value *v = NULL;
  403. /* Eliminate duplicates */
  404. muid_upward_vs = slapi_valueset_new();
  405. muid_here_vs = slapi_valueset_new();
  406. slapi_attr_get_valueset(muid_old_attr, &muid_old_vs);
  407. slapi_valueset_set_valueset(muid_upward_vs, muid_old_vs);
  408. for (i = slapi_valueset_first_value(muid_vs, &v); i != -1;
  409. i = slapi_valueset_next_value(muid_vs, i, &v)) {
  410. if (!slapi_valueset_find(muid_old_attr, muid_old_vs, v)) {
  411. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  412. "propogateMembershipUpward: adding %s to set\n",
  413. slapi_value_get_string(v));
  414. addDynamicGroup = 1;
  415. slapi_valueset_add_value(muid_here_vs, v);
  416. slapi_valueset_add_value(muid_upward_vs, v);
  417. }
  418. }
  419. }
  420. /* Update this group's membership */
  421. slapi_entry_add_valueset(entry, "memberUid", muid_here_vs);
  422. if (addDynamicGroup) {
  423. addDynamicGroupIfNecessary(entry, NULL);
  424. slapi_entry_add_valueset(entry, "dsOnlyMemberUid", muid_here_vs);
  425. }
  426. }
  427. else {
  428. muid_upward_vs = muid_vs;
  429. }
  430. /* Find groups containing this one, recurse
  431. */
  432. char *attrs[] = {"memberUid", "objectClass", NULL};
  433. struct propogateMembershipUpwardArgs data = {muid_upward_vs, depth + 1};
  434. posix_winsync_foreach_parent(entry, attrs, propogateMembershipUpwardCallback, &data);
  435. /* Cleanup */
  436. if (muid_here_vs && muid_here_vs != muid_vs) {
  437. slapi_valueset_free(muid_here_vs); muid_here_vs = NULL;
  438. }
  439. if (muid_upward_vs && muid_upward_vs != muid_vs) {
  440. slapi_valueset_free(muid_upward_vs); muid_upward_vs = NULL;
  441. }
  442. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  443. "propogateMembershipUpward: <==\n");
  444. }
  445. struct propogateDeletionsUpwardArgs {
  446. const Slapi_DN *base_sdn;
  447. Slapi_ValueSet *smod_deluids;
  448. Slapi_ValueSet *del_nested_vs;
  449. int depth;
  450. };
  451. /* Forward declaration for next function */
  452. void propogateDeletionsUpward(Slapi_Entry *, const Slapi_DN *, Slapi_ValueSet*, Slapi_ValueSet *, int);
  453. int
  454. propogateDeletionsUpwardCallback(Slapi_Entry *entry, void *callback_data)
  455. {
  456. struct propogateDeletionsUpwardArgs *args = (struct propogateDeletionsUpwardArgs *)(callback_data);
  457. propogateDeletionsUpward(entry, args->base_sdn, args->smod_deluids, args->del_nested_vs, args->depth);
  458. return 0;
  459. }
  460. void
  461. propogateDeletionsUpward(Slapi_Entry *entry, const Slapi_DN *base_sdn, Slapi_ValueSet *smod_deluids, Slapi_ValueSet *del_nested_vs, int depth)
  462. {
  463. if (smod_deluids == NULL) return;
  464. if (depth >= MAX_RECURSION_DEPTH) {
  465. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  466. "propogateDeletionsUpward: recursion limit reached: %d\n", depth);
  467. return;
  468. }
  469. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  470. "propogateDeletionsUpward: ==>\n");
  471. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  472. "propogateDeletionsUpward: entry name: %s\n",
  473. slapi_entry_get_dn_const(entry));
  474. char *attrs[] = { "uniqueMember", "memberUid", "objectClass", NULL };
  475. struct propogateDeletionsUpwardArgs data = {base_sdn, smod_deluids, del_nested_vs, depth + 1};
  476. posix_winsync_foreach_parent(entry, attrs, propogateDeletionsUpwardCallback, &data);
  477. Slapi_Attr *muid_attr = NULL;
  478. int rc = slapi_entry_attr_find(entry, "dsOnlyMemberUid", &muid_attr);
  479. if (rc == 0 && muid_attr != NULL) {
  480. Slapi_ValueSet *muid_vs = slapi_valueset_new();
  481. Slapi_ValueSet *muid_nested_vs = slapi_valueset_new();
  482. Slapi_ValueSet *muid_deletions_vs = slapi_valueset_new();
  483. getMembershipFromDownward(entry, muid_vs, muid_nested_vs, smod_deluids, base_sdn, 0);
  484. int i;
  485. Slapi_Value *v;
  486. for (i = slapi_attr_first_value(muid_attr, &v); i != -1;
  487. i = slapi_attr_next_value(muid_attr, i, &v)) {
  488. if (!slapi_valueset_find(muid_attr, muid_vs, v)) {
  489. const char *uid = slapi_value_get_string(v);
  490. if (depth == 0 && !uid_in_valueset(uid, smod_deluids)) {
  491. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  492. "propogateDeletionsUpward: Adding deletion to modlist: %s\n",
  493. slapi_value_get_string(v));
  494. slapi_valueset_add_value(del_nested_vs, v);
  495. }
  496. else if (depth > 0) {
  497. slapi_valueset_add_value(muid_deletions_vs, v);
  498. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  499. "propogateDeletionsUpward: Adding deletion to deletion list: %s\n",
  500. slapi_value_get_string(v));
  501. }
  502. }
  503. }
  504. if (depth > 0) {
  505. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  506. "propogateDeletionsUpward: executing deletion list\n");
  507. Slapi_Mods *smods = slapi_mods_new();
  508. slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, "memberuid", valueset_get_valuearray(muid_deletions_vs));
  509. slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, "dsonlymemberuid", valueset_get_valuearray(muid_deletions_vs));
  510. Slapi_PBlock *mod_pb = slapi_pblock_new();
  511. slapi_modify_internal_set_pb_ext(mod_pb, slapi_entry_get_sdn(entry), slapi_mods_get_ldapmods_passout(smods), 0, 0,
  512. posix_winsync_get_plugin_identity(), 0);
  513. slapi_modify_internal_pb(mod_pb);
  514. slapi_pblock_destroy(mod_pb);
  515. slapi_mods_free(&smods);
  516. }
  517. slapi_valueset_free(muid_vs); muid_vs = NULL;
  518. slapi_valueset_free(muid_nested_vs); muid_nested_vs = NULL;
  519. slapi_valueset_free(muid_deletions_vs); muid_deletions_vs = NULL;
  520. }
  521. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  522. "propogateDeletionsUpward: <==\n");
  523. }
  524. int
  525. modGroupMembership(Slapi_Entry *entry, Slapi_Mods *smods, int *do_modify)
  526. {
  527. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "modGroupMembership: ==>\n");
  528. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "modGroupMembership: Modding %s\n",
  529. slapi_entry_get_dn_const(entry));
  530. int posixGroup = hasObjectClass(entry, "posixGroup");
  531. if (!(posixGroup || hasObjectClass(entry, "ntGroup"))) {
  532. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  533. "modGroupMembership end: Not a posixGroup or ntGroup\n");
  534. return 0;
  535. }
  536. Slapi_Mod *smod = NULL;
  537. Slapi_Mod *nextMod = slapi_mod_new();
  538. int del_mod = 0; /* Bool: was there a delete mod? */
  539. char **smod_adduids = NULL;
  540. Slapi_ValueSet *smod_deluids = NULL;
  541. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  542. "modGroupMembership: posixGroup -> look for uniquemember\n");
  543. if (slapi_is_loglevel_set(SLAPI_LOG_PLUGIN))
  544. slapi_mods_dump(smods, "memberUid - mods dump - initial");
  545. for (smod = slapi_mods_get_first_smod(smods, nextMod); smod; smod
  546. = slapi_mods_get_next_smod(smods, nextMod)) {
  547. if (slapi_attr_types_equivalent(slapi_mod_get_type(smod), "uniqueMember")) {
  548. struct berval *bv;
  549. int current_del_mod = SLAPI_IS_MOD_DELETE(slapi_mod_get_operation(smod));
  550. if (current_del_mod) {
  551. del_mod = 1;
  552. }
  553. for (bv = slapi_mod_get_first_value(smod); bv;
  554. bv = slapi_mod_get_next_value(smod)) {
  555. Slapi_Value *sv = slapi_value_new();
  556. slapi_value_init_berval(sv, bv); /* copies bv_val */
  557. if (current_del_mod) {
  558. if (!smod_deluids) smod_deluids = slapi_valueset_new();
  559. slapi_valueset_add_value(smod_deluids, sv);
  560. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  561. "modGroupMembership: add to deluids %s\n",
  562. bv->bv_val);
  563. } else {
  564. slapi_ch_array_add(&smod_adduids,
  565. slapi_ch_strdup(slapi_value_get_string(sv)));
  566. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  567. "modGroupMembership: add to adduids %s\n",
  568. bv->bv_val);
  569. }
  570. slapi_value_free(&sv);
  571. }
  572. }
  573. }
  574. slapi_mod_free(&nextMod);
  575. int muid_rc = 0;
  576. Slapi_Attr * muid_attr = NULL; /* Entry attributes */
  577. Slapi_ValueSet *muid_vs = NULL;
  578. Slapi_Value * uid_value = NULL; /* Attribute values */
  579. Slapi_ValueSet *adduids = slapi_valueset_new();
  580. Slapi_ValueSet *add_nested_vs = slapi_valueset_new();
  581. Slapi_ValueSet *deluids = slapi_valueset_new();
  582. Slapi_ValueSet *del_nested_vs = slapi_valueset_new();
  583. const Slapi_DN *base_sdn = slapi_entry_get_sdn_const(entry);
  584. int j = 0;
  585. if (del_mod || smod_deluids != NULL) {
  586. do { /* Create a context to "break" from */
  587. muid_rc = slapi_entry_attr_find(entry, "memberUid", &muid_attr);
  588. if (smod_deluids == NULL) { /* deletion of the last value, deletes the Attribut from entry complete, this operation has no value, so we must look by self */
  589. Slapi_Attr * um_attr = NULL; /* Entry attributes */
  590. Slapi_Value * uid_dn_value = NULL; /* Attribute values */
  591. int rc = slapi_entry_attr_find(entry, "uniquemember", &um_attr);
  592. if (rc != 0 || um_attr == NULL) {
  593. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  594. "modGroupMembership end: attribute uniquemember not found\n");
  595. break;
  596. }
  597. slapi_attr_get_valueset(um_attr, &smod_deluids);
  598. }
  599. if (muid_rc != 0 || muid_attr == NULL) {
  600. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  601. "modGroupMembership end: attribute memberUid not found\n");
  602. }
  603. else if (posix_winsync_config_get_mapMemberUid()) {
  604. /* ...loop for value... */
  605. for (j = slapi_attr_first_value(muid_attr, &uid_value); j != -1;
  606. j = slapi_attr_next_value(muid_attr, j, &uid_value)) {
  607. /* remove from uniquemember: remove from memberUid also */
  608. const char *uid = NULL;
  609. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  610. "modGroupMembership: test dellist \n");
  611. uid = slapi_value_get_string(uid_value);
  612. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  613. "modGroupMembership: test dellist %s\n", uid);
  614. if (uid_in_valueset(uid, smod_deluids)) {
  615. slapi_valueset_add_value(deluids, uid_value);
  616. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  617. "modGroupMembership: add to dellist %s\n", uid);
  618. }
  619. }
  620. }
  621. if (posix_winsync_config_get_mapNestedGrouping()) {
  622. propogateDeletionsUpward(entry, base_sdn, smod_deluids, del_nested_vs, 0);
  623. int i;
  624. Slapi_Value *v;
  625. for (i = slapi_valueset_first_value(del_nested_vs, &v); i != -1;
  626. i = slapi_valueset_next_value(del_nested_vs, i, &v)) {
  627. slapi_valueset_add_value(deluids, v);
  628. }
  629. }
  630. } while (false);
  631. }
  632. if (smod_adduids != NULL) { /* not MOD_DELETE */
  633. const char *uid_dn = NULL;
  634. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  635. "modGroupMembership: posixGroup -> look for uniquemember\n");
  636. if (muid_rc == 0 && muid_attr == NULL) {
  637. muid_rc = slapi_entry_attr_find(entry, "memberUid", &muid_attr);
  638. }
  639. if (muid_rc == 0 && muid_attr != NULL) {
  640. slapi_attr_get_valueset(muid_attr, &muid_vs);
  641. }
  642. else {
  643. muid_vs = slapi_valueset_new();
  644. }
  645. if (posix_winsync_config_get_mapMemberUid()) {
  646. for (j = 0; smod_adduids[j]; j++) {
  647. static char *uid = NULL;
  648. uid_dn = smod_adduids[j];
  649. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  650. "modGroupMembership: perform user %s\n", uid_dn);
  651. uid = searchUid(uid_dn);
  652. if (uid == NULL) {
  653. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  654. "modGroupMembership: uid not found for %s, cannot do anything\n",
  655. uid_dn); /* member on longer on server, do nothing */
  656. } else {
  657. Slapi_Value *v = slapi_value_new();
  658. slapi_value_init_string_passin(v, uid);
  659. if (muid_rc == 0 && muid_attr != NULL &&
  660. slapi_valueset_find(muid_attr, muid_vs, v) != NULL) {
  661. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  662. "modGroupMembership: uid found in memberuid list %s nothing to do\n",
  663. uid);
  664. }
  665. else {
  666. slapi_valueset_add_value(adduids, v);
  667. slapi_valueset_add_value(muid_vs, v);
  668. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  669. "modGroupMembership: add to modlist %s\n", uid);
  670. }
  671. slapi_value_free(&v); /* also frees uid since it was a passin */
  672. }
  673. }
  674. }
  675. if (posix_winsync_config_get_mapNestedGrouping()) {
  676. for (j = 0; smod_adduids[j]; ++j) {
  677. char *attrs[] = { "uniqueMember", "memberUid", "uid", "objectClass", NULL };
  678. Slapi_Entry *child = getEntry(smod_adduids[j], attrs);
  679. if (child) {
  680. if (hasObjectClass(child, "ntGroup") || hasObjectClass(child, "posixGroup")) {
  681. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  682. "modGroupMembership: Found mod to add group, adding membership: %s\n",
  683. smod_adduids[j]);
  684. Slapi_ValueSet *muid_tempnested = slapi_valueset_new();
  685. getMembershipFromDownward(child, muid_vs, add_nested_vs, smod_deluids, base_sdn, 0);
  686. slapi_valueset_free(muid_tempnested); muid_tempnested = NULL;
  687. }
  688. }
  689. else {
  690. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  691. "modGroupMembership: entry not found for dn: %s\n",
  692. smod_adduids[j]);
  693. }
  694. }
  695. getMembershipFromDownward(entry, muid_vs, add_nested_vs, smod_deluids, base_sdn, 0);
  696. int i = 0;
  697. Slapi_Value *v = NULL;
  698. for (i = slapi_valueset_first_value(add_nested_vs, &v); i != -1;
  699. i = slapi_valueset_next_value(add_nested_vs, i, &v)) {
  700. slapi_valueset_add_value(adduids, v);
  701. }
  702. propogateMembershipUpward(entry, adduids, 0);
  703. }
  704. }
  705. if (posixGroup) {
  706. int addDynamicGroup = 0;
  707. int i;
  708. Slapi_Value *v;
  709. for (i = slapi_valueset_first_value(adduids, &v); i != -1;
  710. i = slapi_valueset_next_value(adduids, i, &v)){
  711. const char *muid = slapi_value_get_string(v);
  712. if (!smods_has_mod(smods, LDAP_MOD_ADD, "memberUid", muid)) {
  713. *do_modify = 1;
  714. slapi_mods_add_string(smods, LDAP_MOD_ADD, "memberUid", muid);
  715. }
  716. }
  717. for (i = slapi_valueset_first_value(add_nested_vs, &v); i != -1;
  718. i = slapi_valueset_next_value(add_nested_vs, i, &v)) {
  719. const char *muid = slapi_value_get_string(v);
  720. if (!smods_has_mod(smods, LDAP_MOD_ADD, "dsOnlyMemberUid", muid)) {
  721. addDynamicGroup = 1;
  722. *do_modify = 1;
  723. slapi_mods_add_string(smods, LDAP_MOD_ADD, "dsOnlyMemberUid", muid);
  724. }
  725. }
  726. for (i = slapi_valueset_first_value(deluids, &v); i != -1;
  727. i = slapi_valueset_next_value(deluids, i, &v)){
  728. const char *muid = slapi_value_get_string(v);
  729. if (!smods_has_mod(smods, LDAP_MOD_DELETE, "memberUid", muid)) {
  730. *do_modify = 1;
  731. slapi_mods_add_string(smods, LDAP_MOD_DELETE, "memberUid", muid);
  732. }
  733. }
  734. for (i = slapi_valueset_first_value(del_nested_vs, &v); i != -1;
  735. i = slapi_valueset_next_value(del_nested_vs, i, &v)){
  736. const char *muid = slapi_value_get_string(v);
  737. if (!smods_has_mod(smods, LDAP_MOD_DELETE, "dsOnlyMemberUid", muid)) {
  738. *do_modify = 1;
  739. slapi_mods_add_string(smods, LDAP_MOD_DELETE, "dsOnlyMemberUid", muid);
  740. }
  741. }
  742. if (addDynamicGroup) {
  743. addDynamicGroupIfNecessary(entry, smods);
  744. }
  745. if (slapi_is_loglevel_set(SLAPI_LOG_PLUGIN))
  746. slapi_mods_dump(smods, "memberUid - mods dump");
  747. posix_winsync_config_set_MOFTaskCreated();
  748. }
  749. slapi_ch_array_free(smod_adduids);
  750. smod_adduids = NULL;
  751. if (smod_deluids) slapi_valueset_free(smod_deluids);
  752. smod_deluids = NULL;
  753. slapi_valueset_free(adduids);
  754. adduids = NULL;
  755. slapi_valueset_free(deluids);
  756. deluids = NULL;
  757. slapi_valueset_free(add_nested_vs); add_nested_vs = NULL;
  758. slapi_valueset_free(del_nested_vs); del_nested_vs = NULL;
  759. if (muid_vs) {
  760. slapi_valueset_free(muid_vs); muid_vs = NULL;
  761. }
  762. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "modGroupMembership: <==\n");
  763. return 0;
  764. }
  765. int
  766. addUserToGroupMembership(Slapi_Entry *entry)
  767. {
  768. Slapi_Attr *uid_attr = NULL;
  769. Slapi_Value *v = NULL;
  770. Slapi_ValueSet *muid_vs = slapi_valueset_new();
  771. if (slapi_entry_attr_find(entry, "uid", &uid_attr) == 0) {
  772. slapi_attr_first_value(uid_attr, &v);
  773. if (v) {
  774. slapi_valueset_add_value(muid_vs, v);
  775. }
  776. }
  777. propogateMembershipUpward(entry, muid_vs, 0);
  778. slapi_valueset_free(muid_vs); muid_vs = NULL;
  779. return 0;
  780. }
  781. int
  782. addGroupMembership(Slapi_Entry *entry, Slapi_Entry *ad_entry)
  783. {
  784. int rc = 0;
  785. int i;
  786. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "addGroupMembership: ==>\n");
  787. int posixGroup = hasObjectClass(entry, "posixGroup");
  788. if(!(posixGroup || hasObjectClass(entry, "ntGroup"))) {
  789. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  790. "addGroupMembership: didn't find posixGroup or ntGroup objectclass\n");
  791. return 0;
  792. }
  793. Slapi_Attr * um_attr = NULL; /* Entry attributes uniquemember */
  794. Slapi_Attr * muid_attr = NULL; /* Entry attributes memebrof */
  795. Slapi_Value * uid_value = NULL; /* uniquemember Attribute values */
  796. Slapi_ValueSet *newvs = NULL;
  797. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  798. "addGroupMembership: posixGroup -> look for uniquemember\n");
  799. rc = slapi_entry_attr_find(entry, "uniquemember", &um_attr);
  800. if (rc != 0 || um_attr == NULL) {
  801. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  802. "addGroupMembership end: attribute uniquemember not found\n");
  803. return 0;
  804. }
  805. /* found attribute uniquemember */
  806. rc = slapi_entry_attr_find(entry, "memberUid", &muid_attr);
  807. if (rc != 0 || muid_attr == NULL) { /* Found no memberUid list, so create */
  808. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  809. "addGroupMembership: no attribute memberUid\n");
  810. muid_attr = NULL;
  811. }
  812. newvs = slapi_valueset_new();
  813. /* ...loop for value... */
  814. if (posix_winsync_config_get_mapMemberUid()) {
  815. for (i = slapi_attr_first_value(um_attr, &uid_value); i != -1;
  816. i = slapi_attr_next_value(um_attr, i, &uid_value)) {
  817. const char *uid_dn = NULL;
  818. static char *uid = NULL;
  819. Slapi_Value *v = NULL;
  820. uid_dn = slapi_value_get_string(uid_value);
  821. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  822. "addGroupMembership: perform member %s\n", uid_dn);
  823. uid = searchUid(uid_dn);
  824. if (uid == NULL) {
  825. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  826. "addGroupMembership: uid not found for %s, cannot do anything\n",
  827. uid_dn); /* member on longer on server, do nothing */
  828. } else {
  829. v = slapi_value_new_string(uid);
  830. slapi_ch_free_string(&uid);
  831. if (slapi_attr_value_find(muid_attr, slapi_value_get_berval(v)) != 0) {
  832. slapi_valueset_add_value(newvs, v);
  833. }
  834. slapi_value_free(&v);
  835. }
  836. }
  837. }
  838. if (posix_winsync_config_get_mapNestedGrouping()) {
  839. Slapi_ValueSet *muid_nested_vs = slapi_valueset_new();
  840. getMembershipFromDownward(entry, newvs, muid_nested_vs, NULL, NULL, 0);
  841. propogateMembershipUpward(entry, newvs, 0);
  842. if (posixGroup) {
  843. addDynamicGroupIfNecessary(entry, NULL);
  844. slapi_entry_add_valueset(entry, "dsOnlyMemberUid", muid_nested_vs);
  845. }
  846. slapi_valueset_free(muid_nested_vs); muid_nested_vs = NULL;
  847. }
  848. if (posixGroup) {
  849. slapi_entry_add_valueset(entry, "memberUid", newvs);
  850. }
  851. slapi_valueset_free(newvs); newvs = NULL;
  852. posix_winsync_config_get_MOFTaskCreated();
  853. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "addGroupMembership: <==\n");
  854. return 0;
  855. }