1
0

windows_protocol_util.c 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /* repl5_protocol_util.c */
  7. /*
  8. Code common to both incremental and total protocols.
  9. */
  10. #include "repl5.h"
  11. #include "repl5_prot_private.h"
  12. #include "windowsrepl.h"
  13. #include "slap.h"
  14. #include <unicode/ustring.h> /* UTF8 conversion */
  15. int ruv_private_new( RUV **ruv, RUV *clone );
  16. static Slapi_Entry* windows_entry_already_exists(Slapi_Entry *e);
  17. static void windows_dirsync_now (Private_Repl_Protocol *prp);
  18. static Slapi_DN* map_dn_user(Slapi_DN *sdn, int map_to, const Slapi_DN *root);
  19. static Slapi_DN* map_dn_group(Slapi_DN *sdn, int map_to, const Slapi_DN *root);
  20. static void make_mods_from_entries(Slapi_Entry *new_entry, Slapi_Entry *existing_entry, LDAPMod ***attrs);
  21. static void windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod ***returned_mods, int is_user, char** password);
  22. static int is_subject_of_agreemeent_local(const Slapi_Entry *local_entry,const Repl_Agmt *ra);
  23. static int windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_entry, Slapi_DN *remote_sdn, Slapi_Entry **remote_entry, char** password);
  24. static int windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_entry);
  25. static int windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry);
  26. static int map_entry_dn_outbound(Slapi_Entry *e, const Slapi_DN **dn, Private_Repl_Protocol *prp, int *missing_entry);
  27. static char* extract_ntuserdomainid_from_entry(Slapi_Entry *e);
  28. static int windows_get_remote_entry (Private_Repl_Protocol *prp, Slapi_DN* remote_dn,Slapi_Entry **remote_entry);
  29. static const char* op2string (int op);
  30. static int is_subject_of_agreemeent_remote(Slapi_Entry *e, const Repl_Agmt *ra);
  31. static int map_entry_dn_inbound(Slapi_Entry *e, const Slapi_DN **dn, const Repl_Agmt *ra);
  32. /* Controls the direction of flow for mapped attributes */
  33. typedef enum mapping_types {
  34. bidirectional,
  35. fromwindowsonly,
  36. towindowsonly,
  37. disabled
  38. } mapping_types;
  39. /* Controls if we sync the attibute always, or only when we're creating new entries */
  40. /* Used for attributes like samaccountname, where we want to fill it in on a new entry, but
  41. * we never want to change it on an existing entry */
  42. typedef enum creation_types {
  43. always,
  44. createonly
  45. } creation_types;
  46. typedef enum attr_types {
  47. normal,
  48. dnmap
  49. } attr_types;
  50. typedef struct _windows_attribute_map
  51. {
  52. char *windows_attribute_name;
  53. char *ldap_attribute_name;
  54. mapping_types map_type;
  55. creation_types create_type;
  56. attr_types attr_type;
  57. } windows_attribute_map;
  58. /* List of attributes that are common to AD and LDAP, so we simply copy them over in both directions */
  59. static char* windows_user_matching_attributes[] =
  60. {
  61. "destinationIndicator",
  62. "facsimileTelephoneNumber",
  63. "givenName",
  64. "homePhone",
  65. "homePostalAddress",
  66. "initials",
  67. "l",
  68. "mail",
  69. "manager",
  70. "mobile",
  71. "o",
  72. "ou",
  73. "pager",
  74. "physicalDeliveryOfficeName",
  75. "postOfficeBox",
  76. "postalAddress",
  77. "postalCode",
  78. "preferredDeliveryMethod",
  79. "registeredAddress",
  80. "seeAlso",
  81. "sn",
  82. "st",
  83. "street",
  84. "telephoneNumber",
  85. "teletexTerminalIdentifier",
  86. "telexNumber",
  87. "title",
  88. "userCertificate",
  89. "x121Address",
  90. NULL
  91. };
  92. static char* windows_group_matching_attributes[] =
  93. {
  94. "description",
  95. "destinationIndicator",
  96. "facsimileTelephoneNumber",
  97. "givenName",
  98. "homePhone",
  99. "homePostalAddress",
  100. "initials",
  101. "l",
  102. "mail",
  103. "manager",
  104. "mobile",
  105. "o",
  106. "ou",
  107. "pager",
  108. "physicalDeliveryOfficeName",
  109. "postOfficeBox",
  110. "postalAddress",
  111. "postalCode",
  112. "preferredDeliveryMethod",
  113. "registeredAddress",
  114. "seeAlso",
  115. "sn",
  116. "st",
  117. "street",
  118. "telephoneNumber",
  119. "teletexTerminalIdentifier",
  120. "telexNumber",
  121. "title",
  122. "userCertificate",
  123. "x121Address",
  124. NULL
  125. };
  126. static windows_attribute_map user_attribute_map[] =
  127. {
  128. { "homeDirectory", "ntUserHomeDir", bidirectional, always, normal},
  129. { "scriptPath", "ntUserScriptPath", bidirectional, always, normal},
  130. { "lastLogon", "ntUserLastLogon", bidirectional, always, normal},
  131. { "lastLogoff", "ntUserLastLogoff", bidirectional, always, normal},
  132. { "sAMAccountName", "ntUserDomainId", bidirectional, createonly, normal},
  133. /* cn is a naming attribute in AD, so we don't want to change it after entry creation */
  134. { "cn", "cn", towindowsonly, createonly, normal},
  135. /* However, it isn't a naming attribute in DS (we use uid) so it's safe to accept changes inbound */
  136. { "name", "cn", fromwindowsonly, always, normal},
  137. { "manager", "manager", bidirectional, always, dnmap},
  138. { "secretary", "secretary", bidirectional, always, dnmap},
  139. {NULL, NULL, -1}
  140. };
  141. static windows_attribute_map group_attribute_map[] =
  142. {
  143. { "ntGroupType", "groupType", bidirectional, createonly, normal},
  144. { "sAMAccountName", "ntUserDomainId", bidirectional, createonly, normal},
  145. { "member", "uniquemember", bidirectional, always, dnmap},
  146. {NULL, NULL, -1}
  147. };
  148. static const char*
  149. op2string(int op)
  150. {
  151. LDAPDebug( LDAP_DEBUG_TRACE, "=> op2string\n", 0, 0, 0 );
  152. LDAPDebug( LDAP_DEBUG_TRACE, "<= op2string\n", 0, 0, 0 );
  153. switch (op) {
  154. case SLAPI_OPERATION_ADD:
  155. return "add";
  156. case SLAPI_OPERATION_MODIFY:
  157. return "modify";
  158. case SLAPI_OPERATION_DELETE:
  159. return "delete";
  160. case SLAPI_OPERATION_MODRDN:
  161. return "rename";
  162. case SLAPI_OPERATION_EXTENDED:
  163. return "extended";
  164. }
  165. return "unknown";
  166. }
  167. static void
  168. windows_dump_entry(const char *string, Slapi_Entry *e)
  169. {
  170. int length = 0;
  171. char *buffer = NULL;
  172. buffer = slapi_entry2str(e,&length);
  173. slapi_log_error(SLAPI_LOG_REPL, NULL, "Windows sync entry: %s %s\n", string, buffer);
  174. if (buffer)
  175. {
  176. slapi_ch_free((void**)&buffer);
  177. }
  178. }
  179. static void
  180. map_dn_values(Private_Repl_Protocol *prp,Slapi_ValueSet *original_values, Slapi_ValueSet **mapped_values, int to_windows)
  181. {
  182. Slapi_ValueSet *new_vs = NULL;
  183. Slapi_Value *original_value = NULL;
  184. int retval = 0;
  185. int i = 0;
  186. /* For each value: */
  187. i= slapi_valueset_first_value(original_values,&original_value);
  188. while ( i != -1 ) {
  189. int is_ours = 0;
  190. char *new_dn_string = NULL;
  191. const char *original_dn_string = NULL;
  192. int original_dn_string_length = 0;
  193. Slapi_DN *original_dn = NULL;
  194. original_dn_string = slapi_value_get_string(original_value);
  195. /* Sanity check the data was a valid string */
  196. original_dn_string_length = slapi_value_get_length(original_value);
  197. /* Make a sdn from the string */
  198. original_dn = slapi_sdn_new_dn_byref(original_dn_string);
  199. if (to_windows)
  200. {
  201. Slapi_Entry *local_entry = NULL;
  202. /* Try to get the local entry */
  203. retval = windows_get_local_entry(original_dn,&local_entry);
  204. if (0 == retval && local_entry)
  205. {
  206. int missing_entry = 0;
  207. Slapi_DN *remote_dn = NULL;
  208. /* Now map the DN */
  209. is_ours = is_subject_of_agreemeent_local(local_entry,prp->agmt);
  210. if (is_ours)
  211. {
  212. map_entry_dn_outbound(local_entry,&remote_dn,prp,&missing_entry);
  213. if (remote_dn)
  214. {
  215. if (!missing_entry)
  216. {
  217. /* Success */
  218. new_dn_string = slapi_ch_strdup(slapi_sdn_get_dn(remote_dn));
  219. }
  220. slapi_sdn_free(&remote_dn);
  221. }
  222. }
  223. } else {
  224. slapi_log_error(SLAPI_LOG_REPL, NULL, "map_dn_values: no local entry found for %s\n", original_dn_string);
  225. }
  226. if (local_entry)
  227. {
  228. slapi_entry_free(local_entry);
  229. local_entry = NULL;
  230. }
  231. } else
  232. {
  233. Slapi_Entry *remote_entry = NULL;
  234. Slapi_DN *local_dn = NULL;
  235. /* Try to get the remote entry */
  236. retval = windows_get_remote_entry(prp,original_dn,&remote_entry);
  237. is_ours = is_subject_of_agreemeent_remote(remote_entry,prp->agmt);
  238. if (is_ours)
  239. {
  240. retval = map_entry_dn_inbound(remote_entry,&local_dn,prp->agmt);
  241. if (0 == retval && local_dn)
  242. {
  243. new_dn_string = slapi_ch_strdup(slapi_sdn_get_dn(local_dn));
  244. slapi_sdn_free(&local_dn);
  245. } else
  246. {
  247. slapi_log_error(SLAPI_LOG_REPL, NULL, "map_dn_values: no remote entry found for %s\n", original_dn_string);
  248. }
  249. }
  250. if (remote_entry)
  251. {
  252. slapi_entry_free(remote_entry);
  253. remote_entry = NULL;
  254. }
  255. }
  256. /* Extract the dn string and store in the new value */
  257. if (new_dn_string)
  258. {
  259. Slapi_Value *new_value = NULL;
  260. if (NULL == new_vs)
  261. {
  262. new_vs = slapi_valueset_new();
  263. }
  264. new_value = slapi_value_new_string_passin(new_dn_string);
  265. slapi_valueset_add_value(new_vs,new_value);
  266. slapi_value_free(&new_value);
  267. }
  268. /* If not then we skip it */
  269. i = slapi_valueset_next_value(original_values,i,&original_value);
  270. if (original_dn)
  271. {
  272. slapi_sdn_free(&original_dn);
  273. }
  274. }/* while */
  275. if (new_vs)
  276. {
  277. *mapped_values = new_vs;
  278. }
  279. }
  280. /*
  281. * Acquire exclusive access to a replica. Send a start replication extended
  282. * operation to the replica. The response will contain a success code, and
  283. * optionally the replica's update vector if acquisition is successful.
  284. * This function returns one of the following:
  285. * ACQUIRE_SUCCESS - the replica was acquired, and we have exclusive update access
  286. * ACQUIRE_REPLICA_BUSY - another master was updating the replica
  287. * ACQUIRE_FATAL_ERROR - something bad happened, and it's not likely to improve
  288. * if we wait.
  289. * ACQUIRE_TRANSIENT_ERROR - something bad happened, but it's probably worth
  290. * another try after waiting a while.
  291. * If ACQUIRE_SUCCESS is returned, then ruv will point to the replica's update
  292. * vector. It's possible that the replica does something goofy and doesn't
  293. * return us an update vector, so be prepared for ruv to be NULL (but this is
  294. * an error).
  295. */
  296. int
  297. windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv, int check_ruv)
  298. {
  299. int return_value = ACQUIRE_SUCCESS;
  300. ConnResult crc;
  301. Repl_Connection *conn;
  302. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_acquire_replica\n", 0, 0, 0 );
  303. PR_ASSERT(prp);
  304. if (prp->replica_acquired) /* we already acquire replica */
  305. {
  306. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
  307. "%s: Remote replica already acquired\n",
  308. agmt_get_long_name(prp->agmt));
  309. return_value = ACQUIRE_FATAL_ERROR;
  310. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_acquire_replica\n", 0, 0, 0 );
  311. return ACQUIRE_SUCCESS;
  312. }
  313. {
  314. Replica *replica;
  315. Object *supl_ruv_obj, *cons_ruv_obj;
  316. PRBool is_newer = PR_FALSE;
  317. RUV *r;
  318. if (prp->agmt)
  319. {
  320. cons_ruv_obj = agmt_get_consumer_ruv(prp->agmt);
  321. }
  322. object_acquire(prp->replica_object);
  323. replica = object_get_data(prp->replica_object);
  324. supl_ruv_obj = replica_get_ruv ( replica );
  325. /* make a copy of the existing RUV as a starting point
  326. XXX this is probably a not-so-elegant hack */
  327. slapi_log_error(SLAPI_LOG_REPL, NULL, "acquire_replica, supplier RUV:\n");
  328. if (supl_ruv_obj) {
  329. object_acquire(supl_ruv_obj);
  330. ruv_dump ((RUV*) object_get_data ( supl_ruv_obj ), "supplier", NULL);
  331. object_release(supl_ruv_obj);
  332. }else
  333. slapi_log_error(SLAPI_LOG_REPL, NULL, "acquire_replica, supplier RUV = null\n");
  334. slapi_log_error(SLAPI_LOG_REPL, NULL, "acquire_replica, consumer RUV:\n");
  335. if (cons_ruv_obj)
  336. {
  337. RUV* con;
  338. object_acquire(cons_ruv_obj);
  339. con = (RUV*) object_get_data ( cons_ruv_obj );
  340. ruv_dump (con,"consumer", NULL);
  341. object_release( cons_ruv_obj );
  342. } else {
  343. slapi_log_error(SLAPI_LOG_REPL, NULL, "acquire_replica, consumer RUV = null\n");
  344. }
  345. is_newer = ruv_is_newer ( supl_ruv_obj, cons_ruv_obj );
  346. /* This follows ruv_is_newer, since it's always newer if it's null */
  347. if (cons_ruv_obj == NULL)
  348. {
  349. RUV *s;
  350. s = (RUV*) object_get_data ( replica_get_ruv ( replica ) );
  351. agmt_set_consumer_ruv(prp->agmt, s );
  352. object_release ( replica_get_ruv ( replica ) );
  353. cons_ruv_obj = agmt_get_consumer_ruv(prp->agmt);
  354. }
  355. r = (RUV*) object_get_data ( cons_ruv_obj);
  356. *ruv = r;
  357. if ( supl_ruv_obj ) object_release ( supl_ruv_obj );
  358. if ( cons_ruv_obj ) object_release ( cons_ruv_obj );
  359. object_release (prp->replica_object);
  360. replica = NULL;
  361. if (is_newer == PR_FALSE && check_ruv) {
  362. prp->last_acquire_response_code = NSDS50_REPL_UPTODATE;
  363. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_acquire_replica - ACQUIRE_CONSUMER_WAS_UPTODATE\n", 0, 0, 0 );
  364. return ACQUIRE_CONSUMER_WAS_UPTODATE;
  365. }
  366. }
  367. prp->last_acquire_response_code = NSDS50_REPL_REPLICA_NO_RESPONSE;
  368. /* Get the connection */
  369. conn = prp->conn;
  370. crc = windows_conn_connect(conn);
  371. if (CONN_OPERATION_FAILED == crc)
  372. {
  373. return_value = ACQUIRE_TRANSIENT_ERROR;
  374. }
  375. else if (CONN_SSL_NOT_ENABLED == crc)
  376. {
  377. return_value = ACQUIRE_FATAL_ERROR;
  378. }
  379. else
  380. {
  381. /* we don't want the timer to go off in the middle of an operation */
  382. windows_conn_cancel_linger(conn);
  383. /* Does the remote replica support the dirsync protocol?
  384. if it update the conn object */
  385. windows_conn_replica_supports_dirsync(conn);
  386. if (CONN_NOT_CONNECTED == crc || CONN_OPERATION_FAILED == crc)
  387. {
  388. /* We don't know anything about the remote replica. Try again later. */
  389. return_value = ACQUIRE_TRANSIENT_ERROR;
  390. }
  391. else
  392. {
  393. /* Good to go. Start the protocol. */
  394. CSN *current_csn = NULL;
  395. Slapi_DN *replarea_sdn;
  396. /* Obtain a current CSN */
  397. replarea_sdn = agmt_get_replarea(prp->agmt);
  398. current_csn = get_current_csn(replarea_sdn);
  399. if (NULL != current_csn)
  400. {
  401. return_value = ACQUIRE_SUCCESS;
  402. }
  403. else
  404. {
  405. /* Couldn't get a current CSN */
  406. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
  407. "%s: Unable to obtain current CSN. "
  408. "Replication is aborting.\n",
  409. agmt_get_long_name(prp->agmt));
  410. return_value = ACQUIRE_FATAL_ERROR;
  411. }
  412. slapi_sdn_free(&replarea_sdn);
  413. }
  414. }
  415. if (ACQUIRE_SUCCESS != return_value)
  416. {
  417. /* could not acquire the replica, so reinstate the linger timer, since this
  418. means we won't call release_replica, which also reinstates the timer */
  419. windows_conn_start_linger(conn);
  420. }
  421. else
  422. {
  423. /* replica successfully acquired */
  424. prp->replica_acquired = PR_TRUE;
  425. }
  426. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_acquire_replica\n", 0, 0, 0 );
  427. return return_value;
  428. }
  429. void
  430. windows_release_replica(Private_Repl_Protocol *prp)
  431. {
  432. struct berval *retdata = NULL;
  433. char *retoid = NULL;
  434. struct berval *payload = NULL;
  435. Slapi_DN *replarea_sdn = NULL;
  436. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_release_replica\n", 0, 0, 0 );
  437. PR_ASSERT(NULL != prp);
  438. PR_ASSERT(NULL != prp->conn);
  439. if (!prp->replica_acquired)
  440. return;
  441. windows_conn_start_linger(prp->conn);
  442. prp->replica_acquired = PR_FALSE;
  443. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_release_replica\n", 0, 0, 0 );
  444. }
  445. /* this entry had a password, handle it seperately */
  446. /* http://support.microsoft.com/?kbid=269190 */
  447. static int
  448. send_password_modify(Slapi_DN *sdn, char *password, Private_Repl_Protocol *prp)
  449. {
  450. ConnResult pw_return = 0;
  451. LDAPMod *pw_mods[2];
  452. LDAPMod pw_mod;
  453. struct berval bv = {0};
  454. UChar *unicode_password = NULL;
  455. int32_t unicode_password_length = 0; /* Length in _characters_ */
  456. int32_t buffer_size = 0; /* Size in _characters_ */
  457. UErrorCode error = U_ZERO_ERROR;
  458. char *quoted_password = NULL;
  459. struct berval *bvals[2];
  460. /* AD wants the password in quotes ! */
  461. quoted_password = PR_smprintf("\"%s\"",password);
  462. if (quoted_password)
  463. {
  464. /* Need to UNICODE encode the password here */
  465. /* It's one of those 'ask me first and I will tell you the buffer size' functions */
  466. u_strFromUTF8(NULL, 0, &unicode_password_length, quoted_password, strlen(quoted_password), &error);
  467. buffer_size = unicode_password_length;
  468. unicode_password = (UChar *)slapi_ch_malloc(unicode_password_length * sizeof(UChar));
  469. if (unicode_password) {
  470. error = U_ZERO_ERROR;
  471. u_strFromUTF8(unicode_password, buffer_size, &unicode_password_length, quoted_password, strlen(quoted_password), &error);
  472. bv.bv_len = unicode_password_length * sizeof(UChar);
  473. bv.bv_val = (char*)unicode_password;
  474. bvals[0] = &bv;
  475. bvals[1] = NULL;
  476. pw_mod.mod_type = "UnicodePwd";
  477. pw_mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  478. pw_mod.mod_bvalues = bvals;
  479. pw_mods[0] = &pw_mod;
  480. pw_mods[1] = NULL;
  481. pw_return = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(sdn), pw_mods, NULL, NULL );
  482. slapi_ch_free((void**)&unicode_password);
  483. }
  484. PR_smprintf_free(quoted_password);
  485. }
  486. return pw_return;
  487. }
  488. static int
  489. windows_entry_has_attr_and_value(Slapi_Entry *e, const char *attrname, char *value)
  490. {
  491. int retval = 0;
  492. Slapi_Attr *attr = 0;
  493. if (!e || !attrname)
  494. return retval;
  495. /* see if the entry has the specified attribute name */
  496. if (!slapi_entry_attr_find(e, attrname, &attr) && attr)
  497. {
  498. /* if value is not null, see if the attribute has that
  499. value */
  500. if (!value)
  501. {
  502. retval = 1;
  503. }
  504. else
  505. {
  506. Slapi_Value *v = 0;
  507. int index = 0;
  508. for (index = slapi_attr_first_value(attr, &v);
  509. v && (index != -1);
  510. index = slapi_attr_next_value(attr, index, &v))
  511. {
  512. const char *s = slapi_value_get_string(v);
  513. if (!s)
  514. continue;
  515. if (!strcasecmp(s, value))
  516. {
  517. retval = 1;
  518. break;
  519. }
  520. }
  521. }
  522. }
  523. return retval;
  524. }
  525. static void
  526. windows_is_local_entry_user_or_group(Slapi_Entry *e, int *is_user, int *is_group)
  527. {
  528. *is_user = windows_entry_has_attr_and_value(e,"objectclass","ntuser");
  529. *is_group = windows_entry_has_attr_and_value(e,"objectclass","ntgroup");
  530. }
  531. static void
  532. windows_is_remote_entry_user_or_group(Slapi_Entry *e, int *is_user, int *is_group)
  533. {
  534. *is_user = windows_entry_has_attr_and_value(e,"objectclass","person");
  535. *is_group = windows_entry_has_attr_and_value(e,"objectclass","group");
  536. }
  537. static int
  538. add_remote_entry_allowed(Slapi_Entry *e)
  539. {
  540. /* We say yes if the entry has the ntUserCreateNewAccount attribute set in the case of a user, or the ntGroupDeleteGroup
  541. * attribute set in the case of a group
  542. */
  543. /* Is this a user or a group ? */
  544. int is_user = 0;
  545. int is_group = 0;
  546. char *delete_attr = NULL;
  547. windows_is_local_entry_user_or_group(e,&is_user,&is_group);
  548. if (!is_user && !is_group)
  549. {
  550. /* Neither fish nor foul.. */
  551. return -1;
  552. }
  553. if (is_user && is_group)
  554. {
  555. /* Now that's just really strange... */
  556. return -1;
  557. }
  558. if (is_user)
  559. {
  560. delete_attr = "ntUserCreateNewAccount";
  561. } else
  562. {
  563. delete_attr = "ntGroupCreateNewGroup";
  564. }
  565. /* Now test if the attribute value is set */
  566. return windows_entry_has_attr_and_value(e,delete_attr,"true");
  567. }
  568. static int
  569. delete_remote_entry_allowed(Slapi_Entry *e)
  570. {
  571. /* We say yes if the entry has the ntUserDeleteAccount attribute set in the case of a user, or the ntGroupDeleteGroup
  572. * attribute set in the case of a group
  573. */
  574. /* Is this a user or a group ? */
  575. int is_user = 0;
  576. int is_group = 0;
  577. char *delete_attr = NULL;
  578. windows_is_local_entry_user_or_group(e,&is_user,&is_group);
  579. if (!is_user && !is_group)
  580. {
  581. /* Neither fish nor foul.. */
  582. return -1;
  583. }
  584. if (is_user && is_group)
  585. {
  586. /* Now that's just really strange... */
  587. return -1;
  588. }
  589. if (is_user)
  590. {
  591. delete_attr = "ntUserDeleteAccount";
  592. } else
  593. {
  594. delete_attr = "ntGroupDeleteGroup";
  595. }
  596. /* Now test if the attribute value is set */
  597. return windows_entry_has_attr_and_value(e,delete_attr,"true");
  598. }
  599. static void
  600. windows_make_mods_for_add_retry(Slapi_Entry *local_entry, Slapi_Entry *remote_entry, LDAPMod ***result_mods, int is_user)
  601. {
  602. }
  603. static void
  604. windows_log_add_entry_remote(const Slapi_DN *local_dn,const Slapi_DN *remote_dn)
  605. {
  606. const char* local_dn_string = slapi_sdn_get_dn(local_dn);
  607. const char* remote_dn_string = slapi_sdn_get_dn(remote_dn);
  608. slapi_log_error(SLAPI_LOG_REPL, NULL, "Attempting to add entry %s to AD for local entry %s\n",remote_dn_string,local_dn_string);
  609. }
  610. static ConnResult
  611. process_replay_add(Private_Repl_Protocol *prp, slapi_operation_parameters *op, Slapi_Entry *local_entry, Slapi_DN *local_dn, Slapi_DN *remote_dn, int is_user, int missing_entry, char **password)
  612. {
  613. int remote_add_allowed = add_remote_entry_allowed(local_entry);
  614. ConnResult return_value = 0;
  615. int rc = 0;
  616. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  617. "%s: process_replay_add: dn=\"%s\" (%s,%s)\n",
  618. agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn), missing_entry ? "not present" : "already present" , remote_add_allowed ? "add allowed" : "add not allowed");
  619. if (missing_entry)
  620. {
  621. if (remote_add_allowed) {
  622. LDAPMod **entryattrs = NULL;
  623. Slapi_Entry *mapped_entry = NULL;
  624. /* First map the entry */
  625. rc = windows_create_remote_entry(prp,op->p.p_add.target_entry, remote_dn, &mapped_entry, password);
  626. /* Convert entry to mods */
  627. if (0 == rc && mapped_entry)
  628. {
  629. (void)slapi_entry2mods (mapped_entry , NULL /* &entrydn : We don't need it */, &entryattrs);
  630. slapi_entry_free(mapped_entry);
  631. mapped_entry = NULL;
  632. if (NULL == entryattrs)
  633. {
  634. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_replay_update: Cannot convert entry to LDAPMods.\n",agmt_get_long_name(prp->agmt));
  635. return_value = CONN_LOCAL_ERROR;
  636. }
  637. else
  638. {
  639. windows_log_add_entry_remote(local_dn, remote_dn);
  640. return_value = windows_conn_send_add(prp->conn, slapi_sdn_get_dn(remote_dn), entryattrs, NULL, NULL);
  641. /* It's possible that the entry already exists in AD, in which case we fall back to modify it */
  642. if (return_value)
  643. {
  644. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_replay_update: Cannot replay add operation.\n",agmt_get_long_name(prp->agmt));
  645. }
  646. ldap_mods_free(entryattrs, 1);
  647. entryattrs = NULL;
  648. }
  649. } else
  650. {
  651. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  652. "%s: process_replay_add: failed to create mapped entry dn=\"%s\"\n",agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn));
  653. }
  654. }
  655. } else
  656. {
  657. /* Need to re-play this as a mod */
  658. LDAPMod **mapped_mods = NULL;
  659. Slapi_Entry *remote_entry = NULL;
  660. /* Fetch the remote entry */
  661. rc = windows_get_remote_entry(prp, remote_dn,&remote_entry);
  662. if (0 == rc && remote_entry) {
  663. windows_make_mods_for_add_retry(op->p.p_add.target_entry, remote_entry, &mapped_mods, is_user);
  664. /* It's possible that the mapping process results in an empty mod list, in which case we don't bother with the replay */
  665. if ( mapped_mods == NULL || *(mapped_mods)== NULL )
  666. {
  667. return_value = CONN_OPERATION_SUCCESS;
  668. } else
  669. {
  670. return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn),mapped_mods, NULL,NULL);
  671. }
  672. if (mapped_mods)
  673. {
  674. ldap_mods_free(mapped_mods,1);
  675. mapped_mods = NULL;
  676. }
  677. slapi_entry_free(remote_entry);
  678. }
  679. }
  680. return return_value;
  681. }
  682. /*
  683. * Given a changelog entry, construct the appropriate LDAP operations to sync
  684. * the operation to AD.
  685. */
  686. ConnResult
  687. windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op)
  688. {
  689. ConnResult return_value = 0;
  690. LDAPControl *update_control = NULL; /* No controls used for AD */
  691. int rc = 0;
  692. char *password = NULL;
  693. int is_ours = 0;
  694. int is_user = 0;
  695. int is_group = 0;
  696. Slapi_DN *remote_dn = NULL;
  697. Slapi_DN *local_dn = NULL;
  698. Slapi_Entry *local_entry = NULL;
  699. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_replay_update\n", 0, 0, 0 );
  700. local_dn = slapi_sdn_new_dn_byref( op->target_address.dn );
  701. /* Since we have the target uniqueid in the op structure, let's
  702. * fetch the local entry here using it.
  703. */
  704. rc = windows_get_local_entry_by_uniqueid(prp, op->target_address.uniqueid, &local_entry);
  705. if (rc)
  706. {
  707. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  708. "%s: windows_replay_update: failed to fetch local entry for %s operation dn=\"%s\"\n",
  709. agmt_get_long_name(prp->agmt),
  710. op2string(op->operation_type), op->target_address.dn);
  711. goto error;
  712. }
  713. is_ours = is_subject_of_agreemeent_local(local_entry, prp->agmt);
  714. windows_is_local_entry_user_or_group(local_entry,&is_user,&is_group);
  715. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  716. "%s: windows_replay_update: Looking at %s operation dn=\"%s\" (%s,%s,%s)\n",
  717. agmt_get_long_name(prp->agmt),
  718. op2string(op->operation_type), op->target_address.dn, is_ours ? "ours" : "not ours",
  719. is_user ? "user" : "not user", is_group ? "group" : "not group");
  720. if (is_ours && (is_user || is_group) ) {
  721. int missing_entry = 0;
  722. /* Make the entry's DN */
  723. rc = map_entry_dn_outbound(local_entry,&remote_dn,prp,&missing_entry);
  724. if (rc || NULL == remote_dn)
  725. {
  726. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  727. "%s: windows_replay_update: failed map dn for %s operation dn=\"%s\"\n",
  728. agmt_get_long_name(prp->agmt),
  729. op2string(op->operation_type), op->target_address.dn);
  730. goto error;
  731. }
  732. switch (op->operation_type) {
  733. /* For an ADD operation, we map the entry and then send the operation, which may fail if the peer entry already existed */
  734. case SLAPI_OPERATION_ADD:
  735. return_value = process_replay_add(prp,op,local_entry,local_dn,remote_dn,is_user,missing_entry,&password);
  736. break;
  737. case SLAPI_OPERATION_MODIFY:
  738. {
  739. LDAPMod **mapped_mods = NULL;
  740. windows_map_mods_for_replay(prp,op->p.p_modify.modify_mods, &mapped_mods, is_user, &password);
  741. /* It's possible that the mapping process results in an empty mod list, in which case we don't bother with the replay */
  742. if ( mapped_mods == NULL || *(mapped_mods)== NULL )
  743. {
  744. return_value = CONN_OPERATION_SUCCESS;
  745. } else
  746. {
  747. return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn), mapped_mods, update_control,NULL /* returned controls */);
  748. }
  749. if (mapped_mods)
  750. {
  751. ldap_mods_free(mapped_mods,1);
  752. mapped_mods = NULL;
  753. }
  754. }
  755. break;
  756. case SLAPI_OPERATION_DELETE:
  757. if (delete_remote_entry_allowed(local_entry))
  758. {
  759. return_value = windows_conn_send_delete(prp->conn, slapi_sdn_get_dn(remote_dn), update_control, NULL /* returned controls */);
  760. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  761. "%s: windows_replay_update: deleted remote entry, dn=\"%s\", result=%d\n",
  762. agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn), return_value);
  763. } else
  764. {
  765. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  766. "%s: windows_replay_update: delete not allowed on remote entry, dn=\"%s\"\n",
  767. agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn));
  768. }
  769. break;
  770. case SLAPI_OPERATION_MODRDN:
  771. return_value = windows_conn_send_rename(prp->conn, op->target_address.dn,
  772. op->p.p_modrdn.modrdn_newrdn,
  773. op->p.p_modrdn.modrdn_newsuperior_address.dn,
  774. op->p.p_modrdn.modrdn_deloldrdn,
  775. update_control, NULL /* returned controls */);
  776. break;
  777. default:
  778. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "%s: replay_update: Unknown "
  779. "operation type %d found in changelog - skipping change.\n",
  780. agmt_get_long_name(prp->agmt), op->operation_type);
  781. }
  782. if (password)
  783. {
  784. return_value = send_password_modify(remote_dn, password, prp);
  785. if (return_value)
  786. {
  787. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, "%s: windows_replay_update: update password returned %d\n",
  788. agmt_get_long_name(prp->agmt), return_value );
  789. }
  790. }
  791. } else {
  792. /* We ignore operations that target entries outside of our sync'ed subtree, or which are not Windows users or groups */
  793. }
  794. error:
  795. if (local_entry)
  796. {
  797. slapi_entry_free(local_entry);
  798. }
  799. if (local_dn)
  800. {
  801. slapi_sdn_free (&local_dn);
  802. }
  803. if (remote_dn)
  804. {
  805. slapi_sdn_free(&remote_dn);
  806. }
  807. return return_value;
  808. }
  809. static int
  810. is_straight_mapped_attr(const char *type, int is_user /* or group */)
  811. {
  812. int found = 0;
  813. size_t offset = 0;
  814. char *this_attr = NULL;
  815. char **list = is_user ? windows_user_matching_attributes : windows_group_matching_attributes;
  816. /* Look for the type in the list of straight mapped attrs for the appropriate object type */
  817. while (this_attr = list[offset])
  818. {
  819. if (0 == slapi_attr_type_cmp(this_attr, type, SLAPI_TYPE_CMP_SUBTYPE))
  820. {
  821. found = 1;
  822. break;
  823. }
  824. offset++;
  825. }
  826. return found;
  827. }
  828. static void
  829. windows_map_attr_name(const char *original_type , int to_windows, int is_user, int is_create, char **mapped_type, int *map_dn)
  830. {
  831. char *new_type = NULL;
  832. windows_attribute_map *our_map = is_user ? user_attribute_map : group_attribute_map;
  833. windows_attribute_map *this_map = NULL;
  834. size_t offset = 0;
  835. *mapped_type = NULL;
  836. /* Iterate over the map entries looking for the type we have */
  837. while(this_map = &(our_map[offset]))
  838. {
  839. char *their_name = to_windows ? this_map->windows_attribute_name : this_map->ldap_attribute_name;
  840. char *our_name = to_windows ? this_map->ldap_attribute_name : this_map->windows_attribute_name;
  841. if (NULL == their_name)
  842. {
  843. /* End of the list */
  844. break;
  845. }
  846. if (0 == slapi_attr_type_cmp(original_type, our_name, SLAPI_TYPE_CMP_SUBTYPE))
  847. {
  848. if (!is_create && (this_map->create_type == createonly))
  849. {
  850. /* Skip create-only entries if we're not creating */
  851. } else
  852. {
  853. if ( (this_map->map_type == towindowsonly && to_windows) || (this_map->map_type == fromwindowsonly && !to_windows)
  854. || (this_map->map_type == bidirectional) )
  855. {
  856. new_type = slapi_ch_strdup(their_name);
  857. *map_dn = (this_map->attr_type == dnmap);
  858. break;
  859. }
  860. }
  861. }
  862. offset++;
  863. }
  864. if (new_type)
  865. {
  866. *mapped_type = new_type;
  867. }
  868. }
  869. /*
  870. * Make a new entry suitable for the sync destination (indicated by the to_windows argument).
  871. * Returns the new entry ready to be passed to an LDAP ADD operation, either remote or local.
  872. * Also returns the plaintext value of any password contained in the original entry (only for the
  873. * to_windows direction). This is because passwords must be added to entries after they are added in AD.
  874. * Caller must free the new entry and any password returned.
  875. */
  876. static int
  877. windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_entry, Slapi_DN *remote_sdn, Slapi_Entry **remote_entry, char** password)
  878. {
  879. int retval = 0;
  880. char *entry_string = NULL;
  881. Slapi_Entry *new_entry = NULL;
  882. Slapi_PBlock* pb = NULL;
  883. int rc = 0;
  884. int is_user = 1; /* DBDB need to add code to test for group here */
  885. Slapi_Attr *attr = NULL;
  886. char *username = NULL;
  887. const char *dn_string = NULL;
  888. char *remote_entry_template = NULL;
  889. char *fqusername = NULL;
  890. const char *domain_name = windows_private_get_windows_domain(prp->agmt);
  891. char *remote_user_entry_template =
  892. "dn: %s\n"
  893. "objectclass:top\n"
  894. "objectclass:person\n"
  895. "objectclass:organizationalperson\n"
  896. "objectclass:user\n"
  897. "userPrincipalName:%s\n"
  898. "userAccountControl:512\n";
  899. char *remote_group_entry_template =
  900. "dn: %s\n"
  901. "objectclass:top\n"
  902. "objectclass:group\n";
  903. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_create_remote_entry\n", 0, 0, 0 );
  904. remote_entry_template = is_user ? remote_user_entry_template : remote_group_entry_template;
  905. /* Create a new entry */
  906. /* Give it its DN and samaccountname */
  907. username = extract_ntuserdomainid_from_entry(original_entry);
  908. if (NULL == username)
  909. {
  910. goto error;
  911. }
  912. fqusername = PR_smprintf("%s@%s",username,domain_name);
  913. dn_string = slapi_sdn_get_dn(remote_sdn);
  914. entry_string = slapi_ch_smprintf(remote_entry_template, dn_string, fqusername);
  915. PR_smprintf_free(fqusername);
  916. if (NULL == entry_string)
  917. {
  918. goto error;
  919. }
  920. new_entry = slapi_str2entry(entry_string, 0);
  921. slapi_ch_free((void**)&entry_string);
  922. if (NULL == new_entry)
  923. {
  924. goto error;
  925. }
  926. /* Map the appropriate attributes sourced from the remote entry */
  927. /* Iterate over the local entry's attributes */
  928. for (rc = slapi_entry_first_attr(original_entry, &attr); rc == 0;
  929. rc = slapi_entry_next_attr(original_entry, attr, &attr))
  930. {
  931. Slapi_Value *value = NULL;
  932. char *type = NULL;
  933. Slapi_ValueSet *vs = NULL;
  934. int mapdn = 0;
  935. slapi_attr_get_type( attr, &type );
  936. slapi_attr_get_valueset(attr,&vs);
  937. if ( is_straight_mapped_attr(type,is_user) )
  938. {
  939. /* copy over the attr values */
  940. slapi_entry_add_valueset(new_entry,type,vs);
  941. } else
  942. {
  943. char *new_type = NULL;
  944. windows_map_attr_name(type , 1 /* to windows */, is_user, 1 /* create */, &new_type, &mapdn);
  945. if (new_type)
  946. {
  947. if (mapdn)
  948. {
  949. Slapi_ValueSet *mapped_values = NULL;
  950. map_dn_values(prp,vs,&mapped_values, 1 /* to windows */);
  951. if (mapped_values)
  952. {
  953. slapi_entry_add_valueset(new_entry,new_type,mapped_values);
  954. slapi_valueset_free(mapped_values);
  955. mapped_values = NULL;
  956. }
  957. } else
  958. {
  959. slapi_entry_add_valueset(new_entry,new_type,vs);
  960. }
  961. slapi_ch_free((void**)&new_type);
  962. }
  963. /* password mods are treated specially */
  964. if (0 == slapi_attr_type_cmp(type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, SLAPI_TYPE_CMP_SUBTYPE) )
  965. {
  966. const char *password_value = NULL;
  967. Slapi_Value *value = NULL;
  968. slapi_valueset_first_value(vs,&value);
  969. password_value = slapi_value_get_string(value);
  970. *password = slapi_ch_strdup(password_value);
  971. }
  972. }
  973. if (vs)
  974. {
  975. slapi_valueset_free(vs);
  976. vs = NULL;
  977. }
  978. }
  979. if (remote_entry)
  980. {
  981. *remote_entry = new_entry;
  982. }
  983. error:
  984. if (username)
  985. {
  986. slapi_ch_free((void**)&username);
  987. }
  988. windows_dump_entry("Created new remote entry:\n",new_entry);
  989. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_create_remote_entry: %d\n", retval, 0, 0 );
  990. return retval;
  991. }
  992. /* the entry has already been translated, so be sure to search for ntuserid
  993. and not samaccountname or anything else. */
  994. static Slapi_Entry*
  995. windows_entry_already_exists(Slapi_Entry *e){
  996. int rc = 0;
  997. Slapi_DN *sdn = NULL;
  998. Slapi_Entry *entry = NULL;
  999. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_entry_already_exists\n", 0, 0, 0 );
  1000. sdn = slapi_entry_get_sdn(e);
  1001. rc = slapi_search_internal_get_entry( sdn, NULL, &entry, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION));
  1002. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_entry_already_exists\n", 0, 0, 0 );
  1003. if (rc == LDAP_SUCCESS)
  1004. {
  1005. return entry;
  1006. }
  1007. else
  1008. {
  1009. return NULL;
  1010. }
  1011. }
  1012. static int
  1013. windows_delete_local_entry(Slapi_DN *sdn){
  1014. Slapi_PBlock *pb = NULL;
  1015. int return_value = 0;
  1016. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_delete_local_entry\n", 0, 0, 0 );
  1017. pb = slapi_pblock_new();
  1018. slapi_delete_internal_set_pb(pb, slapi_sdn_get_dn(sdn), NULL, NULL, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
  1019. slapi_delete_internal_pb(pb);
  1020. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
  1021. slapi_pblock_destroy(pb);
  1022. if (return_value) {
  1023. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
  1024. "delete operation on local entry %s returned: %d\n", slapi_sdn_get_dn(sdn), return_value);
  1025. }
  1026. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_delete_local_entry: %d\n", return_value, 0, 0 );
  1027. return return_value;
  1028. }
  1029. static void
  1030. windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod ***returned_mods, int is_user, char** password)
  1031. {
  1032. Slapi_Mods smods = {0};
  1033. Slapi_Mods mapped_smods = {0};
  1034. LDAPMod *mod = NULL;
  1035. int i=0;
  1036. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_map_mods_for_replay\n", 0, 0, 0 );
  1037. /* Iterate through the original mods, looking each attribute type up in the maps for either user or group */
  1038. slapi_mods_init_byref(&smods, original_mods);
  1039. slapi_mods_init(&mapped_smods,10);
  1040. mod = slapi_mods_get_first_mod(&smods);
  1041. while(mod)
  1042. {
  1043. char *attr_type = mod->mod_type;
  1044. int mapdn = 0;
  1045. /* Check to see if this attribute is passed through */
  1046. if (is_straight_mapped_attr(attr_type,is_user)) {
  1047. /* If so then just copy over the mod */
  1048. slapi_mods_add_modbvps(&mapped_smods,mod->mod_op,attr_type,mod->mod_bvalues);
  1049. } else
  1050. {
  1051. char *mapped_type = NULL;
  1052. /* Check if this mod has its attribute type mapped */
  1053. windows_map_attr_name(attr_type,1,is_user,0,&mapped_type, &mapdn);
  1054. if (mapped_type)
  1055. {
  1056. /* If so copy over the mod with new type name */
  1057. if (mapdn)
  1058. {
  1059. Slapi_ValueSet *mapped_values = NULL;
  1060. Slapi_ValueSet *vs = NULL;
  1061. Slapi_Mod smod;
  1062. vs = slapi_valueset_new();
  1063. slapi_mod_init_byref(&smod,mod);
  1064. slapi_valueset_set_from_smod(vs, &smod);
  1065. map_dn_values(prp,vs,&mapped_values, 1 /* to windows */);
  1066. if (mapped_values)
  1067. {
  1068. slapi_mods_add_mod_values(&mapped_smods,mod->mod_op,mapped_type,valueset_get_valuearray(mapped_values));
  1069. slapi_valueset_free(mapped_values);
  1070. mapped_values = NULL;
  1071. }
  1072. slapi_mod_done(&smod);
  1073. slapi_valueset_free(vs);
  1074. } else
  1075. {
  1076. slapi_mods_add_modbvps(&mapped_smods,mod->mod_op,mapped_type,mod->mod_bvalues);
  1077. }
  1078. slapi_ch_free((void**)&mapped_type);
  1079. } else
  1080. {
  1081. /* password mods are treated specially */
  1082. if (0 == slapi_attr_type_cmp(attr_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, SLAPI_TYPE_CMP_SUBTYPE) )
  1083. {
  1084. char *password_value = NULL;
  1085. password_value = mod->mod_bvalues[0]->bv_val;
  1086. *password = slapi_ch_strdup(password_value);
  1087. }
  1088. }
  1089. }
  1090. /* Otherwise we do not copy this mod at all */
  1091. mod = slapi_mods_get_next_mod(&smods);
  1092. }
  1093. slapi_mods_done (&smods);
  1094. /* Extract the mods for the caller */
  1095. *returned_mods = slapi_mods_get_ldapmods_passout(&mapped_smods);
  1096. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_map_mods_for_replay\n", 0, 0, 0 );
  1097. }
  1098. /* Returns non-zero if the attribute value sets are identical */
  1099. static int
  1100. attr_compare_equal(Slapi_Attr *a, Slapi_Attr *b)
  1101. {
  1102. /* For now only handle single values */
  1103. Slapi_Value *va = NULL;
  1104. Slapi_Value *vb = NULL;
  1105. int num_a = 0;
  1106. int num_b = 0;
  1107. int match = 1;
  1108. slapi_attr_get_numvalues(a,&num_a);
  1109. slapi_attr_get_numvalues(b,&num_b);
  1110. if (num_a == num_b)
  1111. {
  1112. slapi_attr_first_value(a, &va);
  1113. slapi_attr_first_value(b, &vb);
  1114. if (va->bv.bv_len == va->bv.bv_len)
  1115. {
  1116. if (0 != memcmp(va->bv.bv_val,vb->bv.bv_val,va->bv.bv_len))
  1117. {
  1118. match = 0;
  1119. }
  1120. } else
  1121. {
  1122. match = 0;
  1123. }
  1124. } else
  1125. {
  1126. match = 0;
  1127. }
  1128. return match;
  1129. }
  1130. /* Helper functions for dirsync result processing */
  1131. /* Is this entry a tombstone ? */
  1132. static int
  1133. is_tombstone(Slapi_Entry *e)
  1134. {
  1135. int retval = 0;
  1136. char *string_deleted = "(isdeleted=*)";
  1137. /* DBDB: we should allocate these filters once and keep them around for better performance */
  1138. Slapi_Filter *filter_deleted = slapi_str2filter( string_deleted );
  1139. /* DBDB: this should be one filter, the code originally tested separately and hasn't been fixed yet */
  1140. if ( (slapi_filter_test_simple( e, filter_deleted ) == 0) )
  1141. {
  1142. retval = 1;
  1143. }
  1144. slapi_filter_free(filter_deleted,1);
  1145. filter_deleted = NULL;
  1146. return retval;
  1147. }
  1148. #define ENTRY_NOTFOUND -1
  1149. #define ENTRY_NOT_UNIQUE -2
  1150. /* Search for an entry in AD */
  1151. static int
  1152. find_entry_by_attr_value_remote(const char *attribute, const char *value, Slapi_Entry **e, Private_Repl_Protocol *prp)
  1153. {
  1154. int retval = 0;
  1155. ConnResult cres = 0;
  1156. char *filter = NULL;
  1157. const char *searchbase = NULL;
  1158. Slapi_Entry *found_entry = NULL;
  1159. filter = PR_smprintf("(%s=%s)",attribute,value);
  1160. searchbase = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt));
  1161. cres = windows_search_entry(prp->conn, (char*)searchbase, filter, &found_entry);
  1162. if (cres)
  1163. {
  1164. retval = -1;
  1165. } else
  1166. {
  1167. if (found_entry)
  1168. {
  1169. *e = found_entry;
  1170. }
  1171. }
  1172. if (filter)
  1173. {
  1174. PR_smprintf_free(filter);
  1175. filter = NULL;
  1176. }
  1177. return retval;
  1178. }
  1179. /* Search for an entry in AD by DN */
  1180. static int
  1181. windows_get_remote_entry (Private_Repl_Protocol *prp, Slapi_DN* remote_dn,Slapi_Entry **remote_entry)
  1182. {
  1183. int retval = 0;
  1184. ConnResult cres = 0;
  1185. char *filter = "(objectclass=*)";
  1186. const char *searchbase = NULL;
  1187. Slapi_Entry *found_entry = NULL;
  1188. searchbase = slapi_sdn_get_dn(remote_dn);
  1189. cres = windows_search_entry(prp->conn, (char*)searchbase, filter, &found_entry);
  1190. if (cres)
  1191. {
  1192. retval = -1;
  1193. } else
  1194. {
  1195. if (found_entry)
  1196. {
  1197. *remote_entry = found_entry;
  1198. }
  1199. }
  1200. return retval;
  1201. }
  1202. static int
  1203. find_entry_by_attr_value(const char *attribute, const char *value, Slapi_Entry **e, const Repl_Agmt *ra)
  1204. {
  1205. Slapi_PBlock *pb = slapi_pblock_new();
  1206. Slapi_Entry **entries = NULL, **ep = NULL;
  1207. Slapi_Entry *entry_found = NULL;
  1208. char *query = NULL;
  1209. int found_or_not = ENTRY_NOTFOUND;
  1210. int rval = 0;
  1211. const char *subtree_dn = NULL;
  1212. int not_unique = 0;
  1213. if (pb == NULL)
  1214. goto done;
  1215. query = slapi_ch_smprintf("(%s=%s)", attribute, value);
  1216. if (query == NULL)
  1217. goto done;
  1218. subtree_dn = slapi_sdn_get_dn(windows_private_get_directory_subtree(ra));
  1219. slapi_search_internal_set_pb(pb, subtree_dn,
  1220. LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL,
  1221. (void *)plugin_get_default_component_id(), 0);
  1222. slapi_search_internal_pb(pb);
  1223. slapi_ch_free((void **)&query);
  1224. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rval);
  1225. if (rval != LDAP_SUCCESS)
  1226. {
  1227. goto done;
  1228. }
  1229. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  1230. if ((entries == NULL) || (entries[0] == NULL))
  1231. {
  1232. goto done;
  1233. }
  1234. entry_found = entries[0];
  1235. for (ep = entries; *ep; ep++) {
  1236. if (not_unique)
  1237. {
  1238. found_or_not = ENTRY_NOT_UNIQUE;
  1239. }
  1240. not_unique = 1;
  1241. }
  1242. done:
  1243. if (entry_found && (found_or_not != ENTRY_NOT_UNIQUE))
  1244. {
  1245. found_or_not = 0;
  1246. *e = slapi_entry_dup(entry_found);
  1247. }
  1248. if (pb)
  1249. {
  1250. slapi_free_search_results_internal(pb);
  1251. slapi_pblock_destroy(pb);
  1252. }
  1253. return found_or_not;
  1254. }
  1255. static int
  1256. find_entry_by_username(const char *username, Slapi_Entry **e, const Repl_Agmt *ra)
  1257. {
  1258. return find_entry_by_attr_value("ntUserDomainId",username,e,ra);
  1259. }
  1260. /* Find an entry in the local server given its GUID, or return ENTRY_NOTFOUND */
  1261. static int
  1262. find_entry_by_guid(const char *guid, Slapi_Entry **e, const Repl_Agmt *ra)
  1263. {
  1264. return find_entry_by_attr_value("ntUniqueId",guid,e,ra);
  1265. }
  1266. /* Remove dashes from a GUID string */
  1267. static void
  1268. dedash(char *str)
  1269. {
  1270. char *p = str;
  1271. char c = '\0';
  1272. while (c = *p)
  1273. {
  1274. if ('-' == c)
  1275. {
  1276. /* Move on down please */
  1277. char *q = p;
  1278. char *r = q + 1;
  1279. while (*r)
  1280. {
  1281. *q++ = *r++;
  1282. }
  1283. *q = '\0';
  1284. }
  1285. p++;
  1286. }
  1287. }
  1288. /* For reasons not clear, the GUID returned in the tombstone DN is all
  1289. * messed up, like the guy in the movie 'the fly' after he want in the tranporter device */
  1290. static void
  1291. decrypt(char *guid)
  1292. {
  1293. static int decrypt_offsets[] = {6,7,4,5,2,3,0,1,10,11,8,9,14,15,12,13,16,17,18,19,
  1294. 20,21,22,23,24,25,26,27,28,29,30,31};
  1295. char *p = guid;
  1296. int i = 0;
  1297. char *cpy = slapi_ch_strdup(guid);
  1298. while (*p && i < (sizeof(decrypt_offsets)/sizeof(int)))
  1299. {
  1300. *p = cpy[decrypt_offsets[i]];
  1301. p++;
  1302. i++;
  1303. }
  1304. slapi_ch_free((void**)&cpy);
  1305. }
  1306. static char*
  1307. extract_guid_from_tombstone_dn(const char *dn)
  1308. {
  1309. char *guid = NULL;
  1310. char *colon_offset = NULL;
  1311. char *comma_offset = NULL;
  1312. /* example DN of tombstone:
  1313. "CN=WDel Userdb1\\\nDEL:551706bc-ecf2-4b38-9284-9a8554171d69,CN=Deleted Objects,DC=magpie,DC=com" */
  1314. /* First find the 'DEL:' */
  1315. colon_offset = strchr(dn,':');
  1316. /* Then scan forward to the next ',' */
  1317. comma_offset = strchr(dn,',');
  1318. /* The characters inbetween are the GUID, copy them to a new string and return to the caller */
  1319. if (comma_offset && colon_offset && comma_offset > colon_offset) {
  1320. guid = slapi_ch_malloc(comma_offset - colon_offset);
  1321. strncpy(guid,colon_offset+1,(comma_offset-colon_offset)-1);
  1322. guid[comma_offset-colon_offset-1] = '\0';
  1323. /* Finally remove the dashes since we don't store them on our side */
  1324. dedash(guid);
  1325. decrypt(guid);
  1326. }
  1327. return guid;
  1328. }
  1329. static char *
  1330. convert_to_hex(Slapi_Value *val)
  1331. {
  1332. int offset = 0;
  1333. const struct berval *bvp = NULL;
  1334. int length = 0;
  1335. char *result = NULL;
  1336. bvp = slapi_value_get_berval(val);
  1337. if (bvp)
  1338. {
  1339. char *new_buffer = NULL;
  1340. length = bvp->bv_len;
  1341. for (offset = 0; offset < length; offset++)
  1342. {
  1343. unsigned char byte = ((unsigned char*)(bvp->bv_val))[offset];
  1344. new_buffer = PR_sprintf_append(new_buffer, "%02x", byte );
  1345. }
  1346. if (new_buffer)
  1347. {
  1348. result = new_buffer;
  1349. }
  1350. }
  1351. return result;
  1352. }
  1353. static char*
  1354. extract_guid_from_entry(Slapi_Entry *e)
  1355. {
  1356. char *guid = NULL;
  1357. Slapi_Value *val = NULL;
  1358. Slapi_Attr *attr = NULL;
  1359. slapi_entry_attr_find(e, "objectGUID", &attr);
  1360. if (attr)
  1361. {
  1362. slapi_attr_first_value(attr, &val);
  1363. if (val) {
  1364. guid = convert_to_hex(val);
  1365. }
  1366. }
  1367. return guid;
  1368. }
  1369. static void
  1370. extract_guid_from_entry_bv(Slapi_Entry *e, const struct berval **bv)
  1371. {
  1372. Slapi_Value *val = NULL;
  1373. Slapi_Attr *attr = NULL;
  1374. slapi_entry_attr_find(e, "objectGUID", &attr);
  1375. if (attr)
  1376. {
  1377. slapi_attr_first_value(attr, &val);
  1378. if (val) {
  1379. *bv = slapi_value_get_berval(val);
  1380. }
  1381. }
  1382. }
  1383. static char*
  1384. extract_username_from_entry(Slapi_Entry *e)
  1385. {
  1386. char *uid = NULL;
  1387. uid = slapi_entry_attr_get_charptr(e,"samAccountName");
  1388. return uid;
  1389. }
  1390. static char*
  1391. extract_ntuserdomainid_from_entry(Slapi_Entry *e)
  1392. {
  1393. char *uid = NULL;
  1394. uid = slapi_entry_attr_get_charptr(e,"ntuserdomainid");
  1395. return uid;
  1396. }
  1397. static Slapi_DN *make_dn_from_guid(char *guid)
  1398. {
  1399. Slapi_DN *new_dn = NULL;
  1400. char *dn_string = NULL;
  1401. if (guid)
  1402. {
  1403. new_dn = slapi_sdn_new();
  1404. dn_string = PR_smprintf("<GUID=%s>",guid);
  1405. slapi_sdn_init_dn_byval(new_dn,dn_string);
  1406. PR_smprintf_free(dn_string);
  1407. }
  1408. /* dn string is now inside the Slapi_DN, and will be freed by its owner */
  1409. return new_dn;
  1410. }
  1411. /* Given a non-tombstone entry, return the DN of its peer in AD (whether present or not) */
  1412. static int
  1413. map_entry_dn_outbound(Slapi_Entry *e, const Slapi_DN **dn, Private_Repl_Protocol *prp, int *missing_entry)
  1414. {
  1415. int retval = 0;
  1416. char *guid = NULL;
  1417. Slapi_DN *new_dn = NULL;
  1418. /* To find the DN of the peer entry we first look for an ntUniqueId attribute
  1419. * on the local entry. If that's present, we generate a GUID-form DN.
  1420. * If there's no GUID, then we look for an ntUserDomainId attribute
  1421. * on the entry. If that's present we attempt to search for an entry with
  1422. * that samaccountName attribute value in AD. If we don't find any matching
  1423. * entry we generate a new DN using the entry's cn. If later, we find that
  1424. * this entry already exists, we handle that problem at the time. We don't
  1425. * check here.
  1426. */
  1427. *missing_entry = 0;
  1428. guid = slapi_entry_attr_get_charptr(e,"ntUniqueId");
  1429. if (guid)
  1430. {
  1431. new_dn = make_dn_from_guid(guid);
  1432. slapi_ch_free((void**)&guid);
  1433. } else
  1434. {
  1435. /* No GUID found, try ntUserDomainId */
  1436. Slapi_Entry *remote_entry = NULL;
  1437. char *username = slapi_entry_attr_get_charptr(e,"ntUserDomainId");
  1438. if (username) {
  1439. retval = find_entry_by_attr_value_remote("samAccountName",username,&remote_entry,prp);
  1440. if (0 == retval && remote_entry)
  1441. {
  1442. /* Get the entry's DN */
  1443. new_dn = slapi_sdn_new();
  1444. slapi_sdn_copy(slapi_entry_get_sdn_const(remote_entry), new_dn);
  1445. } else {
  1446. if (0 == retval)
  1447. {
  1448. const char *suffix = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt));
  1449. char *new_dn_string = NULL;
  1450. char *cn_string = NULL;
  1451. *missing_entry = 1;
  1452. /* This means that we failed to find a peer entry */
  1453. /* In that case we need to generate the DN that we want to use */
  1454. /* Generated DN's take the form :
  1455. cn=<cn from local entry>, ... in the case that the local entry has a cn, OR
  1456. cn=<ntuserdomainid attribute value>, ... in the case that the local entry doesn't have a CN
  1457. */
  1458. cn_string = slapi_entry_attr_get_charptr(e,"cn");
  1459. if (!cn_string)
  1460. {
  1461. cn_string = slapi_entry_attr_get_charptr(e,"ntuserdomainid");
  1462. }
  1463. if (cn_string)
  1464. {
  1465. new_dn_string = PR_smprintf("cn=%s,%s",cn_string,suffix);
  1466. if (new_dn_string)
  1467. {
  1468. new_dn = slapi_sdn_new_dn_byval(new_dn_string);
  1469. PR_smprintf_free(new_dn_string);
  1470. }
  1471. slapi_ch_free((void**)&cn_string);
  1472. }
  1473. } else
  1474. {
  1475. /* This means that we failed to talk to the AD for some reason, the operation should be re-tried */
  1476. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1477. "%s: map_entry_dn_outbound: failed to fetch entry from AD: dn=\"%s\", err=%d\n",
  1478. agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)), retval);
  1479. retval = -1;
  1480. }
  1481. }
  1482. slapi_ch_free((void**)&username);
  1483. }
  1484. if (remote_entry)
  1485. {
  1486. slapi_entry_free(remote_entry);
  1487. }
  1488. }
  1489. if (new_dn)
  1490. {
  1491. *dn = new_dn;
  1492. }
  1493. return retval;
  1494. }
  1495. /* Given a tombstone entry, return the DN of its peer in this server (if present) */
  1496. static int
  1497. map_tombstone_dn_inbound(Slapi_Entry *e, const Slapi_DN **dn, const Repl_Agmt *ra)
  1498. {
  1499. int retval = 0;
  1500. Slapi_DN *new_dn = NULL;
  1501. char *guid = NULL;
  1502. const char *dn_string = NULL;
  1503. Slapi_Entry *matching_entry = NULL;
  1504. /* To map a tombstone's DN we need to first extract the entry's objectGUID from the DN
  1505. * CN=vpdxtAD_07\
  1506. DEL:d4ca4e16-e35b-400d-834a-f02db600f3fa,CN=Deleted Objects,DC=magpie,DC=com
  1507. */
  1508. *dn = NULL;
  1509. dn_string = slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)); /* This is a pointer from inside the sdn, no need to free */
  1510. guid = extract_guid_from_tombstone_dn(dn_string);
  1511. if (guid)
  1512. {
  1513. retval = find_entry_by_guid(guid,&matching_entry,ra);
  1514. if (retval)
  1515. {
  1516. if (ENTRY_NOTFOUND == retval)
  1517. {
  1518. } else
  1519. {
  1520. if (ENTRY_NOT_UNIQUE == retval)
  1521. {
  1522. } else
  1523. {
  1524. /* A real error */
  1525. }
  1526. }
  1527. } else
  1528. {
  1529. /* We found the matching entry : get its DN */
  1530. new_dn = slapi_sdn_dup(slapi_entry_get_sdn_const(matching_entry));
  1531. }
  1532. }
  1533. if (new_dn)
  1534. {
  1535. *dn = new_dn;
  1536. }
  1537. if (guid)
  1538. {
  1539. slapi_ch_free((void**)&guid);
  1540. }
  1541. if (matching_entry)
  1542. {
  1543. slapi_entry_free(matching_entry);
  1544. }
  1545. return retval;
  1546. }
  1547. /* Given a non-tombstone entry, return the DN of its peer in this server (whether present or not) */
  1548. static int
  1549. map_entry_dn_inbound(Slapi_Entry *e, const Slapi_DN **dn, const Repl_Agmt *ra)
  1550. {
  1551. int retval = 0;
  1552. Slapi_DN *new_dn = NULL;
  1553. char *guid = NULL;
  1554. char *username = NULL;
  1555. Slapi_Entry *matching_entry = NULL;
  1556. int is_user = 0;
  1557. int is_group = 0;
  1558. /* To map a non-tombstone's DN we need to first try to look it up by GUID.
  1559. * If we do not find it, then we need to generate the DN that it would have if added as a new entry.
  1560. */
  1561. *dn = NULL;
  1562. windows_is_remote_entry_user_or_group(e,&is_user,&is_group);
  1563. guid = extract_guid_from_entry(e);
  1564. if (guid)
  1565. {
  1566. retval = find_entry_by_guid(guid,&matching_entry,ra);
  1567. if (retval)
  1568. {
  1569. if (ENTRY_NOTFOUND == retval)
  1570. {
  1571. } else
  1572. {
  1573. if (ENTRY_NOT_UNIQUE == retval)
  1574. {
  1575. } else
  1576. {
  1577. /* A real error */
  1578. goto error;
  1579. }
  1580. }
  1581. } else
  1582. {
  1583. /* We found the matching entry : get its DN */
  1584. new_dn = slapi_sdn_dup(slapi_entry_get_sdn_const(matching_entry));
  1585. }
  1586. }
  1587. /* If we failed to lookup by guid, try samaccountname */
  1588. if (NULL == new_dn)
  1589. {
  1590. username = extract_username_from_entry(e);
  1591. if (username) {
  1592. retval = find_entry_by_username(username,&matching_entry,ra);
  1593. if (retval)
  1594. {
  1595. if (ENTRY_NOTFOUND == retval)
  1596. {
  1597. } else
  1598. {
  1599. if (ENTRY_NOT_UNIQUE == retval)
  1600. {
  1601. } else
  1602. {
  1603. /* A real error */
  1604. goto error;
  1605. }
  1606. }
  1607. } else
  1608. {
  1609. /* We found the matching entry : get its DN */
  1610. new_dn = slapi_sdn_dup(slapi_entry_get_sdn_const(matching_entry));
  1611. }
  1612. }
  1613. }
  1614. /* If we couldn't find a matching entry by either method, then we need to invent a new DN */
  1615. if (NULL == new_dn)
  1616. {
  1617. /* The new DN has the form: uid=<samaccountname>,<sync'ed subtree> */
  1618. /* If an entry with this DN already exists, we fail and return no DN
  1619. * this is because we don't want to second-guess what the admin wants here:
  1620. * they may want to associate this existing entry with the peer AD entry,
  1621. * but if they intend that we say they must add the ntDomainUserId attribute to
  1622. * that entry.
  1623. */
  1624. char *new_dn_string = NULL;
  1625. if (username)
  1626. {
  1627. const char *suffix = slapi_sdn_get_dn(windows_private_get_directory_subtree(ra));
  1628. /* Local DNs for users and groups are different */
  1629. if (is_user)
  1630. {
  1631. new_dn_string = PR_smprintf("uid=%s,%s",username,suffix);
  1632. } else
  1633. {
  1634. new_dn_string = PR_smprintf("cn=%s,%s",username,suffix);
  1635. }
  1636. new_dn = slapi_sdn_new_dn_byval(new_dn_string);
  1637. PR_smprintf_free(new_dn_string);
  1638. /* Clear any earlier error */
  1639. retval = 0;
  1640. } else
  1641. {
  1642. /* Error, no username */
  1643. }
  1644. }
  1645. if (new_dn)
  1646. {
  1647. *dn = new_dn;
  1648. }
  1649. error:
  1650. if (guid)
  1651. {
  1652. PR_smprintf_free(guid);
  1653. }
  1654. if (matching_entry)
  1655. {
  1656. slapi_entry_free(matching_entry);
  1657. }
  1658. if (username)
  1659. {
  1660. slapi_ch_free((void **) &username);
  1661. }
  1662. return retval;
  1663. }
  1664. /* Tests if the entry is subject to our agreement (i.e. is it in the sync'ed subtree in this server, and is it the right objectclass
  1665. * and does it have the right attribute values for sync ?)
  1666. */
  1667. static int
  1668. is_subject_of_agreemeent_local(const Slapi_Entry *local_entry, const Repl_Agmt *ra)
  1669. {
  1670. int retval = 0;
  1671. int is_in_subtree = 0;
  1672. const Slapi_DN *agreement_subtree = NULL;
  1673. /* First test for the sync'ed subtree */
  1674. agreement_subtree = windows_private_get_directory_subtree(ra);
  1675. if (NULL == agreement_subtree)
  1676. {
  1677. goto error;
  1678. }
  1679. is_in_subtree = slapi_sdn_scope_test(slapi_entry_get_sdn_const(local_entry), agreement_subtree, LDAP_SCOPE_SUBTREE);
  1680. if (is_in_subtree)
  1681. {
  1682. /* Next test for the correct kind of entry */
  1683. if (local_entry) {
  1684. /* DBDB: we should allocate these filters once and keep them around for better performance */
  1685. char *string_filter = "(&(|(objectclass=ntuser)(objectclass=ntgroup))(ntUserDomainId=*))";
  1686. Slapi_Filter *filter = slapi_str2filter( string_filter );
  1687. if (slapi_filter_test_simple( (Slapi_Entry*)local_entry, filter ) == 0)
  1688. {
  1689. retval = 1;
  1690. }
  1691. slapi_filter_free(filter,1);
  1692. filter = NULL;
  1693. } else
  1694. {
  1695. /* Error: couldn't find the entry */
  1696. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
  1697. "failed to find entry in is_subject_of_agreemeent_local: %d\n", retval);
  1698. retval = 0;
  1699. }
  1700. }
  1701. error:
  1702. return retval;
  1703. }
  1704. /* Tests if the entry is subject to our agreement (i.e. is it in the sync'ed subtree in AD and either a user or a group ?) */
  1705. static int
  1706. is_subject_of_agreemeent_remote(Slapi_Entry *e, const Repl_Agmt *ra)
  1707. {
  1708. int retval = 0;
  1709. int is_in_subtree = 0;
  1710. const Slapi_DN *agreement_subtree = NULL;
  1711. /* First test for the sync'ed subtree */
  1712. agreement_subtree = windows_private_get_windows_subtree(ra);
  1713. if (NULL == agreement_subtree)
  1714. {
  1715. goto error;
  1716. }
  1717. is_in_subtree = slapi_sdn_scope_test(slapi_entry_get_sdn_const(e), agreement_subtree, LDAP_SCOPE_SUBTREE);
  1718. if (is_in_subtree)
  1719. {
  1720. retval = 1;
  1721. }
  1722. error:
  1723. return retval;
  1724. }
  1725. static int
  1726. windows_create_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,const Slapi_DN* local_sdn)
  1727. {
  1728. int retval = 0;
  1729. char *entry_string = NULL;
  1730. Slapi_Entry *local_entry = NULL;
  1731. Slapi_PBlock* pb = NULL;
  1732. int is_user = 0;
  1733. int is_group = 0;
  1734. char *local_entry_template = NULL;
  1735. char *username = extract_username_from_entry(remote_entry);
  1736. Slapi_Attr *attr = NULL;
  1737. int rc = 0;
  1738. char *guid_str = NULL;
  1739. char *local_user_entry_template =
  1740. "dn: %s\n"
  1741. "objectclass:top\n"
  1742. "objectclass:organizationalperson\n"
  1743. "objectclass:inetOrgPerson\n"
  1744. "objectclass:ntUser\n"
  1745. "ntUserDeleteAccount:true\n"
  1746. "uid:%s\n";
  1747. char *local_group_entry_template =
  1748. "dn: %s\n"
  1749. "objectclass:top\n"
  1750. "objectclass:groupofuniquenames\n"
  1751. "objectclass:ntGroup\n"
  1752. "objectclass:mailGroup\n"
  1753. "ntGroupDeleteGroup:true\n"
  1754. "cn:%s\n";
  1755. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_create_local_entry\n", 0, 0, 0 );
  1756. windows_is_remote_entry_user_or_group(remote_entry,&is_user,&is_group);
  1757. local_entry_template = is_user ? local_user_entry_template : local_group_entry_template;
  1758. /* Create a new entry */
  1759. /* Give it its DN and username */
  1760. entry_string = slapi_ch_smprintf(local_entry_template,slapi_sdn_get_dn(local_sdn),username, username);
  1761. if (NULL == entry_string)
  1762. {
  1763. goto error;
  1764. }
  1765. local_entry = slapi_str2entry(entry_string, 0);
  1766. slapi_ch_free((void**)&entry_string);
  1767. if (NULL == local_entry)
  1768. {
  1769. goto error;
  1770. }
  1771. /* Map the appropriate attributes sourced from the remote entry */
  1772. for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0;
  1773. rc = slapi_entry_next_attr(remote_entry, attr, &attr))
  1774. {
  1775. Slapi_Value *value = NULL;
  1776. char *type = NULL;
  1777. Slapi_ValueSet *vs = NULL;
  1778. int mapdn = 0;
  1779. slapi_attr_get_type( attr, &type );
  1780. slapi_attr_get_valueset(attr,&vs);
  1781. if ( is_straight_mapped_attr(type,is_user) )
  1782. {
  1783. /* copy over the attr values */
  1784. slapi_entry_add_valueset(local_entry,type,vs);
  1785. } else
  1786. {
  1787. char *new_type = NULL;
  1788. windows_map_attr_name(type , 0 /* from windows */, is_user, 1 /* create */, &new_type, &mapdn);
  1789. if (new_type)
  1790. {
  1791. if (mapdn)
  1792. {
  1793. Slapi_ValueSet *mapped_values = NULL;
  1794. map_dn_values(prp,vs,&mapped_values, 0 /* from windows */);
  1795. if (mapped_values)
  1796. {
  1797. slapi_entry_add_valueset(local_entry,new_type,mapped_values);
  1798. slapi_valueset_free(mapped_values);
  1799. mapped_values = NULL;
  1800. }
  1801. } else
  1802. {
  1803. slapi_entry_add_valueset(local_entry,new_type,vs);
  1804. }
  1805. slapi_ch_free((void**)&new_type);
  1806. }
  1807. }
  1808. if (vs)
  1809. {
  1810. slapi_valueset_free(vs);
  1811. vs = NULL;
  1812. }
  1813. }
  1814. /* Copy over the GUID */
  1815. guid_str = extract_guid_from_entry(remote_entry);
  1816. if (guid_str)
  1817. {
  1818. slapi_entry_add_string(local_entry,"ntUniqueId",guid_str);
  1819. } else
  1820. {
  1821. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
  1822. "extract_guid_from_entry entry %s failed to extract the guid\n", slapi_sdn_get_dn(local_sdn));
  1823. /* Fatal error : need the guid */
  1824. goto error;
  1825. }
  1826. /* Store it */
  1827. windows_dump_entry("Adding new local entry",local_entry);
  1828. pb = slapi_pblock_new();
  1829. slapi_add_entry_internal_set_pb(pb, local_entry, NULL,repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),0);
  1830. slapi_add_internal_pb(pb);
  1831. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &retval);
  1832. if (retval) {
  1833. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
  1834. "add operation of entry %s returned: %d\n", slapi_sdn_get_dn(local_sdn), retval);
  1835. }
  1836. error:
  1837. if (pb)
  1838. {
  1839. slapi_pblock_destroy(pb);
  1840. }
  1841. if (username)
  1842. {
  1843. slapi_ch_free((void**)&username);
  1844. }
  1845. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_create_local_entry\n", 0, 0, 0 );
  1846. return retval;
  1847. }
  1848. static int
  1849. windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,Slapi_Entry *local_entry)
  1850. {
  1851. int retval = 0;
  1852. Slapi_Mods smods = {0};
  1853. Slapi_Attr *attr = NULL;
  1854. int do_modify = 0;
  1855. int is_user = 0;
  1856. int is_group = 0;
  1857. int rc = 0;
  1858. Slapi_PBlock *pb = NULL;
  1859. /* Iterate over the attributes on the remote entry, updating the local entry where appropriate */
  1860. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_update_local_entry\n", 0, 0, 0 );
  1861. windows_is_remote_entry_user_or_group(remote_entry,&is_user,&is_group);
  1862. slapi_mods_init (&smods, 0);
  1863. for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0;
  1864. rc = slapi_entry_next_attr(remote_entry, attr, &attr))
  1865. {
  1866. int is_present_local = 0;
  1867. Slapi_Value *value = NULL;
  1868. char *type = NULL;
  1869. Slapi_ValueSet *vs = NULL;
  1870. char *local_type = NULL;
  1871. Slapi_Attr *local_attr = NULL;
  1872. int is_guid = 0;
  1873. int mapdn = 0;
  1874. slapi_attr_get_type( attr, &type );
  1875. slapi_attr_get_valueset(attr,&vs);
  1876. /* First determine what we will do with this attr */
  1877. /* If it's a GUID, we need to take special action */
  1878. if (0 == slapi_attr_type_cmp(type,"objectGuid",SLAPI_TYPE_CMP_SUBTYPE))
  1879. {
  1880. is_guid = 1;
  1881. local_type = slapi_ch_strdup("ntUniqueId");
  1882. } else
  1883. {
  1884. if ( is_straight_mapped_attr(type,is_user) ) {
  1885. local_type = slapi_ch_strdup(type);
  1886. } else {
  1887. windows_map_attr_name(type , 0 /* from windows */, is_user, 0 /* not create */, &local_type, &mapdn);
  1888. }
  1889. is_guid = 0;
  1890. }
  1891. if (NULL == local_type)
  1892. {
  1893. /* Means we do not map this attribute */
  1894. if (vs)
  1895. {
  1896. slapi_valueset_free(vs);
  1897. vs = NULL;
  1898. }
  1899. continue;
  1900. }
  1901. slapi_entry_attr_find(local_entry,local_type,&local_attr);
  1902. is_present_local = (NULL == local_attr) ? 0 : 1;
  1903. /* Is the attribute present on the local entry ? */
  1904. if (is_present_local && !is_guid)
  1905. {
  1906. int values_equal = attr_compare_equal(attr,local_attr);
  1907. /* If it is then we need to replace the local values with the remote values if they are different */
  1908. if (!values_equal)
  1909. {
  1910. if (mapdn)
  1911. {
  1912. Slapi_ValueSet *mapped_values = NULL;
  1913. map_dn_values(prp,vs,&mapped_values, 1 /* to windows */);
  1914. if (mapped_values)
  1915. {
  1916. slapi_mods_add_mod_values(&smods,LDAP_MOD_REPLACE,local_type,valueset_get_valuearray(mapped_values));
  1917. slapi_valueset_free(mapped_values);
  1918. mapped_values = NULL;
  1919. }
  1920. } else
  1921. {
  1922. slapi_mods_add_mod_values(&smods,LDAP_MOD_REPLACE,local_type,valueset_get_valuearray(vs));
  1923. }
  1924. do_modify = 1;
  1925. } else
  1926. {
  1927. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
  1928. "windows_update_local_entry: %s, %s : values are equal\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(local_entry)), local_type);
  1929. }
  1930. } else
  1931. {
  1932. if (!is_present_local)
  1933. {
  1934. /* If it is currently absent, then we add the value from the remote entry */
  1935. if (is_guid)
  1936. {
  1937. /* Translate the guid value */
  1938. char *guid = extract_guid_from_entry(remote_entry);
  1939. if (guid)
  1940. {
  1941. slapi_mods_add_string(&smods,LDAP_MOD_ADD,local_type,guid);
  1942. slapi_ch_free((void**)&guid);
  1943. }
  1944. } else
  1945. {
  1946. slapi_mods_add_mod_values(&smods,LDAP_MOD_ADD,local_type,valueset_get_valuearray(vs));
  1947. }
  1948. do_modify = 1;
  1949. }
  1950. }
  1951. if (vs)
  1952. {
  1953. slapi_valueset_free(vs);
  1954. vs = NULL;
  1955. }
  1956. if (local_type)
  1957. {
  1958. slapi_ch_free((void**)&local_type);
  1959. local_type = NULL;
  1960. }
  1961. }
  1962. /* Now perform the modify if we need to */
  1963. if (do_modify)
  1964. {
  1965. int rc = 0;
  1966. pb = slapi_pblock_new();
  1967. if (pb)
  1968. {
  1969. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
  1970. "modifying entry: %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(local_entry)));
  1971. slapi_modify_internal_set_pb (pb, slapi_entry_get_ndn(local_entry), slapi_mods_get_ldapmods_byref(&smods), NULL, NULL,
  1972. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  1973. slapi_modify_internal_pb (pb);
  1974. slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1975. if (rc)
  1976. {
  1977. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
  1978. "windows_update_local_entry: failed to modify entry %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(local_entry)));
  1979. }
  1980. slapi_pblock_destroy(pb);
  1981. } else
  1982. {
  1983. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
  1984. "failed to make pb in windows_update_local_entry\n");
  1985. }
  1986. } else
  1987. {
  1988. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
  1989. "no mods generated for entry: %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(remote_entry)));
  1990. }
  1991. slapi_mods_done(&smods);
  1992. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_update_local_entry: %d\n", retval, 0, 0 );
  1993. return retval;
  1994. }
  1995. static int
  1996. windows_process_total_add(Private_Repl_Protocol *prp,Slapi_Entry *e, Slapi_DN* remote_dn)
  1997. {
  1998. int retval = 0;
  1999. LDAPMod **entryattrs = NULL;
  2000. Slapi_Entry *mapped_entry = NULL;
  2001. char *password = NULL;
  2002. const Slapi_DN* local_dn = NULL;
  2003. /* First map the entry */
  2004. local_dn = slapi_entry_get_sdn_const(e);
  2005. retval = windows_create_remote_entry(prp, e, remote_dn, &mapped_entry, &password);
  2006. /* Convert entry to mods */
  2007. if (0 == retval && mapped_entry)
  2008. {
  2009. (void)slapi_entry2mods (mapped_entry , NULL /* &entrydn : We don't need it */, &entryattrs);
  2010. slapi_entry_free(mapped_entry);
  2011. mapped_entry = NULL;
  2012. if (NULL == entryattrs)
  2013. {
  2014. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_replay_update: Cannot convert entry to LDAPMods.\n",agmt_get_long_name(prp->agmt));
  2015. retval = CONN_LOCAL_ERROR;
  2016. }
  2017. else
  2018. {
  2019. windows_log_add_entry_remote(local_dn, remote_dn);
  2020. retval = windows_conn_send_add(prp->conn, slapi_sdn_get_dn(remote_dn), entryattrs, NULL, NULL /* returned controls */);
  2021. /* It's possible that the entry already exists in AD, in which case we fall back to modify it */
  2022. if (retval)
  2023. {
  2024. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_replay_update: Cannot replay add operation.\n",agmt_get_long_name(prp->agmt));
  2025. }
  2026. ldap_mods_free(entryattrs, 1);
  2027. entryattrs = NULL;
  2028. }
  2029. }
  2030. return retval;
  2031. }
  2032. static int
  2033. windows_process_total_delete(Private_Repl_Protocol *prp,Slapi_Entry *e, Slapi_DN* remote_dn)
  2034. {
  2035. int retval = 0;
  2036. if (delete_remote_entry_allowed(e))
  2037. {
  2038. retval = windows_conn_send_delete(prp->conn, slapi_sdn_get_dn(remote_dn), NULL, NULL /* returned controls */);
  2039. }
  2040. return retval;
  2041. }
  2042. /* Entry point for the total protocol */
  2043. int windows_process_total_entry(Private_Repl_Protocol *prp,Slapi_Entry *e)
  2044. {
  2045. int retval = 0;
  2046. int is_ours = 0;
  2047. int is_tombstone = 0;
  2048. Slapi_DN *remote_dn = NULL;
  2049. int missing_entry = 0;
  2050. const Slapi_DN *local_dn = slapi_entry_get_sdn_const(e);
  2051. /* First check if the entry is for us */
  2052. is_ours = is_subject_of_agreemeent_local(e, prp->agmt);
  2053. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2054. "%s: windows_process_total_entry: Looking dn=\"%s\" (%s)\n",
  2055. agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)), is_ours ? "ours" : "not ours");
  2056. if (is_ours)
  2057. {
  2058. retval = map_entry_dn_outbound(e,&remote_dn,prp,&missing_entry);
  2059. if (retval || NULL == remote_dn)
  2060. {
  2061. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2062. "%s: windows_replay_update: failed map dn for total update dn=\"%s\"\n",
  2063. agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(local_dn));
  2064. goto error;
  2065. }
  2066. /* Either the entry is a tombstone, or not a tombstone */
  2067. if (is_tombstone)
  2068. {
  2069. retval = windows_process_total_delete(prp,e,remote_dn);
  2070. } else
  2071. {
  2072. retval = windows_process_total_add(prp,e,remote_dn);
  2073. }
  2074. }
  2075. if (remote_dn)
  2076. {
  2077. slapi_sdn_free(&remote_dn);
  2078. }
  2079. error:
  2080. return retval;
  2081. }
  2082. int
  2083. windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *uniqueid, char ** attrs, Slapi_Entry **ret_entry , void * component_identity)
  2084. {
  2085. Slapi_Entry **entries = NULL;
  2086. Slapi_PBlock *int_search_pb = NULL;
  2087. int rc = 0;
  2088. char *filter_string = NULL;
  2089. const Slapi_DN *local_subtree = NULL;
  2090. *ret_entry = NULL;
  2091. local_subtree = windows_private_get_directory_subtree(prp->agmt);
  2092. filter_string = PR_smprintf("(&(|(objectclass=*)(objectclass=ldapsubentry)(objectclass=nsTombstone))(nsUniqueid=%s))",uniqueid);
  2093. int_search_pb = slapi_pblock_new ();
  2094. slapi_search_internal_set_pb ( int_search_pb, slapi_sdn_get_dn(local_subtree), LDAP_SCOPE_SUBTREE, filter_string,
  2095. attrs ,
  2096. 0 /* attrsonly */, NULL /* controls */,
  2097. NULL /* uniqueid */,
  2098. component_identity, 0 /* actions */ );
  2099. slapi_search_internal_pb ( int_search_pb );
  2100. slapi_pblock_get( int_search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
  2101. if ( LDAP_SUCCESS == rc ) {
  2102. slapi_pblock_get( int_search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries );
  2103. if ( NULL != entries && NULL != entries[ 0 ]) {
  2104. Slapi_Entry *temp_entry = NULL;
  2105. temp_entry = entries[ 0 ];
  2106. *ret_entry = slapi_entry_dup(temp_entry);
  2107. } else {
  2108. /* No entry there */
  2109. rc = LDAP_NO_SUCH_OBJECT;
  2110. }
  2111. }
  2112. slapi_free_search_results_internal(int_search_pb);
  2113. slapi_pblock_destroy(int_search_pb);
  2114. int_search_pb = NULL;
  2115. if (filter_string)
  2116. {
  2117. PR_smprintf_free(filter_string);
  2118. }
  2119. return rc;
  2120. }
  2121. static int
  2122. windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry)
  2123. {
  2124. int retval = ENTRY_NOTFOUND;
  2125. Slapi_Entry *new_entry = NULL;
  2126. windows_search_local_entry_by_uniqueid( prp, uniqueid, NULL, &new_entry,
  2127. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION));
  2128. if (new_entry)
  2129. {
  2130. *local_entry = new_entry;
  2131. retval = 0;
  2132. }
  2133. return retval;
  2134. }
  2135. static int
  2136. windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_entry)
  2137. {
  2138. int retval = ENTRY_NOTFOUND;
  2139. Slapi_Entry *new_entry = NULL;
  2140. slapi_search_internal_get_entry( (Slapi_DN*)local_dn, NULL, &new_entry,
  2141. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION));
  2142. if (new_entry)
  2143. {
  2144. *local_entry = new_entry;
  2145. retval = 0;
  2146. }
  2147. return retval;
  2148. }
  2149. static int
  2150. windows_process_dirsync_entry(Private_Repl_Protocol *prp,Slapi_Entry *e, int is_total)
  2151. {
  2152. Slapi_DN* local_sdn = NULL;
  2153. int rc = 0;
  2154. /* deleted users are outside the 'correct container'.
  2155. They live in cn=deleted objects, windows_private_get_directory_subtree( prp->agmt) */
  2156. if (is_tombstone(e))
  2157. {
  2158. rc = map_tombstone_dn_inbound(e, &local_sdn, prp->agmt);
  2159. if ((0 == rc) && local_sdn)
  2160. {
  2161. /* Go ahead and delte the local peer */
  2162. rc = windows_delete_local_entry(local_sdn);
  2163. slapi_sdn_free(&local_sdn);
  2164. } else
  2165. {
  2166. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_process_dirsync_entry: failed to map tombstone dn.\n",agmt_get_long_name(prp->agmt));
  2167. }
  2168. } else
  2169. {
  2170. /* Is this entry one we should be interested in ? */
  2171. if (is_subject_of_agreemeent_remote(e,prp->agmt))
  2172. {
  2173. /* First make its local DN */
  2174. rc = map_entry_dn_inbound(e, &local_sdn, prp->agmt);
  2175. if ((0 == rc) && local_sdn)
  2176. {
  2177. Slapi_Entry *local_entry = NULL;
  2178. /* Get the local entry if it exists */
  2179. rc = windows_get_local_entry(local_sdn,&local_entry);
  2180. if ((0 == rc) && local_entry)
  2181. {
  2182. /* Since the entry exists we should now make it match the entry we received from AD */
  2183. rc = windows_update_local_entry(prp, e, local_entry);
  2184. slapi_entry_free(local_entry);
  2185. if (rc) {
  2186. /* Something bad happened */
  2187. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,"%s: windows_process_dirsync_entry: failed to update inbound entry.\n",agmt_get_long_name(prp->agmt));
  2188. }
  2189. } else
  2190. {
  2191. /* If it doesn't exist, try to make it */
  2192. windows_create_local_entry(prp,e,local_sdn);
  2193. }
  2194. slapi_sdn_free(&local_sdn);
  2195. } else
  2196. {
  2197. /* We should have been able to map the DN, so this is an error */
  2198. slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,"%s: windows_process_dirsync_entry: failed to map inbound entry.\n",agmt_get_long_name(prp->agmt));
  2199. }
  2200. } /* subject of agreement */
  2201. } /* is tombstone */
  2202. return rc;
  2203. }
  2204. void
  2205. windows_dirsync_inc_run(Private_Repl_Protocol *prp)
  2206. {
  2207. int rc = 0;
  2208. int msgid=0;
  2209. Slapi_PBlock *pb = NULL;
  2210. Slapi_Filter *filter_user = NULL;
  2211. Slapi_Filter *filter_user_deleted = NULL;
  2212. Slapi_Filter *filter_group = NULL;
  2213. Slapi_Filter *filter_group_deleted = NULL;
  2214. int done = 0;
  2215. LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_dirsync_inc_run\n", 0, 0, 0 );
  2216. while (!done) {
  2217. Slapi_Entry *e = NULL;
  2218. int filter_ret = 0;
  2219. PRBool create_users_from_dirsync = windows_private_create_users(prp->agmt);
  2220. rc = send_dirsync_search(prp->conn);
  2221. if (rc != CONN_OPERATION_SUCCESS)
  2222. {
  2223. slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
  2224. "failed to send dirsync search request: %d\n", rc);
  2225. goto error;
  2226. }
  2227. while ( (e = windows_conn_get_search_result(prp->conn) ) != NULL)
  2228. {
  2229. rc = windows_process_dirsync_entry(prp,e,0);
  2230. if (e)
  2231. {
  2232. slapi_entry_free(e);
  2233. }
  2234. } /* While entry != NULL */
  2235. if (!windows_private_dirsync_has_more(prp->agmt))
  2236. {
  2237. done = 1;
  2238. }
  2239. } /* While !done */
  2240. error:
  2241. LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_dirsync_inc_run\n", 0, 0, 0 );
  2242. }