mmldif.c 51 KB

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