home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldif / line64.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-04  |  12.1 KB  |  611 lines

  1. /* line64.c - routines for dealing with the slapd line format */
  2. /* $OpenLDAP: pkg/ldap/libraries/libldif/line64.c,v 1.18.2.6 2000/10/03 20:23:04 kurt Exp $ */
  3. /*
  4.  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  5.  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  6.  */
  7.  
  8. #include "portable.h"
  9.  
  10. #include <stdio.h>
  11.  
  12. #include <ac/stdlib.h>
  13. #include <ac/ctype.h>
  14.  
  15. #include <ac/string.h>
  16. #include <ac/socket.h>
  17. #include <ac/time.h>
  18.  
  19. int ldif_debug = 0;
  20.  
  21. #include "ldap_log.h"
  22. #include "lber_pvt.h"
  23. #include "ldif.h"
  24.  
  25. #define RIGHT2            0x03
  26. #define RIGHT4            0x0f
  27. #define CONTINUED_LINE_MARKER    '\001'
  28.  
  29. #ifdef CSRIMALLOC
  30. #define ber_memalloc malloc
  31. #define ber_memcalloc calloc
  32. #define ber_memrealloc realloc
  33. #define ber_strdup strdup
  34. #endif
  35.  
  36. static const char nib2b64[0x40] =
  37.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  38.  
  39. static const unsigned char b642nib[0x80] = {
  40.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  41.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  42.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  43.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  44.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  45.     0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
  46.     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
  47.     0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  48.     0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  49.     0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
  50.     0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
  51.     0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
  52.     0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
  53.     0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
  54.     0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
  55.     0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
  56. };
  57.  
  58. /*
  59.  * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
  60.  * into components "type" and "value".  if a double colon separates type from
  61.  * value, then value is encoded in base 64, and parse_line un-decodes it
  62.  * (in place) before returning.
  63.  */
  64.  
  65. int
  66. ldif_parse_line(
  67.     LDAP_CONST char    *line,
  68.     char    **typep,
  69.     char    **valuep,
  70.     ber_len_t *vlenp
  71. )
  72. {
  73.     char    *s, *p, *d; 
  74.     char    nib;
  75.     int    b64, url;
  76.     char    *freeme, *type, *value;
  77.     ber_len_t vlen;
  78.  
  79.     *typep = NULL;
  80.     *valuep = NULL;
  81.     *vlenp = 0;
  82.  
  83.     /* skip any leading space */
  84.     while ( isspace( (unsigned char) *line ) ) {
  85.         line++;
  86.     }
  87.  
  88.     freeme = ber_strdup( line );
  89.  
  90.     if( freeme == NULL ) {
  91.         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
  92.             "ldif_parse_line: line malloc failed\n");
  93.         return( -1 );
  94.     }
  95.  
  96.     type = freeme;
  97.  
  98.     s = strchr( type, ':' );
  99.  
  100.     if ( s == NULL ) {
  101.         ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
  102.             "ldif_parse_line: missing ':' after %s\n",
  103.             type );
  104.         ber_memfree( freeme );
  105.         return( -1 );
  106.     }
  107.  
  108.     /* trim any space between type and : */
  109.     for ( p = &s[-1]; p > type && isspace( * (unsigned char *) p ); p-- ) {
  110.         *p = '\0';
  111.     }
  112.     *s++ = '\0';
  113.  
  114.     url = 0;
  115.     b64 = 0;
  116.  
  117.     if ( *s == '\0' ) {
  118.         /* no value */
  119.         value = "";
  120.         vlen = 0;
  121.         goto done;
  122.     }
  123.         
  124.     if ( *s == '<' ) {
  125.         s++;
  126.         url = 1;
  127.     } else if ( *s == ':' ) {
  128.         /* base 64 encoded value */
  129.         s++;
  130.         b64 = 1;
  131.     }
  132.  
  133.     /* skip space between : and value */
  134.     while ( isspace( (unsigned char) *s ) ) {
  135.         s++;
  136.     }
  137.  
  138.     /* check for continued line markers that should be deleted */
  139.     for ( p = s, d = s; *p; p++ ) {
  140.         if ( *p != CONTINUED_LINE_MARKER )
  141.             *d++ = *p;
  142.     }
  143.     *d = '\0';
  144.  
  145.     /* if no value is present, error out */
  146.     if ( *s == '\0' ) {
  147.         ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
  148.             "ldif_parse_line: %s missing %svalue\n", type,
  149.                 url ? "URL " : b64 ? "base64 " : "" );
  150.         value = NULL;
  151.         vlen = 0;
  152.         goto done;
  153.     }
  154.  
  155.     if ( b64 ) {
  156.         char *byte = s;
  157.  
  158.         value = s;
  159.  
  160.         for ( p = s, vlen = 0; p < d; p += 4, vlen += 3 ) {
  161.             int i;
  162.             for ( i = 0; i < 4; i++ ) {
  163.                 if ( p[i] != '=' && (p[i] & 0x80 ||
  164.                     b642nib[ p[i] & 0x7f ] > 0x3f) ) {
  165.                     ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
  166.                         "ldif_parse_line: %s: invalid base64 encoding"
  167.                         " char (%c) 0x%x\n",
  168.                         type, p[i], p[i] );
  169.                     ber_memfree( freeme );
  170.                     return( -1 );
  171.                 }
  172.             }
  173.  
  174.             /* first digit */
  175.             nib = b642nib[ p[0] & 0x7f ];
  176.             byte[0] = nib << 2;
  177.             /* second digit */
  178.             nib = b642nib[ p[1] & 0x7f ];
  179.             byte[0] |= nib >> 4;
  180.             byte[1] = (nib & RIGHT4) << 4;
  181.             /* third digit */
  182.             if ( p[2] == '=' ) {
  183.                 vlen += 1;
  184.                 break;
  185.             }
  186.             nib = b642nib[ p[2] & 0x7f ];
  187.             byte[1] |= nib >> 2;
  188.             byte[2] = (nib & RIGHT2) << 6;
  189.             /* fourth digit */
  190.             if ( p[3] == '=' ) {
  191.                 vlen += 2;
  192.                 break;
  193.             }
  194.             nib = b642nib[ p[3] & 0x7f ];
  195.             byte[2] |= nib;
  196.  
  197.             byte += 3;
  198.         }
  199.         s[ vlen ] = '\0';
  200.  
  201.     } else if ( url ) {
  202.         if( ldif_fetch_url( s, &value, &vlen ) ) {
  203.             ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
  204.                 "ldif_parse_line: %s: URL \"%s\" fetch failed\n",
  205.                 type, s );
  206.             ber_memfree( freeme );
  207.             return( -1 );
  208.         }
  209.  
  210.     } else {
  211.         value = s;
  212.         vlen = (int) (d - s);
  213.     }
  214.  
  215. done:
  216.     type = ber_strdup( type );
  217.  
  218.     if( type == NULL ) {
  219.         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
  220.             "ldif_parse_line: type malloc failed\n");
  221.         ber_memfree( freeme );
  222.         return( -1 );
  223.     }
  224.  
  225.     if( !url && value != NULL ) {
  226.         p = ber_memalloc( vlen + 1 );
  227.         if( p == NULL ) {
  228.             ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
  229.                 "ldif_parse_line: value malloc failed\n");
  230.             ber_memfree( type );
  231.             ber_memfree( freeme );
  232.             return( -1 );
  233.         }
  234.         AC_MEMCPY( p, value, vlen );
  235.         p[vlen] = '\0';
  236.         value = p;
  237.     }
  238.  
  239.     ber_memfree( freeme );
  240.  
  241.     *typep = type;
  242.     *valuep = value;
  243.     *vlenp = vlen;
  244.  
  245.     return( 0 );
  246. }
  247.  
  248. /*
  249.  * ldif_getline - return the next "line" (minus newline) of input from a
  250.  * string buffer of lines separated by newlines, terminated by \n\n
  251.  * or \0.  this routine handles continued lines, bundling them into
  252.  * a single big line before returning.  if a line begins with a white
  253.  * space character, it is a continuation of the previous line. the white
  254.  * space character (nb: only one char), and preceeding newline are changed
  255.  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
  256.  * ldif_parse_line() routine above.
  257.  *
  258.  * ldif_getline will skip over any line which starts '#'.
  259.  *
  260.  * ldif_getline takes a pointer to a pointer to the buffer on the first call,
  261.  * which it updates and must be supplied on subsequent calls.
  262.  */
  263.  
  264. char *
  265. ldif_getline( char **next )
  266. {
  267.     char *line;
  268.  
  269.     do {
  270.         if ( *next == NULL || **next == '\n' || **next == '\0' ) {
  271.             return( NULL );
  272.         }
  273.  
  274.         line = *next;
  275.  
  276.         while ( (*next = strchr( *next, '\n' )) != NULL ) {
  277.             unsigned char c = *(*next + 1);
  278.  
  279.             if ( !isspace( c ) || c == '\n' ) {
  280.                 *(*next)++ = '\0';
  281.                 break;
  282.             }
  283.  
  284.             **next = CONTINUED_LINE_MARKER;
  285.             *(*next+1) = CONTINUED_LINE_MARKER;
  286.             (*next)++;
  287.         }
  288.     } while( *line == '#' );
  289.  
  290.     return( line );
  291. }
  292.  
  293. /* compatibility with U-Mich off by one bug */
  294. #define LDIF_KLUDGE 1
  295.  
  296. void
  297. ldif_sput(
  298.     char **out,
  299.     int type,
  300.     LDAP_CONST char *name,
  301.     LDAP_CONST char *val,
  302.     ber_len_t vlen )
  303. {
  304.     const unsigned char *byte, *stop;
  305.     unsigned char    buf[3];
  306.     unsigned long    bits;
  307.     char        *save;
  308.     int        pad;
  309.  
  310.     ber_len_t savelen;
  311.     ber_len_t len=0;
  312.     ber_len_t i;
  313.  
  314.     /* prefix */
  315.     switch( type ) {
  316.     case LDIF_PUT_COMMENT:
  317.         *(*out)++ = '#';
  318.         len++;
  319.  
  320.         if( vlen ) {
  321.             *(*out)++ = ' ';
  322.             len++;
  323.         }
  324.  
  325.         break;
  326.  
  327.     case LDIF_PUT_SEP:
  328.         *(*out)++ = '\n';
  329.         return;
  330.     }
  331.  
  332.     /* name (attribute type) */
  333.     if( name != NULL ) {
  334.         /* put the name + ":" */
  335.         for ( i=0 ; name[i]; i++ ) {
  336.             *(*out)++ = name[i];
  337.             len++;
  338.         }
  339.  
  340.         if( type != LDIF_PUT_COMMENT ) {
  341.             *(*out)++ = ':';
  342.             len++;
  343.         }
  344.  
  345.     }
  346. #ifdef LDAP_DEBUG
  347.     else {
  348.         assert( type == LDIF_PUT_COMMENT );
  349.     }
  350. #endif
  351.  
  352.     if( vlen == 0 ) {
  353.         *(*out)++ = '\n';
  354.         return;
  355.     }
  356.  
  357.     switch( type ) {
  358.     case LDIF_PUT_NOVALUE:
  359.         *(*out)++ = '\n';
  360.         return;
  361.  
  362.     case LDIF_PUT_URL: /* url value */
  363.         *(*out)++ = '<';
  364.         len++;
  365.         break;
  366.  
  367.     case LDIF_PUT_B64: /* base64 value */
  368.         *(*out)++ = ':';
  369.         len++;
  370.         break;
  371.     }
  372.  
  373.     switch( type ) {
  374.     case LDIF_PUT_TEXT:
  375.     case LDIF_PUT_URL:
  376.     case LDIF_PUT_B64:
  377.         *(*out)++ = ' ';
  378.         len++;
  379.         /* fall-thru */
  380.  
  381.     case LDIF_PUT_COMMENT:
  382.         /* pre-encoded names */
  383.         for ( i=0; i < vlen; i++ ) {
  384.             if ( len > LDIF_LINE_WIDTH ) {
  385.                 *(*out)++ = '\n';
  386.                 *(*out)++ = ' ';
  387.                 len = 1;
  388.             }
  389.  
  390.             *(*out)++ = val[i];
  391.             len++;
  392.         }
  393.         *(*out)++ = '\n';
  394.         return;
  395.     }
  396.  
  397.     save = *out;
  398.     savelen = len;
  399.  
  400.     *(*out)++ = ' ';
  401.     len++;
  402.  
  403.     stop = (const unsigned char *) (val + vlen);
  404.  
  405.     if ( type == LDIF_PUT_VALUE
  406.         && isgraph( val[0] ) && val[0] != ':' && val[0] != '<'
  407.         && isgraph( val[vlen-1] )
  408. #ifndef LDAP_BINARY_DEBUG
  409.         && strstr( name, ";binary" ) == NULL
  410. #endif
  411. #ifndef LDAP_PASSWD_DEBUG
  412.         && strcasecmp( name, "userPassword" ) != 0    /* encode userPassword */
  413.         && strcasecmp( name, "2.5.4.35" ) != 0        /* encode userPassword */
  414. #endif
  415.     ) {
  416.         int b64 = 0;
  417.  
  418.         for ( byte = (const unsigned char *) val; byte < stop;
  419.             byte++, len++ )
  420.         {
  421.             if ( !isascii( *byte ) || !isprint( *byte ) ) {
  422.                 b64 = 1;
  423.                 break;
  424.             }
  425.             if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
  426.                 *(*out)++ = '\n';
  427.                 *(*out)++ = ' ';
  428.                 len = 1;
  429.             }
  430.             *(*out)++ = *byte;
  431.         }
  432.  
  433.         if( !b64 ) {
  434.             *(*out)++ = '\n';
  435.             return;
  436.         }
  437.     }
  438.  
  439.     *out = save;
  440.     *(*out)++ = ':';
  441.     *(*out)++ = ' ';
  442.     len = savelen + 2;
  443.  
  444.     /* convert to base 64 (3 bytes => 4 base 64 digits) */
  445.     for ( byte = (const unsigned char *) val;
  446.         byte < stop - 2;
  447.         byte += 3 )
  448.     {
  449.         bits = (byte[0] & 0xff) << 16;
  450.         bits |= (byte[1] & 0xff) << 8;
  451.         bits |= (byte[2] & 0xff);
  452.  
  453.         for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
  454.             if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
  455.                 *(*out)++ = '\n';
  456.                 *(*out)++ = ' ';
  457.                 len = 1;
  458.             }
  459.  
  460.             /* get b64 digit from high order 6 bits */
  461.             *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
  462.         }
  463.     }
  464.  
  465.     /* add padding if necessary */
  466.     if ( byte < stop ) {
  467.         for ( i = 0; byte + i < stop; i++ ) {
  468.             buf[i] = byte[i];
  469.         }
  470.         for ( pad = 0; i < 3; i++, pad++ ) {
  471.             buf[i] = '\0';
  472.         }
  473.         byte = buf;
  474.         bits = (byte[0] & 0xff) << 16;
  475.         bits |= (byte[1] & 0xff) << 8;
  476.         bits |= (byte[2] & 0xff);
  477.  
  478.         for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
  479.             if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
  480.                 *(*out)++ = '\n';
  481.                 *(*out)++ = ' ';
  482.                 len = 1;
  483.             }
  484.  
  485.             if( i + pad < 4 ) {
  486.                 /* get b64 digit from low order 6 bits */
  487.                 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
  488.             } else {
  489.                 *(*out)++ = '=';
  490.             }
  491.         }
  492.     }
  493.     *(*out)++ = '\n';
  494. }
  495.  
  496.  
  497. /*
  498.  * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
  499.  */
  500. char *
  501. ldif_put(
  502.     int type,
  503.     LDAP_CONST char *name,
  504.     LDAP_CONST char *val,
  505.     ber_len_t vlen )
  506. {
  507.     char    *buf, *p;
  508.     ber_len_t nlen;
  509.  
  510.     nlen = ( name != NULL ) ? strlen( name ) : 0;
  511.  
  512.     buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED( nlen, vlen ) + 1 );
  513.  
  514.     if ( buf == NULL ) {
  515.         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
  516.             "ldif_type_and_value: malloc failed!" );
  517.         return NULL;
  518.     }
  519.  
  520.     p = buf;
  521.     ldif_sput( &p, type, name, val, vlen );
  522.     *p = '\0';
  523.  
  524.     return( buf );
  525. }
  526.  
  527. int ldif_is_not_printable(
  528.     LDAP_CONST char *val,
  529.     ber_len_t vlen )
  530. {
  531.     if( vlen == 0 || val == NULL  ) {
  532.         return -1;
  533.     }
  534.  
  535.     if( isgraph( val[0] ) && val[0] != ':' && val[0] != '<' &&
  536.         isgraph( val[vlen-1] ) )
  537.     {
  538.         ber_len_t i;
  539.  
  540.         for ( i = 0; val[i]; i++ ) {
  541.             if ( !isascii( val[i] ) || !isprint( val[i] ) ) {
  542.                 return 1;
  543.             }
  544.         }
  545.  
  546.         return 0;
  547.     }
  548.  
  549.     return 1;
  550. }
  551.  
  552. /*
  553.  * slap_read_ldif - read an ldif record.  Return 1 for success, 0 for EOF.
  554.  */
  555. int
  556. ldif_read_record(
  557.     FILE        *fp,
  558.     int         *lno,        /* ptr to line number counter              */
  559.     char        **bufp,     /* ptr to malloced output buffer           */
  560.     int         *buflenp )  /* ptr to length of *bufp                  */
  561. {
  562.     char        linebuf[BUFSIZ], *line, *nbufp;
  563.     ber_len_t   lcur = 0, len, linesize;
  564.     int         last_ch = '\n', found_entry = 0, stop;
  565.  
  566.     line     = linebuf;
  567.     linesize = sizeof( linebuf );
  568.  
  569.     for ( stop = feof( fp );  !stop;  last_ch = line[len-1] ) {
  570.         if ( fgets( line, linesize, fp ) == NULL ) {
  571.             stop = 1;
  572.             /* Add \n in case the file does not end with newline */
  573.             line = "\n";
  574.         }
  575.         len = strlen( line );
  576.  
  577.         if ( last_ch == '\n' ) {
  578.             (*lno)++;
  579.  
  580.             if ( line[0] == '\n' ) {
  581.                 if ( !found_entry )
  582.                     continue;
  583.                 break;
  584.             }
  585.  
  586.             if ( !found_entry ) {
  587.                 /* Found a new entry */
  588.                 found_entry = 1;
  589.  
  590.                 if ( isdigit( (unsigned char) line[0] ) ) {
  591.                     /* skip index */
  592.                     continue;
  593.                 }
  594.             }            
  595.         }
  596.  
  597.         if ( *buflenp - lcur <= len ) {
  598.             *buflenp += len + BUFSIZ;
  599.             nbufp = ber_memrealloc( *bufp, *buflenp );
  600.             if( nbufp == NULL ) {
  601.                 return 0;
  602.             }
  603.             *bufp = nbufp;
  604.         }
  605.         strcpy( *bufp + lcur, line );
  606.         lcur += len;
  607.     }
  608.  
  609.     return( found_entry );
  610. }
  611.