]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/chlog2replog.c
Import KRB_LIBS fix from -devel.
[openldap] / servers / slapd / tools / chlog2replog.c
1 /*
2  * Copyright (c) 1990, 1995 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 /*
14  * chlog2replog - read a quipu-style changelog on stdin and write a
15  * slapd-style replog on stdout, or write to a file, respecting
16  * slapd/slurpd locking conventions.
17  */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include <ac/ctype.h>
25 #include <ac/string.h>
26 #include <ac/unistd.h>
27
28 #include <quipu/commonarg.h>
29 #include <quipu/attrvalue.h>
30
31 #include "ldif.h"
32
33 static int dn2ldif(PS ps, DN dn);
34 static void de_t61(char *s, int t61mark);
35
36 extern FILE *lock_fopen( char *, char *, FILE ** );
37 extern int lock_fclose( FILE *, FILE * );
38 extern void *ch_realloc( void *, unsigned long ); 
39
40 short   ldap_dn_syntax;
41 PS      rps;
42 char    *progname;
43 int     ldap_syslog = 0;
44 int     ldap_syslog_level = 0;
45
46
47 #define ST_START        0
48 #define ST_DN           2
49 #define ST_TYPE         3
50 #define ST_ARGS         4
51 #define ST_NL1          5
52 #define ST_PUNT         6
53 #define ST_BAD          7
54 #define ST_CONCAT       8
55
56 #define TY_MODIFYTYPE   1
57 #define TY_ADD          2
58 #define TY_REMOVE       3
59 #define TY_NEWRDN       4
60 #define TY_PUNT         5
61 #define TY_MODIFYARGS   6
62
63 #define MOD_ADDVALUES           1
64 #define MOD_ADDATTRIBUTE        2
65 #define MOD_REMOVEATTRIBUTE     3
66 #define MOD_REMOVEVALUES        4
67
68
69 char *
70 dn2ldap( char *edbdn )
71 {
72     DN          dn;
73     PS          str_ps;
74     char        *ldapdn;
75     int         len;
76     static int  inited = 0;
77
78     if ( !inited ) {
79         /* load & initialize quipu syntax handlers */
80         quipu_syntaxes();
81
82 #ifdef LDAP_USE_PP
83         pp_quipu_init( progname );
84 #endif
85
86         dsap_init( NULL, NULL );
87
88         if (( ldap_dn_syntax = str2syntax( "DN" )) == 0 ) {
89             return( NULL );
90         }
91         inited = 1;
92     }
93
94     if (( dn = str2dn( edbdn )) == NULLDN ) {
95         return( NULL );
96     }
97
98     if (( str_ps = ps_alloc( str_open )) == NULLPS ||
99             str_setup( str_ps, NULLCP, 0, 0 ) == NOTOK ) {
100         dn_free( dn );
101         return( NULL );
102     }
103
104     if ( dn2ldif( str_ps, dn ) != 0 ) {
105         ps_free( str_ps );
106         dn_free( dn );
107         return( NULL );
108     }
109
110     dn_free( dn );
111     len = ( str_ps->ps_ptr - str_ps->ps_base );
112
113     if (( ldapdn = malloc( len + 1 )) == NULL ) {
114         ps_free( str_ps );
115         return( NULL );
116     }
117
118     memcpy( ldapdn, str_ps->ps_base, len );
119     ldapdn[ len ] = '\0';
120     ps_free( str_ps );
121     return( ldapdn );
122 }
123
124
125 #define SEPARATOR(c)    (c == ',' || c == ';')
126 #define SPACE(c)        (c == ' ' || c == '\n')
127
128 static int
129 dn2ldif( PS ps, DN dn )
130 {
131     RDN rdn;
132     int firstrdn, rc;
133     char        *value;
134     PS  rps;
135
136     if ( dn == NULLDN ) {
137         return( 0 );
138     }
139
140     if ( dn->dn_parent != NULLDN ) {
141         if (( rc = dn2ldif( ps, dn->dn_parent )) != 0 ) {
142             return( rc );
143         }
144         ps_print( ps, ", " );
145     }
146
147     if ( (rps = ps_alloc( str_open )) == NULLPS ||
148             str_setup( rps, NULLCP, 0, 0 ) == NOTOK ) {
149         return( -1 );
150     }
151
152     firstrdn = 1;
153     for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
154         if ( firstrdn ) {
155             firstrdn = 0;
156         } else {
157             ps_print( ps, " + " );
158         }
159
160         AttrT_print( ps, rdn->rdn_at, EDBOUT );
161         ps_print( ps, "=" );
162
163         if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
164             if (( rc = dn2ldif( rps, (DN) rdn->rdn_av.av_struct )) != 0 ) {
165                 return( rc );
166             }
167             *rps->ps_ptr = '\0';
168             value = rps->ps_base;
169         } else {
170             AttrV_print( rps, &rdn->rdn_av, EDBOUT );
171             *rps->ps_ptr = '\0';
172             value = rps->ps_base;
173             de_t61( value, 0 );
174         }
175
176         /*
177          * ,+="\\\n all go in quotes.  " and \\ need to
178          * be preceeded by \\.
179          */
180
181         if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
182                 || SPACE( value[max( strlen(value) - 1, 0 )] ) ) {
183             char        *p, *t, *tmp;
184             int specialcount;
185
186             ps_print( ps, "\"" );
187
188             specialcount = 0;
189             for ( p = value; *p != '\0'; p++ ) {
190                 if ( *p == '"' || *p == '\\' ) {
191                     specialcount++;
192                 }
193             }
194             if ( specialcount > 0 ) {
195                 tmp = smalloc( strlen( value ) + specialcount + 1 );
196                 for ( p = value, t = tmp; *p != '\0'; p++ ) {
197                     switch ( *p ) {
198                     case '"':
199                     case '\\':
200                             *t++ = '\\';
201                             /* FALL THROUGH */
202                     default:
203                             *t++ = *p;
204                     }
205                 }
206                 *t = '\0';
207                 ps_print( ps, tmp );
208                 free( tmp );
209             } else {
210                 ps_print( ps, value );
211             }
212
213             ps_print( ps, "\"" );
214         } else {
215             ps_print( ps, value );
216         }
217
218         rps->ps_ptr = rps->ps_base;
219     }
220
221     ps_free( rps );
222
223     return( 0 );
224 }
225
226 #define T61     "{T.61}"
227 #define T61LEN  6
228
229
230
231 static void
232 de_t61(char *s, int t61mark)
233 {
234         char    *next = s;
235         int     c, hex;
236
237         while ( *s ) {
238                 switch ( *s ) {
239                 case '{' :
240                         if ( strncasecmp( s, T61, T61LEN) == 0 ) {
241                                 s += T61LEN;
242                                 if ( t61mark )
243                                         *next++ = '@';
244                         } else {
245                                 *next++ = *s++;
246                         }
247                         break;
248
249                 case '\\':
250                         c = *(s + 1);
251                         if ( c == '\n' ) {
252                                 s += 2;
253                                 if ( *s == '\t' )
254                                         s++;
255                                 break;
256                         }
257                         if ( isdigit( c ) )
258                                 hex = c - '0';
259                         else if ( c >= 'A' && c <= 'F' )
260                                 hex = c - 'A' + 10;
261                         else if ( c >= 'a' && c <= 'f' )
262                                 hex = c - 'a' + 10;
263                         else {
264                                 *next++ = *s++;
265                                 break;
266                         }
267                         hex <<= 4;
268                         c = *(s + 2);
269                         if ( isdigit( c ) )
270                                 hex += c - '0';
271                         else if ( c >= 'A' && c <= 'F' )
272                                 hex += c - 'A' + 10;
273                         else if ( c >= 'a' && c <= 'f' )
274                                 hex += c - 'a' + 10;
275                         else {
276                                 *next++ = *s++;
277                                 *next++ = *s++;
278                                 break;
279                         }
280
281                         *next++ = hex;
282                         s += 3;
283                         break;
284
285                 default:
286                         *next++ = *s++;
287                         break;
288                 }
289         }
290         *next = '\0';
291 }
292
293
294
295
296 char *
297 getattr(char *buf, char sep)
298 {
299     char *val;
300 #define RBSIZE 255
301     static char retbuf[ RBSIZE ];
302
303     if (( val = strchr( buf, sep )) != NULL ) {
304         strncpy( retbuf, buf, val - buf );
305         retbuf[ val - buf ] = '\0';
306     } else {
307         retbuf[ 0 ] = '\0';
308     }
309     return( retbuf );
310 }
311
312
313 char *
314 getattr_ldif(char *buf)
315 {
316     return( getattr( buf, ':' ));
317 }
318
319
320 char *
321 getattr_edb(char *buf)
322 {
323     return( getattr( buf, '=' ));
324 }
325
326 char *
327 getval(char *buf, char sep)
328 {
329     char *val;
330
331     if (( val = strchr( buf, sep )) != NULL ) {
332         return( strdup( ++val ));
333     } else {
334         return( NULL );
335     }
336 }
337
338 char *
339 getval_ldif(char *buf)
340 {
341     return( getval( buf, ':' ));
342 }
343
344
345 char *
346 getval_edb(char *buf)
347 {
348     return( getval( buf, '=' ));
349 }
350
351
352
353
354 int
355 isDNsyntax(char *attr)
356 {
357     oid_table_attr *p, *name2attr(char *);
358
359     p = name2attr( attr );
360     if ( p == ( oid_table_attr * ) 0 ) {
361         return( -1 );
362     }
363     if ( p->oa_syntax == ldap_dn_syntax ) {
364         return( 1 );
365     } else {
366         return( 0 );
367     }
368 }
369
370
371
372 void
373 print_as(Attr_Sequence as, int modtype, FILE *ofp)
374 {
375     Attr_Sequence p;
376     AV_Sequence av;
377     char *attrname, *tmpdn, *obuf;
378
379     p = as;
380     for ( p = as; p != NULLATTR; p = p->attr_link) {
381         rps->ps_ptr = rps->ps_base;
382         AttrT_print( rps,  p->attr_type, EDBOUT );
383         *rps->ps_ptr = '\0';
384         attrname = strdup( rps->ps_base  );
385         if ( modtype != 0 ) {
386             switch ( modtype ) {
387             case MOD_ADDVALUES:
388             case MOD_ADDATTRIBUTE:
389                 fprintf( ofp, "add: %s\n", attrname );
390                 break;
391             case MOD_REMOVEATTRIBUTE:
392             case MOD_REMOVEVALUES:
393                 fprintf( ofp, "delete: %s\n", attrname );
394                 break;
395             default:
396                 break;
397             }
398         }
399         for ( av = p->attr_value; av != NULLAV; av = av->avseq_next ) {
400             rps->ps_ptr = rps->ps_base;
401             AttrV_print( rps, &av->avseq_av, EDBOUT );
402             *rps->ps_ptr = '\0';
403             de_t61( rps->ps_base, 0 );
404             if ( isDNsyntax( attrname )) {
405                 tmpdn = dn2ldap( rps->ps_base );
406                 obuf = ldif_type_and_value( attrname, tmpdn,
407                         strlen( tmpdn ));
408                 free( tmpdn );
409             } else {
410                 obuf = ldif_type_and_value( attrname, rps->ps_base,
411                         strlen( rps->ps_base ));
412             }
413             if ( obuf != NULL ) {
414                 fputs( obuf, ofp );
415                 free( obuf );
416             }
417         }
418         if ( modtype != 0 ) {
419             fprintf( ofp, "-\n" );
420         }
421         free( attrname );
422     }
423 }
424
425
426
427 void
428 usage( char *name )
429 {
430     fprintf( stderr, "usage: %s -d dn-suffix -r replica:port ", name );
431     fprintf( stderr, "[-r replica:port...] [-o outputfile]\n" );
432 }
433
434
435
436 main( int argc, char **argv )
437 {
438     char                *ldapdn, nbuf[ 4096 ], *buf, *p;
439     int                 state, prevstate, modstate, modtype, i;
440     int                 buflen, nbuflen;
441     Attr_Sequence       as;
442     PS                  std_ps;
443     int                 arg;
444     char                *ofile = NULL;
445     FILE                *ofp, *lfp;
446
447     extern char         *optarg;
448     char                **replicas = NULL;
449     int                 nreplicas = 0;
450     char                *dn_suffix = NULL;
451
452     if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
453         progname = argv[ 0 ];
454     } else {
455         ++progname;
456     }
457
458     while (( arg = getopt( argc, argv, "o:r:d:" )) != EOF ) {
459         switch( arg ) {
460         case 'o':
461             ofile = optarg;
462             break;
463         case 'r':
464             replicas = (char **) ch_realloc( (char *) replicas, (unsigned long)
465                     ( nreplicas + 2 ) * sizeof( char * ));
466             replicas[ nreplicas ] = optarg;
467             replicas[ nreplicas + 1 ] = NULL;
468             nreplicas++;
469             break;
470         case 'd':
471             dn_suffix = optarg;
472             break;
473         default:
474             usage( progname );
475             exit( 1 );
476         }
477     }
478
479     if (( dn_suffix == NULL ) || ( nreplicas == 0 )) {
480         usage( progname );
481         exit( 1 );
482     }
483
484     if ( ofile == NULL ) {
485         /* Just write to stdout */
486         ofp = stdout;
487     }
488
489
490     state = prevstate = ST_START;
491     buf = NULL;
492     as = NULL;
493     if (( std_ps = ps_alloc( std_open )) == NULLPS ||
494             std_setup( std_ps, ofp ) != OK ) {
495         fprintf( stderr, "std_ps setup failed - help!\n" );
496         exit( 1 );
497     }
498     if (( rps = ps_alloc( str_open )) == NULLPS ||
499             str_setup( rps, NULLCP, 0, 0 ) != OK ) {
500         fprintf( stderr, "rps setup failed - help!\n" );
501         exit( 1 );
502     }
503
504
505     while ( gets( nbuf ) != NULL ) {
506         if ( nbuf[ 0 ] == '\0' ) {
507             if ( state == ST_NL1 ) {
508                 if ( prevstate == ST_ARGS ) {
509                     /* We've got an attribute sequence to print */
510                     if ( modtype == TY_ADD ) {
511                         print_as( as, 0, ofp ); 
512                     } else {
513                         print_as( as, modstate, ofp ); 
514                     }
515                     /* as_print( std_ps, as, EDBOUT ); */
516                     as_free( as );
517                     as = NULL;
518                 }
519                 state = ST_START;
520                 fprintf( ofp, "\n" );
521                 fflush( ofp );
522                 /* If writing to a file, release the lock */
523                 if ( ofile != NULL ) {
524                     lock_fclose( ofp, lfp );
525                 }
526             } else {
527                 prevstate = state;
528                 state = ST_NL1;
529             }
530             continue;
531         }
532
533         /* See if we've got a line continuation to deal with */
534         nbuflen = strlen( nbuf );
535         if ( state == ST_CONCAT ) {
536             for ( p = nbuf; isspace( *p ); p++, nbuflen-- ); /* skip space */
537             buf = realloc( buf, buflen + nbuflen + 1 );
538             strcat( buf, p );
539             buflen += ( nbuflen );
540         } else {
541             if ( buf != NULL ) {
542                 free( buf );
543             }
544             buf = strdup( nbuf );
545             buflen = nbuflen;
546         }
547         if ( buf[ buflen - 1 ] == '\\' ) {
548             if ( state != ST_CONCAT ) {
549                 prevstate = state;
550             }
551             state = ST_CONCAT;
552             buf[ buflen - 1 ] = '\0';
553             buflen--;
554             continue;
555         } else if ( state == ST_CONCAT ) {
556             state = prevstate;
557         }
558
559         if ( state == ST_PUNT ) {
560             continue;
561         }
562
563         if ( state == ST_START ) {
564             /*
565              * Acquire the file lock if writing to a file.
566              */
567             if ( ofile != NULL ) {
568                 if (( ofp = lock_fopen( ofile, "a", &lfp )) == NULL ) {
569                     perror( "open" );
570                     exit( 1 );
571                 }
572             }
573             /*
574              * If we have a changelog entry, then go ahead
575              * and write the replica: lines for the replog entry.
576              */
577             for ( i = 0; replicas[ i ] != NULL; i++ ) {
578                 fprintf( ofp, "replica: %s\n", replicas[ i ] );
579             }
580             fprintf( ofp, "time: %ld\n", time( NULL ));
581             state = ST_DN;
582             continue;
583         }
584
585         if ( state == ST_DN ) {
586             /* Second line - dn (quipu-style) of entry to be modified */
587             if (( ldapdn = dn2ldap( buf )) == NULL ) {
588                 fprintf( ofp, "dn: (conversion failed)\n" );
589             } else {
590                 fprintf( ofp, "dn: %s%s\n", ldapdn, dn_suffix );
591                 free( ldapdn );
592             }
593             state = ST_TYPE;
594             continue;
595         }
596
597         if ( state == ST_TYPE ) {
598             state = ST_ARGS;
599             modstate = 0;
600             if ( !strcmp( buf, "modify" )) {
601                 modtype = TY_MODIFYTYPE;
602                 fprintf( ofp, "changetype: modify\n" );
603             } else if ( !strcmp( buf, "add" )) {
604                 modtype = TY_ADD;
605                 fprintf( ofp, "changetype: add\n" );
606                 as = NULL;
607             } else if ( !strcmp( buf, "remove" )) {
608                 modtype = TY_REMOVE;
609                 fprintf( ofp, "changetype: delete\n" );
610             } else if ( !strcmp( buf, "newrdn" )) {
611                 modtype = TY_NEWRDN;
612                 fprintf( ofp, "changetype: modrdn\n" );
613             } else {
614                 modtype = TY_PUNT;
615                 state = ST_BAD;
616             }
617             continue;
618         }
619
620         if ( state == ST_ARGS ) {
621             switch ( modtype ) {
622             case TY_NEWRDN:
623                 fprintf( ofp, "newrdn: %s\n", buf );
624                 break;
625             case TY_REMOVE:     /* No additional args */
626                 break;
627             case TY_ADD:
628                 as = as_combine( as, buf, 0 );
629                 break;
630             case TY_MODIFYTYPE:
631             case TY_MODIFYARGS:
632                 if ( buf[ 0 ] == '\0' ) {
633                     state == ST_NL1;
634                     if ( as != NULL ) {
635                         print_as( as, modstate, ofp);
636                         as_free( as );
637                         as = NULL;
638                     }
639                     continue;
640                 }
641                 if (!strcmp( buf, "addvalues" )) {
642                     if ( as != NULL ) {
643                         print_as( as, modstate, ofp );
644                         as_free( as );
645                         as = NULL;
646                     }
647                     modstate = MOD_ADDVALUES;
648                     continue;
649                 } else if (!strcmp( buf, "removevalues" )) {
650                     if ( as != NULL ) {
651                         print_as( as, modstate, ofp );
652                         as_free( as );
653                         as = NULL;
654                     }
655                     modstate = MOD_REMOVEVALUES;
656                     continue;
657                 } else if (!strcmp( buf, "addattribute" )) {
658                     if ( as != NULL ) {
659                         print_as( as, modstate, ofp );
660                         as_free( as );
661                         as = NULL;
662                     }
663                     modstate = MOD_ADDATTRIBUTE;
664                     continue;
665                 } else if (!strcmp( buf, "removeattribute" )) {
666                     if ( as != NULL ) {
667                         print_as( as, modstate, ofp );
668                         as_free( as );
669                         as = NULL;
670                     }
671                     modstate = MOD_REMOVEATTRIBUTE;
672                     continue;
673                 } 
674                 switch ( modstate ) {
675                 case MOD_ADDVALUES:
676                     as = as_combine( as, buf, 0 );
677                     break;
678                 case MOD_REMOVEVALUES:
679                     as = as_combine( as, buf, 0 );
680                     break;
681                 case MOD_ADDATTRIBUTE:
682                     as = as_combine( as, buf, 0 );
683                     break;
684                 case MOD_REMOVEATTRIBUTE:
685                     fprintf( ofp, "delete: %s\n-\n", buf);
686                     break;
687                 }
688             }
689             continue;
690         }
691     }
692
693     if ( ofile != NULL ) {
694         lock_fclose( ofp, lfp );
695         sprintf( nbuf, "%s.lock", ofile );
696         (void) unlink( nbuf );
697     }
698     exit( 0 );
699 }