Example #1
0
svn_error_t *
svn_repos__validate_prop(const char *name,
                         const svn_string_t *value,
                         apr_pool_t *pool)
{
    svn_prop_kind_t kind = svn_property_kind2(name);

    /* Allow deleting any property, even a property we don't allow to set. */
    if (value == NULL)
        return SVN_NO_ERROR;

    /* Disallow setting non-regular properties. */
    if (kind != svn_prop_regular_kind)
        return svn_error_createf
               (SVN_ERR_REPOS_BAD_ARGS, NULL,
                _("Storage of non-regular property '%s' is disallowed through the "
                  "repository interface, and could indicate a bug in your client"),
                name);

    /* Validate "svn:" properties. */
    if (svn_prop_is_svn_prop(name) && value != NULL)
    {
        /* Validate that translated props (e.g., svn:log) are UTF-8 with
         * LF line endings. */
        if (svn_prop_needs_translation(name))
        {
            if (!svn_utf__is_valid(value->data, value->len))
            {
                return svn_error_createf
                       (SVN_ERR_BAD_PROPERTY_VALUE, NULL,
                        _("Cannot accept '%s' property because it is not encoded in "
                          "UTF-8"), name);
            }

            /* Disallow inconsistent line ending style, by simply looking for
             * carriage return characters ('\r'). */
            if (strchr(value->data, '\r') != NULL)
            {
                return svn_error_createf
                       (SVN_ERR_BAD_PROPERTY_VALUE, NULL,
                        _("Cannot accept non-LF line endings in '%s' property"),
                        name);
            }
        }

        /* "svn:date" should be a valid date. */
        if (strcmp(name, SVN_PROP_REVISION_DATE) == 0)
        {
            apr_time_t temp;
            svn_error_t *err;

            err = svn_time_from_cstring(&temp, value->data, pool);
            if (err)
                return svn_error_create(SVN_ERR_BAD_PROPERTY_VALUE,
                                        err, NULL);
        }
    }

    return SVN_NO_ERROR;
}
Example #2
0
svn_boolean_t
svn_utf__cstring_is_valid(const char *data)
{
  if (!data)
    return FALSE;

  return svn_utf__is_valid(data, strlen(data));
}
Example #3
0
/* Make a best effort to convert a X.509 name to a UTF-8 encoded
 * string and return it.  If we can't properly convert just do a
 * fuzzy conversion so we have something to display. */
static const char *
x509name_to_utf8_string(const x509_name *name, apr_pool_t *result_pool)
{
  const svn_string_t *src_string;
  const svn_string_t *utf8_string;
  svn_error_t *err;

  src_string = svn_string_ncreate((const char *)name->val.p,
                                  name->val.len,
                                  result_pool);
  switch (name->val.tag)
    {
    case ASN1_UTF8_STRING:
      if (svn_utf__is_valid(src_string->data, src_string->len))
        return nul_escape(src_string, result_pool);
      else
        /* not a valid UTF-8 string, who knows what it is,
         * so run it through the fuzzy_escape code.  */
        return fuzzy_escape(src_string, result_pool);
      break;

      /* Both BMP and UNIVERSAL should always be in Big Endian (aka
       * network byte order).  But rumor has it that there are certs
       * out there with other endianess and even Byte Order Marks.
       * If we actually run into these, we might need to do something
       * about it. */

    case ASN1_BMP_STRING:
      if (0 != src_string->len % sizeof(apr_uint16_t))
          return fuzzy_escape(src_string, result_pool);
      err = svn_utf__utf16_to_utf8(&utf8_string,
                                   (const void*)(src_string->data),
                                   src_string->len / sizeof(apr_uint16_t),
                                   TRUE, result_pool, result_pool);
      break;

    case ASN1_UNIVERSAL_STRING:
      if (0 != src_string->len % sizeof(apr_int32_t))
          return fuzzy_escape(src_string, result_pool);
      err = svn_utf__utf32_to_utf8(&utf8_string,
                                   (const void*)(src_string->data),
                                   src_string->len / sizeof(apr_int32_t),
                                   TRUE, result_pool, result_pool);
      break;

      /* Despite what all the IETF, ISO, ITU bits say everything out
       * on the Internet that I can find treats this as ISO-8859-1.
       * Even the name is misleading, it's not actually T.61.  All the
       * gory details can be found in the Character Sets section of:
       * https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
       */
    case ASN1_T61_STRING:
      err = latin1_to_utf8(&utf8_string, src_string, result_pool);
      break;

      /* This leaves two types out there in the wild.  PrintableString,
       * which is just a subset of ASCII and IA5 which is ASCII (though
       * 0x24 '$' and 0x23 '#' may be defined with differnet symbols
       * depending on the location, in practice it seems everyone just
       * treats it as ASCII).  Since these are just ASCII run through
       * the fuzzy_escape code to deal with anything that isn't actually
       * ASCII.  There shouldn't be any other types here but if we find
       * a cert with some other encoding, the best we can do is the
       * fuzzy_escape().  Note: Technically IA5 isn't valid in this
       * context, however in the real world it may pop up. */
    default:
      return fuzzy_escape(src_string, result_pool);
    }

  if (err)
    {
      svn_error_clear(err);
      return fuzzy_escape(src_string, result_pool);
    }

  return nul_escape(utf8_string, result_pool);
}
Example #4
0
/* Explicit tests of various valid/invalid sequences */
static svn_error_t *
utf_validate(apr_pool_t *pool)
{
  struct data {
    svn_boolean_t valid;
    char string[20];
  } tests[] = {
    {TRUE,  {'a', 'b', '\0'}},
    {FALSE, {'a', 'b', '\x80', '\0'}},

    {FALSE, {'a', 'b', '\xC0',                                   '\0'}},
    {FALSE, {'a', 'b', '\xC0', '\x81',                 'x', 'y', '\0'}},

    {TRUE,  {'a', 'b', '\xC5', '\x81',                 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xC5', '\xC0',                 'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xE0',                                   '\0'}},
    {FALSE, {'a', 'b', '\xE0',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xE0', '\xA0',                           '\0'}},
    {FALSE, {'a', 'b', '\xE0', '\xA0',                 'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xE0', '\xA0', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xE0', '\x9F', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xE0', '\xCF', '\x81',         'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xE5',                                   '\0'}},
    {FALSE, {'a', 'b', '\xE5',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xE5', '\x81',                           '\0'}},
    {FALSE, {'a', 'b', '\xE5', '\x81',                 'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xE5', '\x81', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xE5', '\xE1', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xE5', '\x81', '\xE1',         'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xED',                                   '\0'}},
    {FALSE, {'a', 'b', '\xED',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xED', '\x81',                           '\0'}},
    {FALSE, {'a', 'b', '\xED', '\x81',                 'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xED', '\x81', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xED', '\xA0', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xED', '\x81', '\xC1',         'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xEE',                                   '\0'}},
    {FALSE, {'a', 'b', '\xEE',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xEE', '\x81',                           '\0'}},
    {FALSE, {'a', 'b', '\xEE', '\x81',                 'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xEE', '\x81', '\x81',         'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xEE', '\xA0', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xEE', '\xC0', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xEE', '\x81', '\xC1',         'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xF0',                                   '\0'}},
    {FALSE, {'a', 'b', '\xF0',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\x91',                           '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\x91',                 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\x91', '\x81',                   '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\x91', '\x81',         'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xF0', '\x91', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\x81', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\xC1', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\x91', '\xC1', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF0', '\x91', '\x81', '\xC1', 'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xF2',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF2', '\x91',                 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF2', '\x91', '\x81',         'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xF2', '\x91', '\x81', '\x81', 'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xF2', '\x81', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF2', '\xC1', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF2', '\x91', '\xC1', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF2', '\x91', '\x81', '\xC1', 'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xF4',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\x91',                 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\x91', '\x81',         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\x91', '\x81', '\x81', 'x', 'y', '\0'}},
    {TRUE,  {'a', 'b', '\xF4', '\x81', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\xC1', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\x91', '\xC1', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\x91', '\x81', '\xC1', 'x', 'y', '\0'}},

    {FALSE, {'a', 'b', '\xF5',                         'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF5', '\x81',                 'x', 'y', '\0'}},

    {TRUE,  {'a', 'b', '\xF4', '\x81', '\x81', '\x81', 'x', 'y',
             'a', 'b', '\xF2', '\x91', '\x81', '\x81', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\x81', '\x81', '\x81', 'x', 'y',
             'a', 'b', '\xF2', '\x91', '\x81', '\xC1', 'x', 'y', '\0'}},
    {FALSE, {'a', 'b', '\xF4', '\x81', '\x81', '\x81', 'x', 'y',
             'a', 'b', '\xF2', '\x91', '\x81',         'x', 'y', '\0'}},

    {-1},
  };
  int i = 0;

  while (tests[i].valid != -1)
    {
      const char *last = svn_utf__last_valid(tests[i].string,
                                             strlen(tests[i].string));
      apr_size_t len = strlen(tests[i].string);

      if ((svn_utf__cstring_is_valid(tests[i].string) != tests[i].valid)
          ||
          (svn_utf__is_valid(tests[i].string, len) != tests[i].valid))
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "is_valid test %d failed", i);

      if (!svn_utf__is_valid(tests[i].string, last - tests[i].string)
          ||
          (tests[i].valid && *last))
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "last_valid test %d failed", i);

      ++i;
    }

  return SVN_NO_ERROR;
}