posix-group-task.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. #include <string.h>
  2. #include "posix-wsp-ident.h"
  3. #include "posix-group-func.h"
  4. #include "slapi-plugin.h"
  5. typedef struct _task_data
  6. {
  7. char *dn; /* search base */
  8. char *filter_str; /* search filter */
  9. } task_data;
  10. typedef struct _cb_data
  11. {
  12. char *dn;
  13. void *txn;
  14. } cb_data;
  15. /*
  16. typedef struct _posix_group_task_data
  17. {
  18. POSIX_WinSync_Config *config;
  19. Slapi_Value *memberdn_val;
  20. Slapi_ValueSet **uidvals;
  21. void *txn;
  22. } posix_group_data_data;
  23. */
  24. Slapi_Value **
  25. valueset_get_valuearray(const Slapi_ValueSet *vs); /* stolen from proto-slap.h */
  26. /* interface function */
  27. int
  28. posix_group_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
  29. Slapi_Entry *
  30. getEntry(const char *udn, char **attrs);
  31. static void
  32. posix_group_task_destructor(Slapi_Task *task);
  33. static void
  34. posix_group_fixup_task_thread(void *arg);
  35. static int
  36. posix_group_fix_memberuid_callback(Slapi_Entry *e, void *callback_data);
  37. /* extract a single value from the entry (as a string) -- if it's not in the
  38. * entry, the default will be returned (which can be NULL).
  39. * you do not need to free anything returned by this.
  40. */
  41. static const char *
  42. fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val)
  43. {
  44. Slapi_Attr *attr;
  45. Slapi_Value *val = NULL;
  46. if (slapi_entry_attr_find(e, attrname, &attr) != 0)
  47. return default_val;
  48. slapi_attr_first_value(attr, &val);
  49. return slapi_value_get_string(val);
  50. }
  51. /* e configEntry */
  52. int
  53. posix_group_task_add(Slapi_PBlock *pb __attribute__((unused)),
  54. Slapi_Entry *e,
  55. Slapi_Entry *eAfter __attribute__((unused)),
  56. int *returncode,
  57. char *returntext __attribute__((unused)),
  58. void *arg __attribute__((unused)))
  59. {
  60. PRThread *thread = NULL;
  61. int rv = SLAPI_DSE_CALLBACK_OK;
  62. task_data *mytaskdata = NULL;
  63. Slapi_Task *task = NULL;
  64. const char *filter;
  65. const char *dn = 0;
  66. *returncode = LDAP_SUCCESS;
  67. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  68. "posix_group_task_add: ==>\n");
  69. /* get arg(s) */
  70. /* default: set replication basedn */
  71. if ((dn = fetch_attr(e, "basedn", slapi_sdn_get_dn(posix_winsync_config_get_suffix()))) == NULL) {
  72. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  73. rv = SLAPI_DSE_CALLBACK_ERROR;
  74. goto out;
  75. }
  76. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  77. "posix_group_task_add: retrieved basedn: %s\n", dn);
  78. if ((filter = fetch_attr(e, "filter", "(&(objectclass=ntGroup)(|(uniquemember=*)(memberuid=*)))")) == NULL) {
  79. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  80. rv = SLAPI_DSE_CALLBACK_ERROR;
  81. goto out;
  82. }
  83. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  84. "posix_group_task_add: retrieved filter: %s\n", filter);
  85. /* setup our task data */
  86. mytaskdata = (task_data *)slapi_ch_malloc(sizeof(task_data));
  87. if (mytaskdata == NULL) {
  88. *returncode = LDAP_OPERATIONS_ERROR;
  89. rv = SLAPI_DSE_CALLBACK_ERROR;
  90. goto out;
  91. }
  92. mytaskdata->dn = slapi_ch_strdup(dn);
  93. mytaskdata->filter_str = slapi_ch_strdup(filter);
  94. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  95. "posix_group_task_add: task data allocated\n");
  96. /* allocate new task now */
  97. char *ndn = slapi_entry_get_ndn(e);
  98. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  99. "posix_group_task_add: creating task object: %s\n",
  100. ndn);
  101. task = slapi_new_task(ndn);
  102. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  103. "posix_group_task_add: task object created\n");
  104. /* register our destructor for cleaning up our private data */
  105. slapi_task_set_destructor_fn(task, posix_group_task_destructor);
  106. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  107. "posix_group_task_add: task destructor set\n");
  108. /* Stash a pointer to our data in the task */
  109. slapi_task_set_data(task, mytaskdata);
  110. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  111. "posix_group_task_add: task object initialized\n");
  112. /* start the sample task as a separate thread */
  113. thread = PR_CreateThread(PR_USER_THREAD, posix_group_fixup_task_thread, (void *)task,
  114. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
  115. SLAPD_DEFAULT_THREAD_STACKSIZE);
  116. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  117. "posix_group_task_add: thread created\n");
  118. if (thread == NULL) {
  119. slapi_log_err(SLAPI_LOG_ERR, POSIX_WINSYNC_PLUGIN_NAME,
  120. "posix_group_task_add: unable to create task thread!\n");
  121. *returncode = LDAP_OPERATIONS_ERROR;
  122. rv = SLAPI_DSE_CALLBACK_ERROR;
  123. slapi_task_finish(task, *returncode);
  124. } else {
  125. rv = SLAPI_DSE_CALLBACK_OK;
  126. }
  127. out:
  128. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  129. "posix_group_task_add: <==\n");
  130. return rv;
  131. }
  132. static void
  133. posix_group_task_destructor(Slapi_Task *task)
  134. {
  135. if (task) {
  136. task_data *mydata = (task_data *)slapi_task_get_data(task);
  137. while (slapi_task_get_refcount(task) > 0) {
  138. /* Yield to wait for the fixup task finishes. */
  139. DS_Sleep(PR_MillisecondsToInterval(100));
  140. }
  141. if (mydata) {
  142. slapi_ch_free_string(&mydata->dn);
  143. slapi_ch_free_string(&mydata->filter_str);
  144. /* Need to cast to avoid a compiler warning */
  145. slapi_ch_free((void **)&mydata);
  146. }
  147. }
  148. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  149. "posix_group_task_destructor <--\n");
  150. }
  151. #if 0 /* NOT USED */
  152. static int
  153. posix_group_del_memberuid_callback(Slapi_Entry *e, void *callback_data)
  154. {
  155. int rc = 0;
  156. LDAPMod mod;
  157. LDAPMod *mods[2];
  158. char *val[2];
  159. Slapi_PBlock *mod_pb = 0;
  160. cb_data *the_cb_data = (cb_data *) callback_data;
  161. mod_pb = slapi_pblock_new();
  162. mods[0] = &mod;
  163. mods[1] = 0;
  164. val[0] = 0; /* all */
  165. val[1] = 0;
  166. mod.mod_op = LDAP_MOD_DELETE;
  167. mod.mod_type = "memberuid";
  168. mod.mod_values = val;
  169. slapi_modify_internal_set_pb_ext(mod_pb, slapi_entry_get_sdn(e), mods, 0, 0,
  170. posix_winsync_get_plugin_identity(), 0);
  171. slapi_pblock_set(mod_pb, SLAPI_TXN, the_cb_data->txn);
  172. slapi_modify_internal_pb(mod_pb);
  173. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  174. slapi_pblock_destroy(mod_pb);
  175. return rc;
  176. }
  177. #endif
  178. static int
  179. posix_group_fix_memberuid(char *dn, char *filter_str, void *txn)
  180. {
  181. int rc = 0;
  182. struct _cb_data callback_data = {dn, txn};
  183. Slapi_PBlock *search_pb = slapi_pblock_new();
  184. /* char *attrs[]={"uniquemember","memberuid",NULL}; */
  185. slapi_search_internal_set_pb(search_pb, dn, LDAP_SCOPE_SUBTREE, filter_str, 0, 0, 0, 0,
  186. posix_winsync_get_plugin_identity(), 0);
  187. slapi_pblock_set(search_pb, SLAPI_TXN, txn); /* set transaction id */
  188. rc = slapi_search_internal_callback_pb(search_pb, &callback_data, 0,
  189. posix_group_fix_memberuid_callback, 0);
  190. slapi_pblock_destroy(search_pb);
  191. return rc;
  192. }
  193. /* posix_group_fix_memberuid_callback()
  194. * Add initial and/or fix up broken group list in entry
  195. *
  196. * 1. forall uniquemember search if posixAccount ? add uid : ""
  197. */
  198. static int
  199. posix_group_fix_memberuid_callback(Slapi_Entry *e, void *callback_data)
  200. {
  201. int i;
  202. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  203. "_fix_memberuid ==>\n");
  204. cb_data *the_cb_data = (cb_data *)callback_data;
  205. int rc = 0;
  206. Slapi_Attr *muid_attr = NULL;
  207. Slapi_Value *v = NULL;
  208. Slapi_Mods *smods = NULL;
  209. char *dn = NULL;
  210. Slapi_DN *sdn = NULL;
  211. LDAPMod **mods = NULL;
  212. int is_posix_group = 0;
  213. /*
  214. * If the server is ordered to shutdown, stop the fixup and return an error.
  215. */
  216. if (slapi_is_shutting_down()) {
  217. rc = -1;
  218. goto bail;
  219. }
  220. smods = slapi_mods_new();
  221. dn = slapi_entry_get_dn(e);
  222. sdn = slapi_entry_get_sdn(e);
  223. if (hasObjectClass(e, "posixGroup")) {
  224. is_posix_group = 1;
  225. }
  226. /* Clean out memberuids and dsonlymemberuids without a valid referant */
  227. rc = slapi_entry_attr_find(e, "memberuid", &muid_attr);
  228. if (rc == 0 && muid_attr) {
  229. Slapi_PBlock *search_pb = slapi_pblock_new();
  230. Slapi_Attr *dsmuid_attr = NULL;
  231. Slapi_ValueSet *dsmuid_vs = NULL;
  232. char *attrs[] = {"uid", NULL};
  233. rc = slapi_entry_attr_find(e, "dsonlymemberuid", &dsmuid_attr);
  234. if (rc == 0 && dsmuid_attr) {
  235. slapi_attr_get_valueset(dsmuid_attr, &dsmuid_vs);
  236. }
  237. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  238. "_fix_memberuid scan for orphaned memberuids\n");
  239. for (i = slapi_attr_first_value(muid_attr, &v); i != -1;
  240. i = slapi_attr_next_value(muid_attr, i, &v)) {
  241. char *muid = (char *)slapi_value_get_string(v);
  242. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  243. "_fix_memberuid iterating memberuid: %s\n",
  244. muid);
  245. size_t vallen = muid ? strlen(muid) : 0;
  246. char *filter_escaped_value = slapi_escape_filter_value(muid, vallen);
  247. char *filter = slapi_ch_smprintf("(uid=%s)", filter_escaped_value);
  248. slapi_ch_free_string(&filter_escaped_value);
  249. Slapi_Entry **search_entries = NULL;
  250. slapi_search_internal_set_pb(search_pb,
  251. the_cb_data->dn,
  252. LDAP_SCOPE_SUBTREE,
  253. filter,
  254. attrs, 0, NULL, NULL,
  255. posix_winsync_get_plugin_identity(), 0);
  256. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  257. "_fix_memberuid searching %s with filter: %s\n",
  258. the_cb_data->dn, filter);
  259. rc = slapi_search_internal_pb(search_pb);
  260. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &search_entries);
  261. if (!search_entries || !search_entries[0]) {
  262. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  263. "_fix_memberuid Adding bad memberuid %s\n",
  264. slapi_value_get_string(v));
  265. slapi_mods_add_string(smods, LDAP_MOD_DELETE, "memberuid", slapi_value_get_string(v));
  266. if (dsmuid_vs && slapi_valueset_find(dsmuid_attr, dsmuid_vs, v)) {
  267. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  268. "_fix_memberuid Adding bad dsonlymemberuid %s\n",
  269. slapi_value_get_string(v));
  270. slapi_mods_add_string(smods, LDAP_MOD_DELETE, "dsonlymemberuid", slapi_value_get_string(v));
  271. }
  272. }
  273. slapi_free_search_results_internal(search_pb);
  274. slapi_pblock_init(search_pb);
  275. slapi_ch_free_string(&filter);
  276. }
  277. if (dsmuid_vs) {
  278. slapi_valueset_free(dsmuid_vs);
  279. dsmuid_vs = NULL;
  280. }
  281. slapi_pblock_destroy(search_pb);
  282. search_pb = NULL;
  283. }
  284. /* Cleanup uniquemembers without a referent, and verify memberuid otherwise */
  285. Slapi_Attr *obj_attr = NULL;
  286. rc = slapi_entry_attr_find(e, "uniquemember", &obj_attr);
  287. if (rc == 0 && obj_attr) {
  288. int fixMembership = 0;
  289. Slapi_ValueSet *bad_ums = NULL;
  290. Slapi_Value *uniqval = NULL; /* uniquemeber Attribute values */
  291. Slapi_ValueSet *uids = NULL;
  292. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  293. "_fix_memberuid scan uniquemember, group %s\n", dn);
  294. for (i = slapi_attr_first_value(obj_attr, &uniqval); i != -1;
  295. i = slapi_attr_next_value(obj_attr, i, &uniqval)) {
  296. const char *member = slapi_value_get_string(uniqval);
  297. char *attrs[] = {"uid", "objectclass", NULL};
  298. Slapi_Entry *child = getEntry(member, attrs);
  299. if (child) {
  300. slapi_entry_free(child);
  301. } else {
  302. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  303. "_fix_memberuid orphaned uniquemember found: %s\n", member);
  304. if ((strncasecmp(member, "cn=", 3) == 0) ||
  305. (strncasecmp(member, "uid=", 4) == 0)) {
  306. fixMembership = 1;
  307. }
  308. if (!bad_ums) {
  309. bad_ums = slapi_valueset_new();
  310. }
  311. slapi_valueset_add_value(bad_ums, uniqval);
  312. }
  313. if (is_posix_group) {
  314. char *uid = NULL;
  315. /* search uid for member (DN) */
  316. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME, "search %s\n", member);
  317. if ((uid = searchUid(member)) != NULL) {
  318. Slapi_Value *value = slapi_value_new();
  319. /* Search an entry having "member" as DN and get uid value from it. */
  320. slapi_value_set_string_passin(value, uid);
  321. /* add uids ValueSet */
  322. if (NULL == uids) {
  323. uids = slapi_valueset_new();
  324. }
  325. slapi_valueset_add_value(uids, value);
  326. slapi_value_free(&value);
  327. }
  328. }
  329. }
  330. /* If we found some posix members, replace the existing memberuid attribute
  331. * with the found values. */
  332. if (uids && slapi_valueset_count(uids)) {
  333. Slapi_Value *val = 0;
  334. Slapi_Mod *smod = slapi_mod_new();
  335. int hint = 0;
  336. slapi_mod_init(smod, 0);
  337. slapi_mod_set_operation(smod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
  338. slapi_mod_set_type(smod, "memberuid");
  339. /* Loop through all of our values and add them to smod */
  340. hint = slapi_valueset_first_value(uids, &val);
  341. while (val) {
  342. /* this makes a copy of the berval */
  343. slapi_mod_add_value(smod, slapi_value_get_berval(val));
  344. hint = slapi_valueset_next_value(uids, hint, &val);
  345. }
  346. slapi_mods_add_ldapmod(smods, slapi_mod_get_ldapmod_passout(smod));
  347. slapi_mod_free(&smod);
  348. }
  349. slapi_valueset_free(uids);
  350. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  351. "_fix_memberuid Finishing...\n");
  352. if (fixMembership && posix_winsync_config_get_mapNestedGrouping()) {
  353. Slapi_ValueSet *del_nested_vs = slapi_valueset_new();
  354. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  355. "_fix_memberuid group deleted, recalculating nesting\n");
  356. propogateDeletionsUpward(e, sdn, bad_ums, del_nested_vs, 0);
  357. slapi_valueset_free(del_nested_vs);
  358. del_nested_vs = NULL;
  359. }
  360. if (bad_ums) {
  361. slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, "uniquemember", valueset_get_valuearray(bad_ums));
  362. slapi_valueset_free(bad_ums);
  363. bad_ums = NULL;
  364. }
  365. }
  366. mods = slapi_mods_get_ldapmods_byref(smods);
  367. if (mods) {
  368. Slapi_PBlock *mod_pb = NULL;
  369. mod_pb = slapi_pblock_new();
  370. slapi_modify_internal_set_pb_ext(mod_pb, sdn, mods, 0, 0,
  371. posix_winsync_get_plugin_identity(), 0);
  372. slapi_pblock_set(mod_pb, SLAPI_TXN, the_cb_data->txn);
  373. slapi_modify_internal_pb(mod_pb);
  374. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  375. slapi_pblock_destroy(mod_pb);
  376. }
  377. slapi_mods_free(&smods);
  378. bail:
  379. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  380. "_fix_memberuid <==\n");
  381. /*
  382. * Since Ticket #481 "expand nested posix groups",
  383. * there's a possibility the found entry does not contain
  384. * uniqueMember attribute. But "not found" error shoud not
  385. * be returned, which stops the further fixup task.
  386. */
  387. return rc;
  388. }
  389. static void
  390. posix_group_fixup_task_thread(void *arg)
  391. {
  392. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  393. "_task_thread ==>\n");
  394. Slapi_Task *task = (Slapi_Task *)arg;
  395. task_data *td = NULL;
  396. int rc = 0;
  397. if (!task) {
  398. return; /* no task */
  399. }
  400. slapi_task_inc_refcount(task);
  401. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  402. "posix_group_fixup_task_thread --> refcount incremented.\n");
  403. /* Fetch our task data from the task */
  404. td = (task_data *)slapi_task_get_data(task);
  405. slapi_task_begin(task, 1);
  406. slapi_task_log_notice(task, "posix_group task starts (arg: %s) ...\n", td->filter_str);
  407. /* get the memberOf operation lock */
  408. memberUidLock();
  409. /* do real work */
  410. rc = posix_group_fix_memberuid(td->dn, td->filter_str, NULL /* no txn? */);
  411. /* release the memberOf operation lock */
  412. memberUidUnlock();
  413. slapi_task_log_notice(task, "posix_group task finished.");
  414. slapi_task_log_status(task, "posix_group task finished.");
  415. slapi_task_inc_progress(task);
  416. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  417. "_task_thread finishing\n");
  418. /* this will queue the destruction of the task */
  419. slapi_task_finish(task, rc);
  420. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  421. "_task_thread <==\n");
  422. slapi_task_dec_refcount(task);
  423. slapi_log_err(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  424. "posix_group_fixup_task_thread <-- refcount decremented.\n");
  425. }