mmldif.c 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #include <stdio.h>
  39. #include <ctype.h>
  40. #include <string.h>
  41. #include <time.h>
  42. #include <stdlib.h>
  43. #include <ldap.h>
  44. #ifndef _WIN32
  45. # define stricmp strcasecmp
  46. #else
  47. # include <io.h>
  48. #endif
  49. #include <pk11func.h>
  50. #include <slap.h>
  51. #include <getopt_ext.h>
  52. #include <ldaplog.h>
  53. #ifndef TRUE
  54. #define TRUE 1
  55. #endif
  56. #ifndef FALSE
  57. #define FALSE 0
  58. #endif
  59. #ifdef _WIN32
  60. int slapd_ldap_debug = 0;
  61. int *module_ldap_debug;
  62. #endif
  63. /*
  64. * VSTRING was defined in PMDF headers.
  65. */
  66. typedef struct vstring {
  67. int length;
  68. char body[252];
  69. } MM_VSTRING;
  70. /*
  71. * Base64 declarations.
  72. */
  73. typedef struct Enc64_s {
  74. struct Enc64_s * next;
  75. unsigned char * source;
  76. int slen;
  77. } Enc64_t;
  78. typedef struct Dec64_s {
  79. struct Dec64_s * next;
  80. unsigned char * dest;
  81. int maxlen;
  82. int curlen;
  83. int nextra;
  84. unsigned char extra[3];
  85. } Dec64_t;
  86. Enc64_t * initEnc64(unsigned char * source, int slen);
  87. int Enc64(Enc64_t * this, unsigned char *dest, int maxlen, int *len);
  88. void freeEnc64(Enc64_t *this);
  89. Dec64_t * initDec64(unsigned char * dest, int maxlen);
  90. int freeDec64(Dec64_t *this);
  91. int Dec64(Dec64_t * this, unsigned char *source);
  92. /*
  93. * License check declarations.
  94. */
  95. int license_limit = -1;
  96. int license_count;
  97. /*
  98. * Public declarations.(potentially).
  99. */
  100. #define IDDS_MM_OK 0
  101. #define IDDS_MM_EOF -1
  102. #define IDDS_MM_ABSENT -2
  103. #define IDDS_MM_FIO -3
  104. #define IDDS_MM_BAD -4
  105. /* attrib_t is used to hold each record in memory. The emphasis here is
  106. * on size, although compromising simplicity rather than speed. In reality
  107. * the way this is used is that there is a block of bytes defined. within
  108. * that block are a sequence of records each alligned on whatever is needed
  109. * to read shorts happilly. each record consists of a name, a value and
  110. * their lengths. The value length is first, because it has to be aligned
  111. * then the name value, because we need it first, then the name, null
  112. * terminated, then the value, null terminated. Thus if "thing" is a pointer
  113. * to one of these things,
  114. * thing->data is the name
  115. * (thing->data + namelen + 1) is the value,
  116. * (thing->data + ((namelen + 1 + valuelen + 1 + 3) & ~3) is the next one
  117. * (if we're aligned on 4 byte boundaries)
  118. */
  119. typedef int Boolean;
  120. typedef struct {
  121. int valuelen;
  122. char namelen;
  123. char data[1];
  124. } attrib_t;
  125. #define attribname(thing) (thing)->data
  126. #define attribvalue(thing) ((thing)->data + (thing)->namelen + 1)
  127. #define attribalign 4
  128. #define attribsize(thing) (((thing)->namelen + (thing)->valuelen + 1 \
  129. + attribalign) & ~(attribalign-1))
  130. #define attribnext(thing) (attrib_t *)(((char *)thing) \
  131. + (((thing)->namelen + (thing)->valuelen \
  132. + sizeof(int) + 2 + attribalign) & ~(attribalign-1)))
  133. /* record_t is used to hold a record once it had been squeezed
  134. * obviously it has to be allocated carefully so that it is the right size
  135. */
  136. typedef struct {
  137. short nattrs;
  138. attrib_t data;
  139. } record_t;
  140. /* attrib1_t is used to read in and sort a record */
  141. typedef struct attrib1_s {
  142. struct attrib1_s *next;
  143. char namelen;
  144. char name[64];
  145. int valuelen;
  146. char value[0x20000];
  147. } attrib1_t;
  148. typedef struct ignore_s {
  149. struct ignore_s *next;
  150. char name[65];
  151. } ignore_t;
  152. /* entry_t is the structure used to carry the fingerprint in the hash table */
  153. typedef struct entry_s {
  154. struct entry_s *overflow; /* we hash into buckets. This
  155. * is the chain of entries */
  156. char key[20]; /* this is the hash of the DN */
  157. int present[4]; /* actually treated as a 128 bit array*/
  158. /* this is the bitmap of which
  159. * directories contain this DN */
  160. int db; /* this is the directory number which
  161. * provided the data for this entry */
  162. record_t * first; /* this it the actual data */
  163. char fingerprint[20];/* this is the hash of the data */
  164. char flags; /* the status of this entry */
  165. #define EMPTY 0
  166. #define IDENTITY 1
  167. #define MODIFIED 2
  168. #define LOADED 0x10
  169. } entry_t;
  170. typedef struct {
  171. time_t start_time;
  172. int records;
  173. int records_away;
  174. time_t end_time;
  175. } cookstats_t;
  176. typedef struct {
  177. cookstats_t cook;
  178. time_t comb_start_time;
  179. int authoritative_records;
  180. time_t comb_end_time;
  181. time_t diff_start_time;
  182. int num_identities;
  183. int num_unchanged;
  184. int num_deletes;
  185. int num_adds;
  186. int num_modifies;
  187. time_t diff_end_time;
  188. cookstats_t uncook;
  189. } stats_t;
  190. extern int mm_init(int argc, char * argv[]);
  191. extern int mm_diff(stats_t *statsp);
  192. extern int mm_getvalue(
  193. record_t *first,
  194. attrib1_t *a,
  195. int directory,
  196. char *name,
  197. char **value,
  198. int *length
  199. );
  200. extern int mm_is_deleted(
  201. record_t *first,
  202. attrib1_t *a,
  203. int directory
  204. );
  205. extern int mm_get_winner(record_t *first, attrib1_t *a);
  206. extern void mm_init_winner(void);
  207. extern void mm_fin_winner(void);
  208. /*
  209. * Private declarations.
  210. */
  211. #define log_write_error() fprintf(stderr, "error writing record\n")
  212. /*
  213. * We need to maintain the order of entries read from input, so that
  214. * we can maintain hierarchical ordering. The entryblock structure
  215. * is used for that purpose. Memory for blocks of entries are allocated
  216. * and strung in a linked list.
  217. */
  218. struct entryblock {
  219. entry_t *eb_block;
  220. unsigned n;
  221. struct entryblock *next;
  222. };
  223. static struct entryblock *eb_head = NULL, *eb_cur = NULL;
  224. entry_t *entryalloc(void)
  225. {
  226. if (eb_head == NULL || eb_cur->n == 0x1000) {
  227. struct entryblock *newblock;
  228. newblock =
  229. (struct entryblock *)calloc(1, sizeof(struct entryblock));
  230. newblock->eb_block = (entry_t*)calloc(0x1000, sizeof(entry_t));
  231. if (eb_head == NULL) {
  232. eb_cur = eb_head = newblock;
  233. } else {
  234. eb_cur = eb_cur->next = newblock;
  235. }
  236. }
  237. return &eb_cur->eb_block[eb_cur->n++];
  238. }
  239. typedef struct {
  240. FILE * fp;
  241. int end;
  242. } edfFILE;
  243. static int ndirectories;
  244. static edfFILE edfin[128];
  245. static FILE * edfout[128];
  246. static FILE * ofp;
  247. static char line[2048];
  248. static char seed;
  249. static int hashmask;
  250. static entry_t **hashtable;
  251. static int maxcount;
  252. static int emitchanges;
  253. static int readrec(edfFILE * edf1, attrib1_t ** attrib);
  254. static void freefreelist(attrib1_t * freelist);
  255. static void hashname(char seed, attrib1_t * attrib, char * hashkey);
  256. static void hashvalue(char seed, attrib1_t * attrib, char * fingerprint);
  257. static record_t * newrecord(attrib1_t * big);
  258. static int adddelete(FILE * edf3, attrib1_t * attrib);
  259. static int addnew(FILE * edf3, const char *changetype, record_t * first);
  260. static int addmodified(FILE * edf3, attrib1_t * attrib, record_t * first);
  261. static int simpletext(unsigned char * body, int length);
  262. static int simpletextbody(unsigned char * body, int length);
  263. static int putvalue(
  264. FILE * fh,
  265. const char *tag,
  266. char * name,
  267. int namelen,
  268. char * value,
  269. int valuelen
  270. );
  271. static int signedmemcmp(
  272. unsigned char * a,
  273. int lena,
  274. unsigned char * b,
  275. int lenb
  276. );
  277. static void makeupper(MM_VSTRING * v, char * body, int len);
  278. static void commententry(FILE *fp, attrib1_t *attrib);
  279. int mm_diff(stats_t *statsp)
  280. {
  281. unsigned int h;
  282. entry_t * overflow;
  283. int i;
  284. int pindex;
  285. int pmask;
  286. attrib1_t * attrib = 0;
  287. entry_t * hashentry;
  288. entry_t * hashentry2;
  289. char fingerprint[16];
  290. int stat;
  291. int count;
  292. int records = 0;
  293. int added;
  294. struct entryblock *block, *next;
  295. union {
  296. unsigned int key;
  297. char data[16];
  298. } hashkey;
  299. unsigned int key;
  300. time(&statsp->diff_start_time);
  301. license_count = 0;
  302. /*
  303. * read all entries from all directories hashing name and value, and make
  304. * a bitmaps of who has each entry. Flag those entries where at least
  305. * one directory differs from any other.
  306. */
  307. for (i = 0; i < ndirectories; i++) {
  308. pindex = i / 32;
  309. pmask = 1 << (i % 32);
  310. LDAPDebug(LDAP_DEBUG_TRACE, "finger printing directory %d\n", i, 0, 0);
  311. while (TRUE) {
  312. stat = readrec(&edfin[i], &attrib);
  313. if (stat == IDDS_MM_ABSENT) {
  314. LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
  315. attrib->name, attrib->value, 0);
  316. continue;
  317. }
  318. if (stat == IDDS_MM_EOF)
  319. break;
  320. if (stat != IDDS_MM_OK) {
  321. free(hashtable);
  322. return stat;
  323. }
  324. records++;
  325. LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
  326. i, attrib->name, attrib->value);
  327. hashname(seed, attrib, hashkey.data);
  328. key = hashkey.key & hashmask;
  329. if (!hashtable[key]) {
  330. hashentry = hashtable[key] = entryalloc();
  331. } else {
  332. hashentry = hashtable[key];
  333. while (hashentry &&
  334. memcmp(hashkey.data, hashentry->key, 16))
  335. hashentry = hashentry->overflow;
  336. if (hashentry != NULL) {
  337. if (hashentry->present[pindex] & pmask) {
  338. LDAPDebug(LDAP_DEBUG_TRACE,
  339. "duplicate DN <%s=%s> (ignored)\n",
  340. attrib->name, attrib->value, 0);
  341. if (emitchanges) {
  342. fprintf(edfout[i], "\n# Duplicate DN:\n");
  343. commententry(edfout[i], attrib);
  344. }
  345. if (ofp != NULL) {
  346. fprintf(ofp, "\n# Duplicate DN (in database %d):\n",
  347. i);
  348. commententry(ofp, attrib);
  349. }
  350. } else {
  351. hashentry->present[pindex] |= pmask;
  352. hashvalue(seed, attrib, fingerprint);
  353. if (memcmp(fingerprint, hashentry->fingerprint, 16)) {
  354. LDAPDebug(LDAP_DEBUG_TRACE,
  355. "...data modified\n", key, 0, 0);
  356. hashentry->flags = MODIFIED;
  357. }
  358. }
  359. continue;
  360. }
  361. LDAPDebug(LDAP_DEBUG_TRACE, "overflow in key %u\n", key, 0, 0);
  362. hashentry2 = entryalloc();
  363. hashentry2->overflow = hashtable[key];
  364. hashentry = hashtable[key] = hashentry2;
  365. }
  366. hashentry->present[pindex] |= pmask;
  367. memcpy(hashentry->key, hashkey.data, 16);
  368. hashentry->flags = IDENTITY;
  369. statsp->num_identities++;
  370. hashvalue(seed, attrib, hashentry->fingerprint);
  371. }
  372. if ((license_limit > 0) && (records > license_limit)) {
  373. fprintf(stderr, "license exceeded\n");
  374. free(hashtable);
  375. return IDDS_MM_BAD;
  376. }
  377. if (records > license_count)
  378. license_count = records;
  379. records = 0;
  380. }
  381. /*
  382. * read all the directories again. This time we load the data into memory
  383. * We use a fairly tight (and ugly) structure to hold the data.
  384. * There are three possibilities to consider:
  385. * 1. no data has yet been loaded for this entry (load it)
  386. * 2. data is present, and the data is marked as an identity
  387. * (skip it)
  388. * 3. data is present, and the data differs in at least one
  389. * directory. call out to see who wins.
  390. */
  391. for (i = 0; i < ndirectories; i++) {
  392. rewind(edfin[i].fp);
  393. edfin[i].end = FALSE;
  394. pindex = i / 32;
  395. pmask = 1 << (i % 32);
  396. LDAPDebug(LDAP_DEBUG_TRACE,
  397. "loading authoritative data from directory %d\n", i, 0, 0);
  398. count = 0;
  399. while (TRUE) {
  400. stat = readrec(&edfin[i], &attrib);
  401. if (stat == IDDS_MM_ABSENT) {
  402. LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
  403. attrib->name, attrib->value, 0);
  404. continue;
  405. }
  406. if (stat == IDDS_MM_EOF)
  407. break;
  408. if (stat != IDDS_MM_OK) {
  409. free(hashtable);
  410. return stat;
  411. }
  412. LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
  413. i, attrib->name, attrib->value);
  414. hashname(seed, attrib, hashkey.data);
  415. key = hashkey.key & hashmask;
  416. hashentry = hashtable[key];
  417. while (hashentry &&
  418. memcmp(hashentry->key, hashkey.data, 16))
  419. hashentry = hashentry->overflow;
  420. if (hashentry == NULL) {
  421. LDAPDebug(LDAP_DEBUG_TRACE, "...hash entry not found\n", 0, 0, 0);
  422. continue;
  423. }
  424. if (!(hashentry->flags & LOADED))
  425. {
  426. count++;
  427. hashentry->first = newrecord(attrib);
  428. hashentry->flags |= LOADED;
  429. LDAPDebug(LDAP_DEBUG_TRACE, " ...data loaded\n", 0, 0, 0);
  430. hashentry->db = i;
  431. continue;
  432. }
  433. if (hashentry->flags & IDENTITY)
  434. continue;
  435. if (mm_get_winner(hashentry->first, attrib)) {
  436. hashentry->flags |= LOADED;
  437. LDAPDebug(LDAP_DEBUG_TRACE, " ...winner data loaded\n", 0, 0, 0);
  438. hashentry->db = i;
  439. free(hashentry->first);
  440. hashentry->first = newrecord(attrib);
  441. hashvalue(seed, attrib, hashentry->fingerprint);
  442. /* must take new fingerprint */
  443. continue;
  444. }
  445. }
  446. }
  447. if (!emitchanges) goto afterchanges;
  448. /*
  449. * Now we have the "authoritative" data in memory. Hey, that's what
  450. * VM is for. Now we are able to go through each directory (again)
  451. * and generate the differences. There are a number of possibilities
  452. * 1. the entry is marked as an identity. skip it
  453. * 2. the entry is marked as originating from this directory
  454. * skip it
  455. * 3. the entry's finger print is unchanged. skip it
  456. * 4. the entry has isDeleted set. emit a delete
  457. * 5. otherwise emit a change record.
  458. */
  459. for (i = 0; i < ndirectories; i++) {
  460. rewind(edfin[i].fp);
  461. edfin[i].end = FALSE;
  462. pindex = i / 32;
  463. pmask = 1 << (i % 32);
  464. LDAPDebug(LDAP_DEBUG_TRACE,
  465. "generating differences for directory %d\n", i, 0, 0);
  466. count = 0;
  467. while (TRUE) {
  468. stat = readrec(&edfin[i], &attrib);
  469. if (stat == IDDS_MM_ABSENT) {
  470. LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
  471. attrib->name, attrib->value, 0);
  472. continue;
  473. }
  474. if (stat == IDDS_MM_EOF)
  475. break;
  476. if (stat != IDDS_MM_OK) {
  477. free(hashtable);
  478. return stat;
  479. }
  480. LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
  481. i, attrib->name, attrib->value);
  482. hashname(seed, attrib, hashkey.data);
  483. key = hashkey.key & hashmask;
  484. hashentry = hashtable[key];
  485. while (hashentry &&
  486. memcmp(hashentry->key, hashkey.data, 16))
  487. hashentry = hashentry->overflow;
  488. if (hashentry == NULL) {
  489. LDAPDebug(LDAP_DEBUG_TRACE, "...hash entry not found\n", 0, 0, 0);
  490. continue;
  491. }
  492. if (hashentry->flags & IDENTITY)
  493. continue;
  494. if (hashentry->db == i)
  495. continue;
  496. hashvalue(seed, attrib, fingerprint);
  497. if (memcmp(fingerprint, hashentry->fingerprint, 16)) {
  498. if (mm_is_deleted(hashentry->first, attrib, 0)) {
  499. LDAPDebug(LDAP_DEBUG_TRACE, " ...deleted\n", 0, 0, 0);
  500. adddelete(edfout[i], attrib);
  501. } else {
  502. LDAPDebug(LDAP_DEBUG_TRACE, " ...modified\n", 0, 0, 0);
  503. addmodified(edfout[i], attrib, hashentry->first);
  504. }
  505. }
  506. }
  507. }
  508. afterchanges:
  509. /*
  510. * Nearly done. Now we need to go through each entry in the hash table
  511. * and for each directory check the "present" bit. If this is set
  512. * no action is needed here. Otherwise we emit an add.
  513. * we take this opportunity to free the memory.
  514. */
  515. LDAPDebug(LDAP_DEBUG_TRACE, "scanning db for new entries\n", 0, 0, 0);
  516. for (h = 0; h < 0x1000; h++) {
  517. for (hashentry = hashtable[h]; hashentry; hashentry = overflow) {
  518. if (!hashentry->flags)
  519. break;
  520. for (i = 0, added = 0; i < ndirectories; i++) {
  521. pindex = i / 32;
  522. pmask = 1 << (i % 32);
  523. if (hashentry->present[pindex] & pmask)
  524. continue;
  525. if (mm_is_deleted(hashentry->first, NULL, 0)) continue;
  526. added++;
  527. if (!emitchanges) continue;
  528. LDAPDebug(LDAP_DEBUG_TRACE, " ...add new\n", 0, 0, 0);
  529. addnew(edfout[i], "add", hashentry->first);
  530. }
  531. if (added) {
  532. statsp->num_adds++;
  533. } else if (hashentry->flags & MODIFIED) {
  534. statsp->num_modifies++;
  535. } else {
  536. statsp->num_unchanged++;
  537. }
  538. overflow = hashentry->overflow;
  539. }
  540. }
  541. /* output authoritative data and free data */
  542. for (block = eb_head; block != NULL; block = next) {
  543. entry_t *entry;
  544. for (h = 0; h < block->n; h++) {
  545. entry = &block->eb_block[h];
  546. if (ofp != NULL) {
  547. if (!mm_is_deleted(entry->first, NULL, 0)) {
  548. addnew(ofp, NULL, entry->first);
  549. }
  550. }
  551. free(entry->first);
  552. }
  553. next = block->next;
  554. free(block->eb_block);
  555. free(block);
  556. }
  557. free(hashtable);
  558. time(&statsp->diff_end_time);
  559. return IDDS_MM_OK;
  560. }
  561. static void usage(char *m)
  562. {
  563. fprintf(stderr,"usage: %s [-c] [-D] [-o out.ldif] in1.ldif in2.ldif ...\n\n", m);
  564. fprintf(stderr,"-c\tWrite a change file (.delta) for each input file\n");
  565. fprintf(stderr,"-D\tPrint debugging information\n");
  566. fprintf(stderr,"-o\tWrite authoritative data to this file\n");
  567. fprintf(stderr,"\n");
  568. exit(1);
  569. }
  570. int mm_init(int argc, char * argv[])
  571. {
  572. char deltaname[255];
  573. time_t tl;
  574. int c;
  575. char *ofn = NULL;
  576. char *prog = argv[0];
  577. char *tailorfile = NULL;
  578. time(&tl);
  579. seed = (char)tl;
  580. maxcount = 10;
  581. ndirectories = 0;
  582. emitchanges = 0;
  583. ofp = NULL;
  584. mm_init_winner();
  585. slapd_ldap_debug = 0;
  586. while ((c = getopt(argc, argv, "cDho:")) != EOF) {
  587. switch (c) {
  588. case 'c':
  589. emitchanges = 1;
  590. break;
  591. case 'D':
  592. slapd_ldap_debug = 65535;
  593. break;
  594. case 'o':
  595. ofn = strdup(optarg);
  596. break;
  597. case 'h':
  598. default:
  599. usage(prog);
  600. break;
  601. }
  602. }
  603. #ifdef _WIN32
  604. module_ldap_debug = &slapd_ldap_debug;
  605. libldap_init_debug_level(&slapd_ldap_debug);
  606. #endif
  607. if (ofn != NULL) {
  608. ofp = fopen(ofn, "w");
  609. if (ofp == NULL) {
  610. perror(ofn);
  611. return -1;
  612. }
  613. free(ofn);
  614. ofn = NULL;
  615. }
  616. for (argv += optind; optind < argc; optind++, argv++) {
  617. edfin[ndirectories].fp = fopen(*argv, "r");
  618. if (edfin[ndirectories].fp == NULL) {
  619. perror(*argv);
  620. return -1;
  621. }
  622. edfin[ndirectories].end = FALSE;
  623. if (emitchanges) {
  624. PL_strncpyz(deltaname, *argv, sizeof(deltaname));
  625. PL_strcatn(deltaname, sizeof(deltaname), ".delta");
  626. edfout[ndirectories] = fopen(deltaname, "w");
  627. if (edfout[ndirectories] == NULL) {
  628. perror(deltaname);
  629. return -1;
  630. }
  631. }
  632. ndirectories++;
  633. }
  634. if (ndirectories == 0) {
  635. fprintf(stderr, "\nno input files\n\n");
  636. usage(prog);
  637. return 0;
  638. }
  639. hashmask = 0xfff;
  640. hashtable = (entry_t **)calloc(0x1000, sizeof(entry_t*));
  641. if (tailorfile) free(tailorfile);
  642. return 0;
  643. }
  644. /* this clears the attrib structure if there is one, and reads in the data
  645. * sorting lines 2 to n by name, and eliminating comments
  646. */
  647. static int
  648. readrec(edfFILE * edf1, attrib1_t ** attrib)
  649. {
  650. Dec64_t * b64;
  651. char * vptr;
  652. char * lptr;
  653. char * ptr;
  654. int len;
  655. int lookahead = 0;
  656. int toolong = FALSE;
  657. int rc;
  658. int cmp;
  659. attrib1_t * att;
  660. attrib1_t ** prev;
  661. attrib1_t * freelist = *attrib;
  662. attrib1_t * newlist = NULL;
  663. attrib1_t * a;
  664. int ignore_rec = FALSE;
  665. *attrib = NULL;
  666. if (edf1->end) {
  667. freefreelist(freelist);
  668. return IDDS_MM_EOF;
  669. }
  670. while (TRUE) {
  671. if (lookahead) {
  672. if (lookahead == '\n') {
  673. break; /* return */
  674. }
  675. line[0] = lookahead;
  676. lptr = line+1;
  677. lookahead = 0;
  678. }
  679. else
  680. lptr = line;
  681. if (!fgets(lptr, sizeof(line)-1, edf1->fp)) {
  682. edf1->end = TRUE;
  683. if (!newlist) {
  684. /* that's for the case where the file */
  685. /* has a trailing blank line */
  686. freefreelist(freelist);
  687. return IDDS_MM_EOF;
  688. }
  689. break; /* return */
  690. }
  691. if (line[0] == '\n') {
  692. /* ignore empty lines at head of LDIF file */
  693. if (newlist == NULL) {
  694. continue;
  695. }
  696. break; /* an empty line terminates a record */
  697. }
  698. if (line[0] == '#')
  699. continue; /* skip comment lines */
  700. len = strlen(line);
  701. for (lptr = line+len-1; len; len--, lptr--) {
  702. if ((*lptr != '\n') && (*lptr != '\r'))
  703. break;
  704. *lptr = 0;
  705. }
  706. vptr = strchr(line, ':');
  707. if (!vptr) {
  708. LDAPDebug(LDAP_DEBUG_TRACE, "%s\n invalid input line\n",
  709. line, 0, 0);
  710. continue; /* invalid line, but we'll just skip it */
  711. }
  712. *vptr = 0;
  713. if (!stricmp(line, "authoritative"))
  714. continue;
  715. if (!freelist) {
  716. att = (attrib1_t *)malloc(sizeof(attrib1_t));
  717. } else {
  718. att = freelist;
  719. freelist = freelist->next;
  720. }
  721. att->namelen = vptr-line;
  722. if (att->namelen > 63) {
  723. att->namelen = 63;
  724. *(line+64) = 0;
  725. }
  726. memcpy(att->name, line, att->namelen+1);
  727. vptr++;
  728. if (*vptr == ':') {
  729. vptr++;
  730. while (*vptr == ' ') vptr++; /* skip optional spaces */
  731. b64 = initDec64((unsigned char *)att->value, 0x20000);
  732. if (Dec64(b64, (unsigned char *) vptr)) {
  733. LDAPDebug(LDAP_DEBUG_TRACE, "%s\n invalid input line\n",
  734. line, 0, 0);
  735. continue; /* invalid line, but we'll just skip it */
  736. }
  737. toolong = FALSE;
  738. while (TRUE) {
  739. lookahead = fgetc(edf1->fp);
  740. if (lookahead != ' ')
  741. break;
  742. fgets(line, sizeof(line), edf1->fp);
  743. len = strlen(line);
  744. for (lptr = line+len-1; len; len--, lptr--) {
  745. if ((*lptr != '\n') && (*lptr != '\r'))
  746. break;
  747. *lptr = 0;
  748. }
  749. rc = Dec64(b64, (unsigned char *)line);
  750. if (rc == -1)
  751. {
  752. LDAPDebug(LDAP_DEBUG_TRACE,
  753. "%s\n invalid input line\n", line, 0, 0);
  754. continue; /* invalid line, but we'll just skip it */
  755. }
  756. if (rc) {
  757. if (!toolong) {
  758. toolong = TRUE;
  759. LDAPDebug(LDAP_DEBUG_TRACE,
  760. "%s\n line too long\n", line, 0, 0);
  761. }
  762. continue;
  763. }
  764. }
  765. att->valuelen = freeDec64(b64);
  766. } else {
  767. if (!*vptr) {
  768. att->valuelen = 0;
  769. }
  770. while (*vptr == ' ') vptr++; /* skip optional spaces */
  771. att->valuelen = strlen(vptr);
  772. memcpy(att->value, vptr, att->valuelen);
  773. ptr = att->value + att->valuelen;
  774. while (TRUE) {
  775. lookahead = fgetc(edf1->fp);
  776. if (lookahead != ' ')
  777. break;
  778. fgets(line, sizeof(line), edf1->fp);
  779. len = strlen(line);
  780. for (lptr = line+len-1; len; len--, lptr--) {
  781. if ((*lptr != '\n') && (*lptr != '\r'))
  782. break;
  783. *lptr = 0;
  784. }
  785. memcpy(ptr, line, len);
  786. att->valuelen += len;
  787. ptr += len;
  788. }
  789. *ptr = 0;
  790. }
  791. if (newlist) {
  792. if (newlist->next) {
  793. for (a = newlist->next, prev = &(newlist->next);
  794. a; prev=&(a->next), a = a->next) {
  795. cmp = stricmp(a->name, att->name);
  796. if (cmp > 0) {
  797. att->next = *prev;
  798. *prev = att;
  799. goto f1;
  800. }
  801. if (cmp == 0) {
  802. cmp = signedmemcmp((unsigned char *)a->value,
  803. a->valuelen,
  804. (unsigned char *)att->value,
  805. att->valuelen);
  806. if (cmp > 0) {
  807. att->next = *prev;
  808. *prev = att;
  809. goto f1;
  810. }
  811. }
  812. }
  813. *prev = att;
  814. att->next = NULL;
  815. f1: ;
  816. } else {
  817. newlist->next = att;
  818. att->next = NULL;
  819. }
  820. } else {
  821. newlist = att;
  822. att->next = NULL;
  823. }
  824. }
  825. *attrib = newlist;
  826. freefreelist(freelist);
  827. if (ignore_rec)
  828. return IDDS_MM_ABSENT;
  829. return IDDS_MM_OK;
  830. }
  831. static void
  832. freefreelist(attrib1_t * freelist)
  833. {
  834. attrib1_t * next;
  835. for (;freelist; freelist = next) {
  836. next = freelist->next;
  837. free(freelist);
  838. }
  839. }
  840. static void
  841. hashname(char seed, attrib1_t * attrib, char * hashkey)
  842. {
  843. MM_VSTRING upper;
  844. PK11Context *context;
  845. unsigned int hashLen;
  846. /* we want the name to be case insensitive, and if the name DN, we want
  847. * the value to be case insensitive. */
  848. /* this creates a hash key based on the first line in attrib */
  849. makeupper(&upper, attrib->name, attrib->namelen);
  850. context = PK11_CreateDigestContext(SEC_OID_MD5);
  851. if (context != NULL) {
  852. PK11_DigestBegin(context);
  853. PK11_DigestOp(context, (unsigned char *)&seed, 1);
  854. PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
  855. PK11_DigestOp(context, (unsigned char *)"=", 1);
  856. if (!memcmp(upper.body, "DN", 2)) {
  857. makeupper(&upper, attrib->value, attrib->valuelen);
  858. PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
  859. } else
  860. PK11_DigestOp(context, (unsigned char *)attrib->value, attrib->valuelen);
  861. PK11_DigestFinal(context, (unsigned char *)hashkey, &hashLen, 16);
  862. PK11_DestroyContext(context, PR_TRUE);
  863. }
  864. else { /* Probably desesperate but at least deterministic... */
  865. memset(hashkey, 0, 16);
  866. }
  867. }
  868. /* this creates a hash key base on all but the first line in attrib */
  869. static void
  870. hashvalue(char seed, attrib1_t * attrib, char * fingerprint)
  871. {
  872. MM_VSTRING upper;
  873. attrib1_t * a;
  874. PK11Context *context;
  875. unsigned int fgLen;
  876. context = PK11_CreateDigestContext(SEC_OID_MD5);
  877. if (context != NULL) {
  878. PK11_DigestBegin(context);
  879. PK11_DigestOp(context, (unsigned char *)&seed, 1);
  880. for (a = attrib->next; a; a = a->next) {
  881. if (!stricmp(a->name, "authoritative"))
  882. continue;
  883. /* we want the name to be case insensitive, and if the name DN, we want
  884. * the value to be case insensitive. */
  885. makeupper(&upper, a->name, a->namelen);
  886. PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
  887. PK11_DigestOp(context, (unsigned char *)"=", 1);
  888. if (!memcmp(upper.body, "DN", 2)) {
  889. makeupper(&upper, a->value, a->valuelen);
  890. PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
  891. } else
  892. PK11_DigestOp(context, (unsigned char *)a->value, a->valuelen);
  893. PK11_DigestOp(context, (unsigned char *)";", 1);
  894. }
  895. PK11_DigestFinal(context, (unsigned char *)fingerprint, &fgLen, 16);
  896. PK11_DestroyContext(context, PR_TRUE);
  897. }
  898. else { /* Probably desesperate but at least deterministic... */
  899. memset(fingerprint, 0, 16);
  900. }
  901. }
  902. /* this writes a record deletion record based on the first line in attrib */
  903. static int
  904. adddelete(FILE * edf3, attrib1_t * attrib)
  905. {
  906. if (!putvalue(edf3, NULL, attrib->name, attrib->namelen,
  907. attrib->value, attrib->valuelen)) {
  908. log_write_error();
  909. return IDDS_MM_FIO;
  910. }
  911. fprintf(edf3, "changetype: delete\n\n");
  912. return IDDS_MM_OK;
  913. }
  914. /* this writes a record addition record based on attrib */
  915. static int
  916. addnew(FILE * edf3, const char *changetype, record_t * first)
  917. {
  918. attrib_t * att;
  919. int attnum;
  920. for (attnum = 1, att = &first->data;
  921. attnum <= first->nattrs;
  922. attnum++, att = attribnext(att)) {
  923. if (!stricmp(attribname(att), "modifytimestamp"))
  924. continue;
  925. if (!stricmp(attribname(att), "modifiersname"))
  926. continue;
  927. if (!putvalue(edf3, NULL, attribname(att), att->namelen,
  928. attribvalue(att), att->valuelen)) {
  929. log_write_error();
  930. return IDDS_MM_FIO;
  931. }
  932. if (attnum == 1 && changetype != NULL) {
  933. fprintf(edf3, "changetype: %s\n", changetype);
  934. }
  935. }
  936. if (fputs("\n", edf3) < 0) {
  937. log_write_error();
  938. return IDDS_MM_FIO;
  939. }
  940. return IDDS_MM_OK;
  941. }
  942. /* this writes a record modification record based on the information in
  943. * first and attrib
  944. */
  945. static int
  946. addmodified(FILE * edf3, attrib1_t * attrib, record_t * first)
  947. {
  948. attrib_t *b;
  949. attrib1_t *a;
  950. int num_b;
  951. int tot_b;
  952. int cmp;
  953. char *attrname;
  954. if (!putvalue(edf3, NULL, attrib->name, attrib->namelen,
  955. attrib->value, attrib->valuelen)) {
  956. log_write_error();
  957. return IDDS_MM_FIO;
  958. }
  959. if (fputs("changetype: modify\n", edf3) < 0) {
  960. log_write_error();
  961. return IDDS_MM_FIO;
  962. }
  963. tot_b = first->nattrs;
  964. num_b = 1;
  965. b = &first->data;
  966. /* advance past dn attrs */
  967. a = attrib->next;
  968. b = attribnext(b); num_b++;
  969. /*
  970. * Lock-step through the two attr lists while there are still
  971. * attrs remaining in either.
  972. */
  973. while (a != NULL || num_b <= tot_b) {
  974. /* ignore operational attrs */
  975. if (num_b <= tot_b &&
  976. (stricmp(attribname(b), "modifytimestamp") == 0 ||
  977. stricmp(attribname(b), "modifiersname") == 0)) {
  978. b = attribnext(b); num_b++;
  979. continue;
  980. }
  981. if (a != NULL &&
  982. (stricmp(a->name, "modifytimestamp") == 0 ||
  983. stricmp(a->name, "modifiersname") == 0)) {
  984. a = a->next;
  985. continue;
  986. }
  987. if (num_b > tot_b) {
  988. cmp = -1;
  989. } else if (a == NULL) {
  990. cmp = 1;
  991. } else {
  992. cmp = stricmp(a->name, attribname(b));
  993. }
  994. if (cmp < 0) {
  995. /* a < b: a is deleted */
  996. attrname = a->name;
  997. fprintf(edf3, "delete: %s\n-\n", attrname);
  998. do {
  999. a = a->next;
  1000. } while (a != NULL && stricmp(a->name, attrname) == 0);
  1001. continue;
  1002. } else if (cmp > 0) {
  1003. /* a > b: b is added */
  1004. attrname = attribname(b);
  1005. fprintf(edf3, "add: %s\n", attrname);
  1006. do {
  1007. if (!putvalue(edf3, NULL, attribname(b), b->namelen,
  1008. attribvalue(b), b->valuelen)) {
  1009. log_write_error();
  1010. return IDDS_MM_FIO;
  1011. }
  1012. b = attribnext(b); num_b++;
  1013. } while (num_b <= tot_b && stricmp(attribname(b), attrname) == 0);
  1014. fprintf(edf3, "-\n");
  1015. continue;
  1016. } else {
  1017. /* a == b */
  1018. int nmods = 0;
  1019. attrib_t *begin_b = b;
  1020. attrib1_t *v_del = NULL;
  1021. attrib_t *v_add = NULL;
  1022. int begin_num_b = num_b;
  1023. /*
  1024. * Lock-step through the ordered values.
  1025. * Remember a maximum of one changed value.
  1026. * If we encounter more than one change then
  1027. * just issue a replace of the whole value.
  1028. */
  1029. attrname = a->name;
  1030. do {
  1031. if (num_b > tot_b || stricmp(attribname(b), attrname) != 0) {
  1032. cmp = -1;
  1033. } else if (a == NULL || stricmp(a->name, attrname) != 0) {
  1034. cmp = 1;
  1035. } else {
  1036. cmp = signedmemcmp((unsigned char *)a->value,
  1037. a->valuelen,
  1038. (unsigned char *)attribvalue(b),
  1039. b->valuelen);
  1040. }
  1041. if (cmp < 0) {
  1042. nmods++;
  1043. v_del = a;
  1044. a = a->next;
  1045. } else if (cmp > 0) {
  1046. nmods++;
  1047. v_add = b;
  1048. b = attribnext(b); num_b++;
  1049. } else {
  1050. a = a->next;
  1051. b = attribnext(b); num_b++;
  1052. }
  1053. } while ((a != NULL &&
  1054. stricmp(a->name, attrname) == 0) ||
  1055. (num_b <= tot_b &&
  1056. stricmp(attribname(b), attrname) == 0));
  1057. if (nmods == 1) {
  1058. if (v_add != NULL) {
  1059. if (!putvalue(edf3, "add",
  1060. attribname(v_add), v_add->namelen,
  1061. attribvalue(v_add), v_add->valuelen)) {
  1062. log_write_error();
  1063. return IDDS_MM_FIO;
  1064. }
  1065. } else {
  1066. if (!putvalue(edf3, "delete",
  1067. v_del->name, v_del->namelen,
  1068. v_del->value, v_del->valuelen)) {
  1069. log_write_error();
  1070. return IDDS_MM_FIO;
  1071. }
  1072. }
  1073. } else if (nmods > 1) {
  1074. fprintf(edf3, "replace: %s\n", attrname);
  1075. do {
  1076. if (!putvalue(edf3, NULL,
  1077. attribname(begin_b), begin_b->namelen,
  1078. attribvalue(begin_b), begin_b->valuelen)) {
  1079. log_write_error();
  1080. return IDDS_MM_FIO;
  1081. }
  1082. begin_b = attribnext(begin_b); begin_num_b++;
  1083. } while (begin_num_b <= tot_b && begin_b != b);
  1084. fprintf(edf3, "-\n");
  1085. }
  1086. }
  1087. }
  1088. if (fputs("\n", edf3) < 0) {
  1089. log_write_error();
  1090. return IDDS_MM_FIO;
  1091. }
  1092. return IDDS_MM_OK;
  1093. }
  1094. static record_t * newrecord(attrib1_t * big)
  1095. {
  1096. record_t * smll;
  1097. attrib_t * b;
  1098. attrib1_t * a;
  1099. int len = 0;
  1100. int count = 0;
  1101. for (a=big; a; a = a->next) {
  1102. count++;
  1103. len += (a->namelen + a->valuelen + sizeof(attrib_t) + attribalign) &
  1104. ~ (attribalign-1);
  1105. }
  1106. len += sizeof(short);
  1107. smll = (record_t *)malloc(len);
  1108. for (a=big, b=&smll->data; a; a = a->next, b = attribnext(b)) {
  1109. b->valuelen = a->valuelen;
  1110. b->namelen = a->namelen;
  1111. memcpy(attribname(b), a->name, a->namelen+1);
  1112. memcpy(attribvalue(b), a->value, a->valuelen+1);
  1113. }
  1114. smll->nattrs = count;
  1115. return smll;
  1116. }
  1117. static int
  1118. simpletextbody(unsigned char * body, int length)
  1119. {
  1120. int i;
  1121. for (i = length; --i >= 0; body++) {
  1122. if ((*body < ' ') || (*body >= 0x7f))
  1123. return FALSE;
  1124. }
  1125. return TRUE;
  1126. }
  1127. static int
  1128. simpletext(unsigned char * body, int length)
  1129. {
  1130. if ((*body == ':') || (*body == '<') || (*body == ' '))
  1131. return FALSE;
  1132. return simpletextbody(body, length);
  1133. }
  1134. /* output a string value */
  1135. static int
  1136. putvalue(
  1137. FILE * fh,
  1138. const char * tag,
  1139. char * name,
  1140. int namelen,
  1141. char * value,
  1142. int valuelen
  1143. )
  1144. {
  1145. Enc64_t * b64;
  1146. char * lptr;
  1147. char line[255];
  1148. int return_code;
  1149. int len;
  1150. char * sptr;
  1151. int rc;
  1152. lptr = line;
  1153. if (tag != NULL) {
  1154. sprintf(lptr, "%s: ", tag);
  1155. lptr += strlen(lptr);
  1156. memcpy(lptr, name, namelen);
  1157. lptr += namelen;
  1158. *lptr++ = '\n';
  1159. }
  1160. memcpy(lptr, name, namelen);
  1161. lptr += namelen;
  1162. *lptr++ = ':';
  1163. if (!valuelen) {
  1164. *lptr = '\n';
  1165. *(lptr+1) = 0;
  1166. return_code = fputs(line, fh);
  1167. goto return_bit;
  1168. }
  1169. if (simpletext((unsigned char *)value, valuelen)) {
  1170. *lptr = ' ';
  1171. if (valuelen + (lptr+1 - line) < 80) {
  1172. strcpy(lptr+1, value);
  1173. strcpy(lptr+1 + valuelen, "\n");
  1174. return_code = fputs(line, fh);
  1175. goto return_bit;
  1176. }
  1177. len = 80 - (lptr+1 - line);
  1178. memcpy(lptr+1, value, len);
  1179. line[80] = '\n';
  1180. line[81] = 0;
  1181. return_code = fputs(line, fh);
  1182. if (return_code < 0)
  1183. goto return_bit;
  1184. sptr = value + len;
  1185. len = valuelen - len;
  1186. line[0] = ' ';
  1187. while (len > 79) {
  1188. memcpy(line+1, sptr, 79);
  1189. return_code = fputs(line, fh);
  1190. if (return_code < 0)
  1191. goto return_bit;
  1192. sptr += 79;
  1193. len -= 79;
  1194. }
  1195. if (len) {
  1196. memcpy(line+1, sptr, len);
  1197. line[len+1] = '\n';
  1198. line[len+2] = 0;
  1199. return_code = fputs(line, fh);
  1200. }
  1201. goto return_bit;
  1202. }
  1203. b64 = initEnc64((unsigned char *)value, valuelen);
  1204. *lptr = ':';
  1205. *(lptr+1) = ' ';
  1206. rc = Enc64(b64, (unsigned char *)(lptr+2), 80-(lptr-line), &len);
  1207. *(lptr +len+2) = '\n';
  1208. *(lptr + len +3) = 0;
  1209. return_code = fputs(line, fh);
  1210. if (return_code < 0)
  1211. goto return_bit;
  1212. while (TRUE) {
  1213. line[0] = ' ';
  1214. rc = Enc64(b64, (unsigned char *)line+1, 79, &len);
  1215. if (rc)
  1216. break;
  1217. line[len+1] = '\n';
  1218. line[len+2] = 0;
  1219. return_code = fputs(line, fh);
  1220. if (return_code < 0)
  1221. goto return_bit;
  1222. }
  1223. return_bit:
  1224. if (tag != NULL) {
  1225. fputs("-\n", fh);
  1226. }
  1227. if (return_code < 0)
  1228. return FALSE;
  1229. return TRUE;
  1230. }
  1231. static int
  1232. signedmemcmp(unsigned char * a, int lena, unsigned char * b, int lenb)
  1233. {
  1234. int c;
  1235. for (;; a++, b++) {
  1236. if (!lenb)
  1237. return lena;
  1238. if (!lena)
  1239. return -1;
  1240. if ((c=(int)*a - (int)*b))
  1241. return c;
  1242. lena--;
  1243. lenb--;
  1244. }
  1245. }
  1246. static void
  1247. makeupper(MM_VSTRING * v, char * body, int len)
  1248. {
  1249. char * vp;
  1250. v->length = len;
  1251. for (vp = v->body; len > 0; len--, vp++, body++)
  1252. *vp = toupper(*body);
  1253. }
  1254. int
  1255. mm_getvalue(
  1256. record_t *first,
  1257. attrib1_t *a,
  1258. int directory,
  1259. char *name,
  1260. char **value,
  1261. int *length
  1262. )
  1263. {
  1264. int attnum;
  1265. attrib_t * att;
  1266. if (directory) {
  1267. for ( ; a; a = a->next) {
  1268. if (!stricmp(a->name, name)) {
  1269. if (!*value) {
  1270. *value = a->value;
  1271. *length = a->valuelen;
  1272. return TRUE;
  1273. } else {
  1274. if (*value == a->value)
  1275. *value = NULL;
  1276. }
  1277. }
  1278. }
  1279. return FALSE;
  1280. }
  1281. att = &first->data;
  1282. for (attnum = 1, att = &first->data;
  1283. attnum <= first->nattrs;
  1284. attnum++, att = attribnext(att)) {
  1285. if (!stricmp(attribname(att), name)) {
  1286. if (!*value) {
  1287. *value = attribvalue(att);
  1288. *length = att->valuelen;
  1289. return TRUE;
  1290. } else {
  1291. if (*value == attribvalue(att))
  1292. *value = NULL;
  1293. }
  1294. }
  1295. }
  1296. return FALSE;
  1297. }
  1298. int mm_is_deleted(
  1299. record_t *first,
  1300. attrib1_t *attrib,
  1301. int directory
  1302. )
  1303. {
  1304. char * value = NULL;
  1305. int len;
  1306. while (mm_getvalue(first, attrib, directory,
  1307. "objectclass",
  1308. &value, &len)) {
  1309. if (stricmp(value, "nsTombstone") == 0) {
  1310. return 1;
  1311. }
  1312. }
  1313. if (mm_getvalue(first, attrib, directory, "isdeleted", &value, &len)) {
  1314. if ((len == 1 && *value == '1') ||
  1315. (len == 4 && stricmp(value, "true") == 0)) {
  1316. return 1;
  1317. }
  1318. }
  1319. if (mm_getvalue(first, attrib, directory, "zombi", &value, &len)) {
  1320. return 1;
  1321. }
  1322. return 0;
  1323. }
  1324. static void commententry(FILE *fp, attrib1_t *attrib)
  1325. {
  1326. attrib1_t *a;
  1327. if (attrib == NULL) return;
  1328. fprintf(fp, "# %s: %s\n", attrib->name, attrib->value);
  1329. for (a = attrib->next; a; a = a->next) {
  1330. if (simpletext((unsigned char *)a->value,
  1331. a->valuelen)) {
  1332. fprintf(fp, "# %*.*s: %*.*s\n",
  1333. a->namelen, a->namelen,
  1334. a->name,
  1335. a->valuelen, a->valuelen,
  1336. a->value);
  1337. }
  1338. }
  1339. fprintf(fp, "\n");
  1340. }
  1341. int main(int argc, char *argv[])
  1342. {
  1343. stats_t stats;
  1344. int rc;
  1345. float difftime;
  1346. memset(&stats, 0, sizeof(stats));
  1347. if ((rc = mm_init(argc, argv)))
  1348. return rc;
  1349. if ((mm_diff(&stats) == IDDS_MM_OK)
  1350. && (license_limit > 0)) {
  1351. if (license_count > license_limit * 98.0 / 100)
  1352. fprintf(stderr, "That was over 98%% of your license limit.\n");
  1353. else if (license_count > license_limit * 95.0 / 100)
  1354. fprintf(stderr, "That was over 95%% of your license limit.\n");
  1355. else if (license_count > license_limit * 90.0 / 100)
  1356. fprintf(stderr, "That was over 90%% of your license limit.\n");
  1357. }
  1358. mm_fin_winner();
  1359. printf("start time %s", ctime(&stats.diff_start_time));
  1360. printf("\nentry counts: unchanged=%d changed=%d new=%d total=%d\n\n",
  1361. stats.num_unchanged,
  1362. stats.num_modifies,
  1363. stats.num_adds,
  1364. stats.num_identities);
  1365. printf("end time %s", ctime(&stats.diff_end_time));
  1366. difftime = stats.diff_end_time - stats.diff_start_time;
  1367. if (difftime <= 1)
  1368. printf("differencing took <= 1 second\n");
  1369. else
  1370. printf("differencing took %u seconds, %u records per second\n",
  1371. (unsigned int)difftime,
  1372. (unsigned int)(stats.num_identities / difftime));
  1373. exit(0);
  1374. }
  1375. /*
  1376. * Conflict resolution.
  1377. */
  1378. void mm_init_winner()
  1379. {
  1380. }
  1381. void mm_fin_winner()
  1382. {
  1383. }
  1384. int mm_get_winner(record_t * first, attrib1_t * a)
  1385. {
  1386. int len;
  1387. char * modified0 = NULL;
  1388. char * modified1 = NULL;
  1389. mm_getvalue(first, a, 0, "modifytimestamp", &modified0, &len);
  1390. mm_getvalue(first, a, 1, "modifytimestamp", &modified1, &len);
  1391. if (!modified0) {
  1392. mm_getvalue(first, a, 0, "createtimestamp", &modified0, &len);
  1393. }
  1394. if (!modified1) {
  1395. mm_getvalue(first, a, 1, "createtimestamp", &modified1, &len);
  1396. }
  1397. if (!modified0) {
  1398. mm_getvalue(first, a, 0, "deletetimestamp", &modified0, &len);
  1399. }
  1400. if (!modified1) {
  1401. mm_getvalue(first, a, 1, "deletetimestamp", &modified1, &len);
  1402. }
  1403. if (!modified0)
  1404. return 1;
  1405. if (!modified1)
  1406. return 0;
  1407. return strcmp(modified0, modified1) <= 0;
  1408. }
  1409. /*
  1410. * Base64 Implementation.
  1411. */
  1412. /* 0123456789ABCDEF */
  1413. static unsigned char b64[] = "ABCDEFGHIJKLMNOP"
  1414. "QRSTUVWXYZabcdef"
  1415. "ghijklmnopqrstuv"
  1416. "wxyz0123456789+/";
  1417. static unsigned char ub64[] = {
  1418. /* 0 1 2 3 4 5 6 7
  1419. * 8 9 A B C C E F
  1420. */
  1421. /*0-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1422. /*0-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1423. /*1-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1424. /*1-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1425. /*2-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1426. /*2-*/ 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63,
  1427. /*3-*/ 52, 53, 54, 55, 56, 57, 58, 59,
  1428. /*3-*/ 60, 61, 0xFF, 0xFF, 0xFF, 64, 0xFF, 0xFF,
  1429. /*4-*/ 0xFF, 0, 1, 2, 3, 4, 5, 6,
  1430. /*4-*/ 7, 8, 9, 10, 11, 12, 13, 14,
  1431. /*5-*/ 15, 16, 17, 18, 19, 20, 21, 22,
  1432. /*5-*/ 23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1433. /*6-*/ 0xFF, 26, 27, 28, 29, 30, 31, 32,
  1434. /*6-*/ 33, 34, 35, 36, 37, 38, 39, 40,
  1435. /*7-*/ 41, 42, 43, 44, 45, 46, 47, 48,
  1436. /*7-*/ 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1437. /*8-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1438. /*8-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1439. /*9-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1440. /*9-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1441. /*A-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1442. /*A-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1443. /*B-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1444. /*B-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1445. /*C-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1446. /*C-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1447. /*D-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1448. /*D-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1449. /*E-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1450. /*E-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1451. /*F-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1452. /*F-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  1453. static Enc64_t * freeEnc64List = NULL;
  1454. static Dec64_t * freeDec64List = NULL;
  1455. Enc64_t *
  1456. initEnc64(unsigned char * source, int slen)
  1457. {
  1458. Enc64_t * this = freeEnc64List;
  1459. if (this)
  1460. freeEnc64List = freeEnc64List->next;
  1461. else
  1462. this = (Enc64_t *)malloc(sizeof(Enc64_t));
  1463. this->source = source;
  1464. this->slen = slen;
  1465. return this;
  1466. }
  1467. int
  1468. Enc64(Enc64_t * this, unsigned char *dest, int maxlen, int *len)
  1469. {
  1470. /* returns 0 normally
  1471. * +1 on end of string
  1472. * -1 on badi
  1473. */
  1474. int l;
  1475. unsigned char * s;
  1476. unsigned char * d;
  1477. int reml;
  1478. int i;
  1479. if (!this->slen)
  1480. return 1;
  1481. l = this->slen / 3;
  1482. s = this->source;
  1483. if (l > maxlen / 4)
  1484. {
  1485. l = maxlen / 4;
  1486. this->slen -= l*3;
  1487. reml = 0;
  1488. this->source += l*3;
  1489. }
  1490. else
  1491. {
  1492. reml = this->slen % 3;
  1493. this->slen = 0;
  1494. }
  1495. for (d = dest, i = 0; i < l; i++)
  1496. {
  1497. *d++ = b64[(*s >> 2) & 0x3f];
  1498. *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
  1499. s++;
  1500. *d++ = b64[((*s << 2) & 0x3c) + ((*(s+1) >> 6) & 0x03)];
  1501. s++;
  1502. *d++ = b64[*s & 0x3f];
  1503. s++;
  1504. }
  1505. if (reml--)
  1506. *d++ = b64[(*s >> 2) & 0x3f];
  1507. else
  1508. {
  1509. *d = 0;
  1510. *len = l*4;
  1511. return 0;
  1512. }
  1513. if (reml)
  1514. {
  1515. *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
  1516. s++;
  1517. *d++ = b64[((*s << 2) & 0x3c)];
  1518. }
  1519. else
  1520. {
  1521. *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
  1522. *d++ = '=';
  1523. }
  1524. *d++ = '=';
  1525. *d = 0;
  1526. *len = (l+1)*4;
  1527. return 0;
  1528. }
  1529. void
  1530. freeEnc64(Enc64_t *this)
  1531. {
  1532. this->next = freeEnc64List;
  1533. freeEnc64List = this;
  1534. }
  1535. Dec64_t *
  1536. initDec64(unsigned char * dest, int maxlen)
  1537. {
  1538. Dec64_t * this = freeDec64List;
  1539. if (this)
  1540. freeDec64List = freeDec64List->next;
  1541. else
  1542. this = (Dec64_t *)malloc(sizeof(Dec64_t));
  1543. this->dest = dest;
  1544. this->maxlen = maxlen;
  1545. this->curlen = 0;
  1546. this->nextra = 0;
  1547. return this;
  1548. }
  1549. int
  1550. freeDec64(Dec64_t *this)
  1551. {
  1552. this->next = freeDec64List;
  1553. freeDec64List = this;
  1554. return this->curlen;
  1555. }
  1556. int
  1557. Dec64(Dec64_t * this, unsigned char *source)
  1558. {
  1559. /* returns 0 normally
  1560. * -1 on badi
  1561. * 1 on too long
  1562. */
  1563. unsigned char * s;
  1564. unsigned char * d;
  1565. unsigned char * e;
  1566. unsigned char s1, s2, s3, s4;
  1567. int i;
  1568. int slen;
  1569. int len;
  1570. int nextra;
  1571. int newnextra;
  1572. unsigned char newextra[3];
  1573. nextra = this->nextra;
  1574. slen = strlen((char *)source);
  1575. len = (slen + nextra) / 4;
  1576. newnextra = (slen + nextra) - len * 4;
  1577. for (i = 0; i < newnextra; i++)
  1578. {
  1579. newextra[i] = source[slen-newnextra+i];
  1580. }
  1581. if (len * 3 > this->maxlen - this->curlen)
  1582. return 1;
  1583. for (d = this->dest + this->curlen, s = source, e = this->extra, i = 0;
  1584. i < len; i++)
  1585. {
  1586. if (nextra)
  1587. {
  1588. nextra--;
  1589. s1 = ub64[*e++];
  1590. }
  1591. else
  1592. s1 = ub64[*s++];
  1593. if (nextra)
  1594. {
  1595. nextra--;
  1596. s2 = ub64[*e++];
  1597. }
  1598. else
  1599. s2 = ub64[*s++];
  1600. if (nextra)
  1601. {
  1602. nextra--;
  1603. s3 = ub64[*e++];
  1604. }
  1605. else
  1606. s3 = ub64[*s++];
  1607. s4 = ub64[*s++];
  1608. if ((s1 | s2 | s3 | s4) & 0x80)
  1609. return -1;
  1610. *d++ = (s1 << 2) + (s2 >> 4);
  1611. this->curlen++;
  1612. if (s3 == 64)
  1613. break;
  1614. *d++ = (s2 << 4) + (s3 >> 2);
  1615. this->curlen++;
  1616. if (s4 == 64)
  1617. break;
  1618. *d++ = (s3 << 6) + s4;
  1619. this->curlen++;
  1620. }
  1621. this->nextra = newnextra;
  1622. memcpy(this->extra, newextra, 3);
  1623. return 0;
  1624. }