Changeset 126


Ignore:
Timestamp:
08/19/08 19:31:33 (16 years ago)
Author:
tim
Message:

improved validation and output of key class names, MULTI_SZ and other unicode strings, and improved warnings and other error messages.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/regfi.h

    r125 r126  
    406406                      uint32* cell_length, bool* unalloc);
    407407
     408char* regfi_parse_classname(REGF_FILE* file, uint32 offset,
     409                            uint16* name_length, bool strict);
     410
    408411#endif  /* _REGFI_H */
  • trunk/lib/regfi.c

    r125 r126  
    15101510
    15111511
    1512 
     1512/*******************************************************************
     1513 *******************************************************************/
    15131514REGF_NK_REC* regfi_parse_nk(REGF_FILE* file, uint32 offset,
    15141515                            uint32 max_size, bool strict)
     
    16351636  ret_val->keyname[ret_val->name_length] = '\0';
    16361637
    1637 
    1638   /***/
    1639  
    1640   if(ret_val->classname_length > 0
    1641      && ret_val->classname_off != REGF_OFFSET_NONE
    1642      && ret_val->classname_off == (ret_val->classname_off & 0xFFFFFFF8))
    1643   {
    1644     ret_val->classname = (char*)zalloc(ret_val->classname_length+1);
    1645     if(ret_val->classname != NULL)
    1646     {
    1647       if(!regfi_parse_cell(file->fd, ret_val->classname_off+REGF_BLOCKSIZE,
    1648                            (uint8*)ret_val->classname, ret_val->classname_length,
    1649                            &cell_length, &unalloc)
    1650          || (cell_length < ret_val->classname_length)
    1651          || (strict && unalloc))
     1638  if(ret_val->classname_off != REGF_OFFSET_NONE)
     1639  {
     1640    ret_val->classname
     1641      = regfi_parse_classname(file, ret_val->classname_off+REGF_BLOCKSIZE,
     1642                              &ret_val->classname_length, strict);
     1643    /*
     1644    if(strict && ret_val->classname == NULL)
     1645        return NULL;
     1646    */
     1647  }
     1648
     1649  return ret_val;
     1650}
     1651
     1652
     1653/*******************************************************************/
     1654/* XXX: Not currently validating against hbin length.              */
     1655/*******************************************************************/
     1656char* regfi_parse_classname(REGF_FILE* file, uint32 offset,
     1657                            uint16* name_length, bool strict)
     1658{
     1659  char* ret_val = NULL;
     1660  uint32 length;
     1661  uint32 cell_length;
     1662  bool unalloc = false;
     1663
     1664  if(*name_length > 0 && offset != REGF_OFFSET_NONE
     1665     && offset == (offset & 0xFFFFFFF8))
     1666  {   
     1667    if(!regfi_parse_cell(file->fd, offset, NULL, 0, &cell_length, &unalloc))
     1668        return NULL;
     1669
     1670    if(cell_length < *name_length)
     1671    {
     1672      if(strict)
     1673        return NULL;
     1674      *name_length = cell_length & 0xFFFFFFF8;
     1675    }
     1676   
     1677    ret_val = (char*)zalloc(*name_length);
     1678    if(ret_val != NULL)
     1679    {
     1680      length = *name_length;
     1681      if((regfi_read(file->fd, (uint8*)ret_val, &length) != 0)
     1682         || length != *name_length)
    16521683      {
    1653         /* Being careful not to reject the whole key here even when
    1654          * strict and things are obviously wrong, since it appears
    1655          * they're commonly obviously wrong.
    1656          */
    1657         free(ret_val->classname);
    1658         ret_val->classname = NULL;
    1659         return ret_val;
     1684        free(ret_val);
     1685        return NULL;
    16601686      }
    16611687
    1662       ret_val->classname[ret_val->classname_length] = '\0';
    16631688      /*printf("==> cell_length=%d, classname_length=%d, max_bytes_subkeyclassname=%d\n", cell_length, ret_val->classname_length, ret_val->max_bytes_subkeyclassname);*/
    16641689    }
    16651690  }
    1666   /***/
    1667 
    16681691
    16691692  return ret_val;
    16701693}
    1671 
    16721694
    16731695
  • trunk/src/common.c

    r121 r126  
    123123 * it's length, uni_max.  Writes ASCII to the buffer ascii, whose size
    124124 * is ascii_max.  Writes at most (ascii_max-1) bytes to ascii, and null
    125  * terminates the string.  Returns the length of the string stored in
     125 * terminates the string.  Returns the length of the data written to
    126126 * ascii.  On error, returns a negative errno code.
    127127 */
    128128static int uni_to_ascii(unsigned char* uni, char* ascii,
    129                         unsigned int uni_max, unsigned int ascii_max)
     129                        uint32 uni_max, uint32 ascii_max)
    130130{
    131131  char* inbuf = (char*)uni;
     
    136136
    137137  /* Set up conversion descriptor. */
    138   conv_desc = iconv_open("US-ASCII", "UTF-16LE");
     138  conv_desc = iconv_open("US-ASCII//TRANSLIT", "UTF-16LE");
    139139
    140140  ret = iconv(conv_desc, &inbuf, &in_len, &outbuf, &out_len);
     
    147147
    148148  iconv_close(conv_desc); 
    149   return strlen(ascii);
     149  return ascii_max-out_len-1;
     150}
     151
     152
     153static char* quote_unicode(unsigned char* uni, uint32 length,
     154                           const char* special, char** error_msg)
     155{
     156  char* ret_val;
     157  char* ascii;
     158  char* tmp_err;
     159  int ret_err;
     160  *error_msg = NULL;
     161
     162  ascii = malloc(length+1);
     163  if(ascii == NULL)
     164  {
     165    *error_msg = (char*)malloc(27);
     166    if(*error_msg == NULL)
     167      return NULL;
     168    strcpy(*error_msg, "Memory allocation failure.");
     169    return NULL;
     170  }
     171 
     172  ret_err = uni_to_ascii(uni, ascii, length, length+1);
     173  if(ret_err < 0)
     174  {
     175    free(ascii);
     176    tmp_err = strerror(-ret_err);
     177    *error_msg = (char*)malloc(54+strlen(tmp_err));
     178    if(*error_msg == NULL)
     179    {
     180      free(ascii);
     181      return NULL;
     182    }
     183
     184    sprintf(*error_msg,
     185            "Unicode conversion failed with '%s'. Quoting as binary.", tmp_err);
     186    ret_val = quote_buffer(uni, length, special);
     187  }
     188  else
     189  {
     190    ret_val = quote_string(ascii, special);
     191    free(ascii);
     192  }
     193 
     194  return ret_val;
    150195}
    151196
     
    166211  char* asciip;
    167212  char* ascii;
    168   unsigned char* cur_str;
    169   char* cur_ascii;
     213  char* ascii_tmp;
    170214  char* cur_quoted;
    171   char* tmp_err;
    172   const char* str_type;
     215  char* tmp_err = NULL;
     216  const char* delim;
    173217  uint32 i;
    174218  uint32 cur_str_len;
    175   uint32 ascii_max, cur_str_max;
    176   uint32 str_rem, cur_str_rem, alen;
     219  uint32 ascii_max;
     220  uint32 str_rem, alen;
    177221  int ret_err;
    178   unsigned short num_nulls;
    179222
    180223  if(datap == NULL)
     
    194237    /* REG_LINK is a symbolic link, stored as a unicode string. */
    195238  case REG_LINK:
    196     ascii_max = sizeof(char)*(len+1);
    197     ascii = malloc(ascii_max);
    198     if(ascii == NULL)
    199       return NULL;
    200    
    201239    /* Sometimes values have binary stored in them.  If the unicode
    202240     * conversion fails, just quote it raw.
    203241     */
    204     ret_err = uni_to_ascii(datap, ascii, len, ascii_max);
    205     if(ret_err < 0)
    206     {
    207       tmp_err = strerror(-ret_err);
    208       str_type = regfi_type_val2str(type);
    209       *error_msg = (char*)malloc(65+strlen(str_type)+strlen(tmp_err)+1);
    210       if(*error_msg == NULL)
    211       {
    212         free(ascii);
    213         return NULL;
    214       }
    215       sprintf(*error_msg, "Unicode conversion failed on %s field; "
    216                "printing as binary.  Error: %s", str_type, tmp_err);
    217      
    218       cur_quoted = quote_buffer(datap, len, common_special_chars);
    219     }
    220     else
    221       cur_quoted = quote_string(ascii, common_special_chars);
    222     free(ascii);
     242    cur_quoted = quote_unicode(datap, len, common_special_chars, &tmp_err);
    223243    if(cur_quoted == NULL)
    224244    {
    225       *error_msg = (char*)malloc(27+1);
    226       if(*error_msg != NULL)
    227         strcpy(*error_msg, "Buffer could not be quoted.");
    228     }
     245      if(tmp_err == NULL && (*error_msg = (char*)malloc(49)) != NULL)
     246        strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
     247      else if((*error_msg = (char*)malloc(42+strlen(tmp_err))) != NULL)
     248      {
     249        sprintf(*error_msg, "Buffer could not be quoted due to error: %s",
     250                tmp_err);
     251        free(tmp_err);
     252      }
     253    }
     254    else if (tmp_err != NULL)
     255      *error_msg = tmp_err;
    229256    return cur_quoted;
    230257    break;
     
    264291    break;
    265292   
    266 
    267   /* XXX: this MULTI_SZ parser is pretty inefficient.  Should be
    268    *      redone with fewer malloc calls and better string concatenation.
    269    *      Also, gives lame output when "\0\0" is the string.
    270    */
    271293  case REG_MULTI_SZ:
    272294    ascii_max = sizeof(char)*(len*4+1);
    273     cur_str_max = sizeof(char)*(len+1);
    274     cur_str = malloc(cur_str_max);
    275     cur_ascii = malloc(cur_str_max);
    276     ascii = malloc(ascii_max);
    277     if(ascii == NULL || cur_str == NULL || cur_ascii == NULL)
    278       return NULL;
    279 
    280     /* Reads until it reaches 4 consecutive NULLs,
    281      * which is two nulls in unicode, or until it reaches len, or until we
    282      * run out of buffer.  The latter should never happen, but we shouldn't
    283      * trust our file to have the right lengths/delimiters.
     295    ascii_tmp = malloc(ascii_max);
     296    if(ascii_tmp == NULL)
     297      return NULL;
     298
     299    /* Attempt to convert entire string from UTF-16LE to ASCII,
     300     * then parse and quote fields individually.
     301     * If this fails, simply quote entire buffer as binary.
    284302     */
    285     asciip = ascii;
    286     num_nulls = 0;
    287     str_rem = ascii_max;
    288     cur_str_rem = cur_str_max;
    289     cur_str_len = 0;
    290 
    291     for(i=0; (i < len) && str_rem > 0; i++)
    292     {
    293       *(cur_str+cur_str_len) = *(datap+i);
    294       if(*(cur_str+cur_str_len) == 0)
    295         num_nulls++;
    296       else
    297         num_nulls = 0;
    298       cur_str_len++;
    299 
    300       if(num_nulls == 2)
    301       {
    302         ret_err = uni_to_ascii(cur_str, cur_ascii, cur_str_len-1, cur_str_max);
    303         if(ret_err < 0)
     303    ret_err = uni_to_ascii(datap, ascii_tmp, len, ascii_max);
     304    if(ret_err < 0)
     305    {
     306      tmp_err = strerror(-ret_err);
     307      *error_msg = (char*)malloc(54+strlen(tmp_err));
     308      if(*error_msg == NULL)
     309        return NULL;
     310      sprintf(*error_msg, "MULTI_SZ unicode conversion"
     311              " failed with '%s'. Quoting as binary.", tmp_err);
     312      ascii = quote_buffer(datap, len, subfield_special_chars);
     313    }
     314    else
     315    {
     316      ascii = malloc(ascii_max);
     317      if(ascii == NULL)
     318      {
     319        free(ascii_tmp);
     320        return NULL;
     321      }
     322      asciip = ascii;
     323      asciip[0] = '\0';
     324      str_rem = ascii_max;
     325      delim = "";
     326      for(i=0; i<ret_err; i+=cur_str_len+1)
     327      {
     328        cur_str_len = strlen(ascii_tmp+i);
     329        if(ascii_tmp[i] != '\0')
    304330        {
    305           /* XXX: should every sub-field error be enumerated? */
    306           if(*error_msg == NULL)
     331          cur_quoted = quote_string(ascii_tmp+i, subfield_special_chars);
     332          if(cur_quoted != NULL)
    307333          {
    308             tmp_err = strerror(-ret_err);
    309             *error_msg = (char*)malloc(90+strlen(tmp_err)+1);
    310             if(*error_msg == NULL)
    311             {
    312               free(cur_str);
    313               free(cur_ascii);
    314               free(ascii);
    315               return NULL;
    316             }
    317             sprintf(*error_msg, "Unicode conversion failed on at least one "
    318                     "MULTI_SZ sub-field; printing as binary.  Error: %s",
    319                     tmp_err);
     334            alen = snprintf(asciip, str_rem, "%s%s", delim, cur_quoted);
     335            asciip += alen;
     336            str_rem -= alen;
     337            free(cur_quoted);
    320338          }
    321           cur_quoted = quote_buffer(cur_str, cur_str_len-1,
    322                                     subfield_special_chars);
    323339        }
    324         else
    325           cur_quoted = quote_string(cur_ascii, subfield_special_chars);
    326 
    327         alen = snprintf(asciip, str_rem, "%s", cur_quoted);
    328         asciip += alen;
    329         str_rem -= alen;
    330         free(cur_quoted);
    331 
    332         if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
    333           break;
    334         else
    335         {
    336           if(str_rem > 0)
    337           {
    338             asciip[0] = '|';
    339             asciip[1] = '\0';
    340             asciip++;
    341             str_rem--;
    342           }
    343           memset(cur_str, 0, cur_str_max);
    344           cur_str_len = 0;
    345           num_nulls = 0;
    346           /* To eliminate leading nulls in subsequent strings. */
    347           i++;
    348         }
    349       }
    350     }
    351     *asciip = 0;
    352     free(cur_str);
    353     free(cur_ascii);
     340        delim = "|";
     341      }
     342    }
     343
     344    free(ascii_tmp);
    354345    return ascii;
    355346    break;
     
    357348  /* XXX: Dont know what to do with these yet, just print as binary... */
    358349  default:
    359     /* XXX: It would be really nice if this message somehow included the
    360      *      name of the current value we're having trouble with, since
    361      *      stderr/stdout don't always sync nicely.
    362      */
    363     fprintf(stderr, "WARNING: Unrecognized registry data type (0x%.8X); quoting as binary.\n", type);
     350    *error_msg = (char*)malloc(65);
     351    if(*error_msg == NULL)
     352      return NULL;
     353    sprintf(*error_msg,
     354            "Unrecognized registry data type (0x%.8X); quoting as binary.",
     355            type);
    364356   
    365357  case REG_NONE:
  • trunk/src/reglookup.c

    r125 r126  
    9797              "Returned error: %s\n", prefix, quoted_name, conv_error);
    9898  }
    99   /* XXX: should these always be printed? */
    10099  else if(conv_error != NULL && print_verbose)
    101100    fprintf(stderr, "VERBOSE: While quoting value for '%s/%s', "
     
    296295  char* dacl = NULL;
    297296  char* quoted_classname;
     297  char* error_msg = NULL;
    298298  char mtime[20];
    299299  time_t tmp_time[1];
     
    322322
    323323    if(k->classname != NULL)
    324       quoted_classname = quote_string(k->classname, key_special_chars);
     324    {
     325      quoted_classname = quote_unicode((uint8*)k->classname, k->classname_length,
     326                                       key_special_chars, &error_msg);
     327      if(quoted_classname == NULL)
     328      {
     329        if(error_msg == NULL)
     330          fprintf(stderr, "ERROR: Could not quote classname"
     331                  " for key '%s' due to unknown error.\n", full_path);
     332        else
     333        {
     334          fprintf(stderr, "ERROR: Could not quote classname"
     335                  " for key '%s' due to error: %s\n", full_path, error_msg);
     336          free(error_msg);
     337        }
     338      }
     339      else if (error_msg != NULL)
     340      {
     341        if(print_verbose)
     342          fprintf(stderr, "WARNING: While converting classname"
     343                  " for key '%s': %s.\n", full_path, error_msg);
     344        free(error_msg);
     345      }
     346    }
    325347    else
    326348      quoted_classname = empty_str;
Note: See TracChangeset for help on using the changeset viewer.