posix-group-task.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. #include "slapi-plugin.h"
  2. #include "slapi-private.h"
  3. #include "nspr.h"
  4. #include "posix-wsp-ident.h"
  5. #include "posix-group-func.h"
  6. typedef struct _task_data
  7. {
  8. char *dn; /* search base */
  9. char *filter_str; /* search filter */
  10. } task_data;
  11. typedef struct _cb_data
  12. {
  13. char *dn;
  14. void *txn;
  15. } cb_data;
  16. /*
  17. typedef struct _posix_group_task_data
  18. {
  19. POSIX_WinSync_Config *config;
  20. Slapi_Value *memberdn_val;
  21. Slapi_ValueSet **uidvals;
  22. void *txn;
  23. } posix_group_data_data;
  24. */
  25. Slapi_Value **
  26. valueset_get_valuearray(const Slapi_ValueSet *vs); /* stolen from proto-slap.h */
  27. /* interface function */
  28. int
  29. posix_group_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode,
  30. char *returntext, void *arg);
  31. Slapi_Entry *
  32. getEntry(const char *udn, char **attrs);
  33. static void
  34. posix_group_task_destructor(Slapi_Task *task);
  35. static void
  36. posix_group_fixup_task_thread(void *arg);
  37. static int
  38. posix_group_fix_memberuid_callback(Slapi_Entry *e, void *callback_data);
  39. /* extract a single value from the entry (as a string) -- if it's not in the
  40. * entry, the default will be returned (which can be NULL).
  41. * you do not need to free anything returned by this.
  42. */
  43. static const char *
  44. fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val)
  45. {
  46. Slapi_Attr *attr;
  47. Slapi_Value *val = NULL;
  48. if (slapi_entry_attr_find(e, attrname, &attr) != 0)
  49. return default_val;
  50. slapi_attr_first_value(attr, &val);
  51. return slapi_value_get_string(val);
  52. }
  53. /* e configEntry */
  54. int
  55. posix_group_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode,
  56. char *returntext, void *arg)
  57. {
  58. PRThread *thread = NULL;
  59. int rv = SLAPI_DSE_CALLBACK_OK;
  60. task_data *mytaskdata = NULL;
  61. Slapi_Task *task = NULL;
  62. const char *filter;
  63. const char *dn = 0;
  64. *returncode = LDAP_SUCCESS;
  65. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  66. "posix_group_task_add: ==>\n");
  67. /* get arg(s) */
  68. /* default: set replication basedn */
  69. if ((dn = fetch_attr(e, "basedn", slapi_sdn_get_dn(posix_winsync_config_get_suffix()))) == NULL) {
  70. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  71. rv = SLAPI_DSE_CALLBACK_ERROR;
  72. goto out;
  73. }
  74. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  75. "posix_group_task_add: retrieved basedn: %s\n", dn);
  76. if ((filter = fetch_attr(e, "filter", "(objectclass=ntGroup)")) == NULL) {
  77. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  78. rv = SLAPI_DSE_CALLBACK_ERROR;
  79. goto out;
  80. }
  81. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  82. "posix_group_task_add: retrieved filter: %s\n", filter);
  83. /* setup our task data */
  84. mytaskdata = (task_data*) slapi_ch_malloc(sizeof(task_data));
  85. if (mytaskdata == NULL) {
  86. *returncode = LDAP_OPERATIONS_ERROR;
  87. rv = SLAPI_DSE_CALLBACK_ERROR;
  88. goto out;
  89. }
  90. mytaskdata->dn = slapi_ch_strdup(dn);
  91. mytaskdata->filter_str = slapi_ch_strdup(filter);
  92. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  93. "posix_group_task_add: task data allocated\n");
  94. /* allocate new task now */
  95. char * ndn = slapi_entry_get_ndn(e);
  96. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  97. "posix_group_task_add: creating task object: %s\n",
  98. ndn);
  99. task = slapi_new_task(ndn);
  100. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  101. "posix_group_task_add: task object created\n");
  102. /* register our destructor for cleaning up our private data */
  103. slapi_task_set_destructor_fn(task, posix_group_task_destructor);
  104. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  105. "posix_group_task_add: task destructor set\n");
  106. /* Stash a pointer to our data in the task */
  107. slapi_task_set_data(task, mytaskdata);
  108. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  109. "posix_group_task_add: task object initialized\n");
  110. /* start the sample task as a separate thread */
  111. thread = PR_CreateThread(PR_USER_THREAD, posix_group_fixup_task_thread, (void *) task,
  112. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
  113. SLAPD_DEFAULT_THREAD_STACKSIZE);
  114. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  115. "posix_group_task_add: thread created\n");
  116. if (thread == NULL) {
  117. slapi_log_error(SLAPI_LOG_FATAL, POSIX_WINSYNC_PLUGIN_NAME,
  118. "unable to create task thread!\n");
  119. *returncode = LDAP_OPERATIONS_ERROR;
  120. rv = SLAPI_DSE_CALLBACK_ERROR;
  121. slapi_task_finish(task, *returncode);
  122. } else {
  123. rv = SLAPI_DSE_CALLBACK_OK;
  124. }
  125. out:
  126. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  127. "posix_group_task_add: <==\n");
  128. return rv;
  129. }
  130. static void
  131. posix_group_task_destructor(Slapi_Task *task)
  132. {
  133. if (task) {
  134. task_data *mydata = (task_data *) slapi_task_get_data(task);
  135. if (mydata) {
  136. slapi_ch_free_string(&mydata->dn);
  137. slapi_ch_free_string(&mydata->filter_str);
  138. /* Need to cast to avoid a compiler warning */
  139. slapi_ch_free((void **) &mydata);
  140. }
  141. }
  142. }
  143. static int
  144. posix_group_del_memberuid_callback(Slapi_Entry *e, void *callback_data)
  145. {
  146. int rc = 0;
  147. LDAPMod mod;
  148. LDAPMod *mods[2];
  149. char *val[2];
  150. Slapi_PBlock *mod_pb = 0;
  151. cb_data *the_cb_data = (cb_data *) callback_data;
  152. mod_pb = slapi_pblock_new();
  153. mods[0] = &mod;
  154. mods[1] = 0;
  155. val[0] = 0; /* all */
  156. val[1] = 0;
  157. mod.mod_op = LDAP_MOD_DELETE;
  158. mod.mod_type = "memberuid";
  159. mod.mod_values = val;
  160. slapi_modify_internal_set_pb_ext(mod_pb, slapi_entry_get_sdn(e), mods, 0, 0,
  161. posix_winsync_get_plugin_identity(), 0);
  162. slapi_pblock_set(mod_pb, SLAPI_TXN, the_cb_data->txn);
  163. slapi_modify_internal_pb(mod_pb);
  164. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  165. slapi_pblock_destroy(mod_pb);
  166. return rc;
  167. }
  168. static int
  169. posix_group_fix_memberuid(char *dn, char *filter_str, void *txn)
  170. {
  171. int rc = 0;
  172. struct _cb_data callback_data = { dn, txn };
  173. Slapi_PBlock *search_pb = slapi_pblock_new();
  174. /* char *attrs[]={"uniquemember","memberuid",NULL}; */
  175. slapi_search_internal_set_pb(search_pb, dn, LDAP_SCOPE_SUBTREE, filter_str, 0, 0, 0, 0,
  176. posix_winsync_get_plugin_identity(), 0);
  177. slapi_pblock_set(search_pb, SLAPI_TXN, txn); /* set transaction id */
  178. rc = slapi_search_internal_callback_pb(search_pb, &callback_data, 0,
  179. posix_group_fix_memberuid_callback, 0);
  180. slapi_pblock_destroy(search_pb);
  181. return rc;
  182. }
  183. /* posix_group_fix_memberuid_callback()
  184. * Add initial and/or fix up broken group list in entry
  185. *
  186. * 1. forall uniquemember search if posixAccount ? add uid : ""
  187. */
  188. static int
  189. posix_group_fix_memberuid_callback(Slapi_Entry *e, void *callback_data)
  190. {
  191. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  192. "_fix_memberuid ==>\n");
  193. cb_data *the_cb_data = (cb_data *) callback_data;
  194. int rc;
  195. Slapi_Attr *muid_attr = NULL;
  196. Slapi_Value *v = NULL;
  197. Slapi_Mods *smods = slapi_mods_new();
  198. char *dn = slapi_entry_get_dn(e);
  199. Slapi_DN *sdn = slapi_entry_get_sdn(e);
  200. LDAPMod **mods = NULL;
  201. /* Clean out memberuids and dsonlymemberuids without a valid referant */
  202. rc = slapi_entry_attr_find(e, "memberuid", &muid_attr);
  203. if (rc == 0 && muid_attr) {
  204. Slapi_PBlock *search_pb = slapi_pblock_new();
  205. Slapi_Attr *dsmuid_attr = NULL;
  206. Slapi_ValueSet *dsmuid_vs = NULL;
  207. char *attrs[] = { "uid", NULL };
  208. rc = slapi_entry_attr_find(e, "dsonlymemberuid", &dsmuid_attr);
  209. if (rc == 0 && dsmuid_attr) {
  210. slapi_attr_get_valueset(dsmuid_attr, &dsmuid_vs);
  211. }
  212. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  213. "_fix_memberuid scan for orphaned memberuids\n");
  214. int i;
  215. for (i = slapi_attr_first_value(muid_attr, &v); i != -1;
  216. i = slapi_attr_next_value(muid_attr, i, &v)) {
  217. const char *muid = slapi_value_get_string(v);
  218. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  219. "_fix_memberuid iterating memberuid: %s\n",
  220. muid);
  221. size_t vallen = muid ? strlen(muid) : 0;
  222. char *filter_escaped_value = slapi_ch_calloc(sizeof(char), vallen*3+1);
  223. char *filter = slapi_ch_smprintf("(uid=%s)", escape_filter_value(muid, vallen, filter_escaped_value));
  224. slapi_ch_free_string(&filter_escaped_value);
  225. Slapi_Entry **search_entries = NULL;
  226. slapi_search_internal_set_pb(search_pb,
  227. the_cb_data->dn,
  228. LDAP_SCOPE_SUBTREE,
  229. filter,
  230. attrs, 0, NULL, NULL,
  231. posix_winsync_get_plugin_identity(), 0);
  232. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  233. "_fix_memberuid searching %s with filter: %s\n",
  234. the_cb_data->dn, filter);
  235. rc = slapi_search_internal_pb(search_pb);
  236. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &search_entries);
  237. if (!search_entries || !search_entries[0]) {
  238. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  239. "_fix_memberuid Adding bad memberuid %s\n",
  240. slapi_value_get_string(v));
  241. slapi_mods_add_string(smods, LDAP_MOD_DELETE, "memberuid", slapi_value_get_string(v));
  242. if (dsmuid_vs && slapi_valueset_find(dsmuid_attr, dsmuid_vs, v)) {
  243. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  244. "_fix_memberuid Adding bad dsonlymemberuid %s\n",
  245. slapi_value_get_string(v));
  246. slapi_mods_add_string(smods, LDAP_MOD_DELETE, "dsonlymemberuid", slapi_value_get_string(v));
  247. }
  248. }
  249. slapi_free_search_results_internal(search_pb);
  250. slapi_pblock_init(search_pb);
  251. slapi_ch_free_string(&filter);
  252. }
  253. if (dsmuid_vs) {
  254. slapi_valueset_free(dsmuid_vs); dsmuid_vs = NULL;
  255. }
  256. slapi_pblock_destroy(search_pb); search_pb = NULL;
  257. }
  258. /* Cleanup uniquemembers without a referent, and verify memberuid otherwise */
  259. Slapi_Attr *obj_attr = NULL;
  260. rc = slapi_entry_attr_find(e, "uniquemember", &obj_attr);
  261. if (rc == 0 && obj_attr) {
  262. int fixMembership = 0;
  263. Slapi_ValueSet *bad_ums = NULL;
  264. int i;
  265. Slapi_Value * uniqval = NULL; /* uniquemeber Attribute values */
  266. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  267. "_fix_memberuid scan uniquemember, group %s\n", dn);
  268. for (i = slapi_attr_first_value(obj_attr, &uniqval); i != -1;
  269. i = slapi_attr_next_value(obj_attr, i, &uniqval)) {
  270. const char *member = slapi_value_get_string(uniqval);
  271. char *attrs[] = { "uid", "objectclass", NULL };
  272. Slapi_Entry *child = getEntry(member, attrs);
  273. if (!child) {
  274. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  275. "_fix_memberuid orphaned uniquemember found: %s\n", member);
  276. if (strncasecmp(member, "cn=", 3) == 0) {
  277. fixMembership = 1;
  278. }
  279. if (!bad_ums) {
  280. bad_ums = slapi_valueset_new();
  281. }
  282. slapi_valueset_add_value(bad_ums, uniqval);
  283. }
  284. }
  285. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  286. "_fix_memberuid Finishing...\n");
  287. if (fixMembership && posix_winsync_config_get_mapNestedGrouping()) {
  288. Slapi_ValueSet *del_nested_vs = slapi_valueset_new();
  289. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  290. "_fix_memberuid group deleted, recalculating nesting\n");
  291. propogateDeletionsUpward(e, sdn, bad_ums, del_nested_vs, 0);
  292. slapi_valueset_free(del_nested_vs); del_nested_vs = NULL;
  293. }
  294. if (bad_ums) {
  295. slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, "uniquemember", valueset_get_valuearray(bad_ums));
  296. slapi_valueset_free(bad_ums); bad_ums = NULL;
  297. }
  298. }
  299. mods = slapi_mods_get_ldapmods_passout(smods);
  300. if (mods) {
  301. Slapi_PBlock *mod_pb = NULL;
  302. mod_pb = slapi_pblock_new();
  303. slapi_modify_internal_set_pb_ext(mod_pb, sdn, mods, 0, 0,
  304. posix_winsync_get_plugin_identity(), 0);
  305. slapi_pblock_set(mod_pb, SLAPI_TXN, the_cb_data->txn);
  306. slapi_modify_internal_pb(mod_pb);
  307. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  308. slapi_pblock_destroy(mod_pb);
  309. }
  310. slapi_mods_free(&smods);
  311. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  312. "_fix_memberuid <==\n");
  313. return rc;
  314. }
  315. static void
  316. posix_group_fixup_task_thread(void *arg)
  317. {
  318. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  319. "_task_thread ==>\n");
  320. Slapi_Task *task = (Slapi_Task *) arg;
  321. task_data *td = NULL;
  322. int rc = 0;
  323. /* Fetch our task data from the task */
  324. td = (task_data *) slapi_task_get_data(task);
  325. slapi_task_begin(task, 1);
  326. slapi_task_log_notice(task, "posix_group task starts (arg: %s) ...\n", td->filter_str);
  327. /* get the memberOf operation lock */
  328. memberUidLock();
  329. /* do real work */
  330. rc = posix_group_fix_memberuid(td->dn, td->filter_str, NULL /* no txn? */);
  331. /* release the memberOf operation lock */
  332. memberUidUnlock();
  333. slapi_task_log_notice(task, "posix_group task finished.");
  334. slapi_task_log_status(task, "posix_group task finished.");
  335. slapi_task_inc_progress(task);
  336. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  337. "_task_thread finishing\n");
  338. /* this will queue the destruction of the task */
  339. slapi_task_finish(task, rc);
  340. slapi_log_error(SLAPI_LOG_PLUGIN, POSIX_WINSYNC_PLUGIN_NAME,
  341. "_task_thread <==\n");
  342. }