mmldif.c 51 KB

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