mmldif.c 51 KB

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