Ejemplo n.º 1
0
SSLSock
SSL_New(int fd,                       // IN
        Bool closeFdOnShutdown)       // IN
{
   SSLSock sslSock;

   sslSock = calloc(1, sizeof *sslSock);
   ASSERT_MEM_ALLOC(sslSock);
   sslSock->fd = fd;
   sslSock->closeFdOnShutdown = closeFdOnShutdown;

   return sslSock;
}
Ejemplo n.º 2
0
static int
SNEForEachCallback(const char *key,     // IN: environment variable
                   void *value,         // IN: environment value
                   void *clientData)    // IN/OUT: DynBuf container (SNEBufs)
{
   DynBuf *nativeEnvironStrings = ((SNEBufs *)clientData)->nativeEnvironStrings;
   DynBuf *nativeEnvironOffsets = ((SNEBufs *)clientData)->nativeEnvironOffsets;
   size_t itemSize;
   char *itemBuf;
   off_t itemOffset;

   /*
    * A NULL value indicates that this variable is not to be set.
    */
   if (value == NULL) {
      return 0;
   }

   /* Determine the length of the new string inc. '=' delimiter and NUL. */
   itemSize = strlen(key) + strlen(value) + sizeof "=";
   itemBuf = Util_SafeMalloc(itemSize);

   /* Create new "key=value" string. */
   snprintf(itemBuf, itemSize, "%s=%s", key, (char *)value);

   ASSERT_MEM_ALLOC(DynBuf_AppendString(nativeEnvironStrings, itemBuf));

   /*
    * Get the relative offset of our newly added string (relative to the DynBuf's base
    * address), and then append that to nativeEnvironOffsets.
    */
   itemOffset = DynBuf_GetSize(nativeEnvironStrings) - itemSize;
   ASSERT_MEM_ALLOC(DynBuf_Append(nativeEnvironOffsets, &itemOffset, sizeof itemOffset));

   free(itemBuf);

   return 0;
}
void *
UnicodeGetAllocBytesInternal(ConstUnicode ustr,       // IN
                             StringEncoding encoding, // IN
                             ssize_t lengthInBytes,   // IN
                             size_t *retLength)       // OUT: optional
{
   const char *utf8Str = ustr;
   char *result = NULL;

   ASSERT(ustr != NULL);

   encoding = Unicode_ResolveEncoding(encoding);

   if (lengthInBytes == -1) {
      lengthInBytes = Unicode_LengthInBytes(ustr, STRING_ENCODING_UTF8);
   }

   switch (encoding) {
   case STRING_ENCODING_US_ASCII:
      if (!UnicodeSanityCheck(utf8Str, lengthInBytes, encoding)) {
	 break;
      }
      // fall through
   case STRING_ENCODING_UTF8:
      result = Util_SafeMalloc(lengthInBytes + 1);
      memcpy(result, utf8Str, lengthInBytes + 1);
      if (retLength != NULL) {
	 *retLength = lengthInBytes;
      }
      break;

   case STRING_ENCODING_UTF16_LE:
      if (!CodeSet_Utf8ToUtf16le(utf8Str, lengthInBytes, &result, retLength)) {
	 // input should be valid UTF-8, no conversion error possible
	 ASSERT_MEM_ALLOC(FALSE);
      }
      break;

   default:
      if (!CodeSet_GenericToGeneric("UTF-8", utf8Str, lengthInBytes,
				    Unicode_EncodingEnumToName(encoding),
				    CSGTG_NORMAL,
				    &result, retLength)) {
	 // XXX can't distinguish error cause
	 ASSERT(result == NULL);
      }
   }

   return result;
}
Ejemplo n.º 4
0
static void
MsgSetCatalog(const char *domain,
              MsgCatalog *catalog)
{
   MsgState *state = MsgGetState();

   ASSERT(domain);

   if (state->domains == NULL) {
      state->domains = HashTable_Alloc(8, HASH_STRING_KEY | HASH_FLAG_COPYKEY,
                                       (HashTableFreeEntryFn) MsgCatalogFree);
      ASSERT_MEM_ALLOC(state->domains);
   }

   HashTable_ReplaceOrInsert(state->domains, domain, catalog);
}
Ejemplo n.º 5
0
static gboolean
RpcChannelReset(RpcInData *data)
{
   gchar *msg;
   RpcChannelInt *chan = data->clientData;

   if (chan->resetCheck == NULL) {
      chan->resetCheck = g_idle_source_new();
      g_source_set_priority(chan->resetCheck, G_PRIORITY_HIGH);
      g_source_set_callback(chan->resetCheck, RpcChannelCheckReset, chan, NULL);
      g_source_attach(chan->resetCheck, chan->mainCtx);
   }

   msg = Str_Asprintf(NULL, "ATR %s", chan->appName);
   ASSERT_MEM_ALLOC(msg);
   return RPCIN_SETRETVALSF(data, msg, TRUE);
}
Bool
Unicode_CopyBytes(void *destBuffer,        // OUT
                  ConstUnicode srcBuffer,  // IN
                  size_t maxLengthInBytes, // IN
                  size_t *retLength,       // OUT
                  StringEncoding encoding) // IN
{
   const char *utf8Str = (const char *)srcBuffer;
   Bool success = FALSE;
   size_t copyBytes = 0;

   encoding = Unicode_ResolveEncoding(encoding);

   switch (encoding) {
   case STRING_ENCODING_US_ASCII:
      if (!UnicodeSanityCheck(utf8Str, -1, encoding)) {
	 break;
      }
      // fall through
   case STRING_ENCODING_UTF8:
      {
         size_t len = strlen(utf8Str);
         copyBytes = MIN(len, maxLengthInBytes - 1);
         memcpy(destBuffer, utf8Str, copyBytes);

         /*
          * If we truncated, force a null termination in a UTF-8 safe
          * manner.
          */
         if (copyBytes >= len) {
	    success = TRUE;
	 } else {
            if (encoding == STRING_ENCODING_UTF8) {
               copyBytes =
                  CodeSet_Utf8FindCodePointBoundary(destBuffer, copyBytes);
            }
         }

         ((char*)destBuffer)[copyBytes] = '\0';
      }
      break;
   case STRING_ENCODING_UTF16_LE:
      {
         char *utf16Buf;
         size_t utf16BufLen;

         if (!CodeSet_Utf8ToUtf16le(utf8Str,
                                    strlen(utf8Str),
                                    &utf16Buf,
                                    &utf16BufLen)) {
	    // input should be valid UTF-8, no conversion error possible
	    ASSERT_MEM_ALLOC(FALSE);
            break;
         }
         copyBytes = MIN(utf16BufLen, maxLengthInBytes - 2);
         memcpy(destBuffer, utf16Buf, copyBytes);
         copyBytes = CodeSet_Utf16FindCodePointBoundary(destBuffer, copyBytes);
         ((utf16_t*)destBuffer)[copyBytes / 2] = 0;
         free(utf16Buf);

         if (copyBytes >= utf16BufLen) {
            success = TRUE;
         }

         break;
      }
   default:
      {
         char *currentBuf;
         size_t currentBufSize;

	 if (!CodeSet_GenericToGeneric("UTF-8", utf8Str, strlen(utf8Str),
				       Unicode_EncodingEnumToName(encoding),
				       CSGTG_NORMAL,
				       &currentBuf, &currentBufSize)) {
	    // XXX can't distinguish error cause
	    break;
	 }
         copyBytes = MIN(currentBufSize, maxLengthInBytes - 1);
         memcpy(destBuffer, currentBuf, copyBytes);
         free(currentBuf);

         /* 
          * XXX this isn't quite correct, we still need to truncate on
          * a code point boundary, based on the current encoding type,
          * rather than just null terminate blindly.
          */

         ((char*)destBuffer)[copyBytes] = 0;

         if (copyBytes >= currentBufSize) {
            success = TRUE;
         }
      }
      break;
   }

   if (retLength) {
      *retLength = copyBytes;
   }
   return success;
}
static Bool
RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
{
   GPtrArray *routes = NULL;
   guint i;
   Bool ret = FALSE;

   if ((routes = SlashProcNet_GetRoute6()) == NULL) {
      return FALSE;
   }

   for (i = 0; i < routes->len; i++) {
      struct sockaddr_storage ss;
      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
      struct in6_rtmsg *in6_rtmsg;
      InetCidrRouteEntry *icre;
      uint32_t ifIndex = -1;

      /* Check to see if we're going above our limit. See bug 605821. */
      if (nicInfo->routes.routes_len == NICINFO_MAX_ROUTES) {
         g_message("%s: route limit (%d) reached, skipping overflow.",
                   __FUNCTION__, NICINFO_MAX_ROUTES);
         break;
      }

      in6_rtmsg = g_ptr_array_index(routes, i);

      if ((in6_rtmsg->rtmsg_flags & RTF_UP) == 0 ||
          !GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex,
                                      &ifIndex)) {
         continue;
      }

      icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
      ASSERT_MEM_ALLOC(icre);

      /*
       * Destination.
       */
      sin6->sin6_family = AF_INET6;
      sin6->sin6_addr = in6_rtmsg->rtmsg_dst;
      GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6,
                                        &icre->inetCidrRouteDest);

      icre->inetCidrRoutePfxLen = in6_rtmsg->rtmsg_dst_len;

      /*
       * Next hop.
       */
      if (in6_rtmsg->rtmsg_flags & RTF_GATEWAY) {
         TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
         sin6->sin6_addr = in6_rtmsg->rtmsg_gateway;
         GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
         icre->inetCidrRouteNextHop = ip;
      }

      /*
       * Interface, metric.
       */
      icre->inetCidrRouteIfIndex = ifIndex;
      icre->inetCidrRouteMetric = in6_rtmsg->rtmsg_metric;
   }

   ret = TRUE;

   SlashProcNet_FreeRoute6(routes);
   return ret;
}
static Bool
RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
{
   GPtrArray *routes = NULL;
   guint i;
   Bool ret = FALSE;

   if ((routes = SlashProcNet_GetRoute()) == NULL) {
      return FALSE;
   }

   for (i = 0; i < routes->len; i++) {
      struct rtentry *rtentry;
      struct sockaddr_in *sin_dst;
      struct sockaddr_in *sin_gateway;
      struct sockaddr_in *sin_genmask;
      InetCidrRouteEntry *icre;
      uint32_t ifIndex;

      /* Check to see if we're going above our limit. See bug 605821. */
      if (nicInfo->routes.routes_len == NICINFO_MAX_ROUTES) {
         g_message("%s: route limit (%d) reached, skipping overflow.",
                   __FUNCTION__, NICINFO_MAX_ROUTES);
         break;
      }

      rtentry = g_ptr_array_index(routes, i);

      if ((rtentry->rt_flags & RTF_UP) == 0 ||
          !GuestInfoGetNicInfoIfIndex(nicInfo,
                                      if_nametoindex(rtentry->rt_dev),
                                      &ifIndex)) {
         continue;
      }

      icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
      ASSERT_MEM_ALLOC(icre);

      sin_dst = (struct sockaddr_in *)&rtentry->rt_dst;
      sin_gateway = (struct sockaddr_in *)&rtentry->rt_gateway;
      sin_genmask = (struct sockaddr_in *)&rtentry->rt_genmask;

      GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_dst,
                                        &icre->inetCidrRouteDest);

      addr_stob((struct sockaddr *)sin_genmask,
                (uint16_t *)&icre->inetCidrRoutePfxLen);

      /*
       * Gateways are optional (ex: one can bind a route to an interface w/o
       * specifying a next hop address).
       */
      if (rtentry->rt_flags & RTF_GATEWAY) {
         TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
         GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_gateway, ip);
         icre->inetCidrRouteNextHop = ip;
      }

      /*
       * Interface, metric.
       */
      icre->inetCidrRouteIfIndex = ifIndex;
      icre->inetCidrRouteMetric = rtentry->rt_metric;
   }

   ret = TRUE;

   SlashProcNet_FreeRoute(routes);
   return ret;
}
static void
RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN
{
   int i;

#if defined RESOLVER_IPV6_GETSERVERS
   {
      union res_sockaddr_union *ns;
      ns = Util_SafeCalloc(_res.nscount, sizeof *ns);
      if (res_getservers(&_res, ns, _res.nscount) != _res.nscount) {
         g_warning("%s: res_getservers failed.\n", __func__);
         return;
      }
      for (i = 0; i < _res.nscount; i++) {
         struct sockaddr *sa = (struct sockaddr *)&ns[i];
         if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
            TypedIpAddress *ip;

            /* Check to see if we're going above our limit. See bug 605821. */
            if (dnsConfigInfo->serverList.serverList_len == DNSINFO_MAX_SERVERS) {
               g_message("%s: dns server limit (%d) reached, skipping overflow.",
                         __FUNCTION__, DNSINFO_MAX_SERVERS);
               break;
            }

            ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
            ASSERT_MEM_ALLOC(ip);
            GuestInfoSockaddrToTypedIpAddress(sa, ip);
         }
      }
   }
#else                                   // if defined RESOLVER_IPV6_GETSERVERS
   {
      /*
       * Name servers (IPv4).
       */
      for (i = 0; i < MAXNS; i++) {
         struct sockaddr_in *sin = &_res.nsaddr_list[i];
         if (sin->sin_family == AF_INET) {
            TypedIpAddress *ip;

            /* Check to see if we're going above our limit. See bug 605821. */
            if (dnsConfigInfo->serverList.serverList_len == DNSINFO_MAX_SERVERS) {
               g_message("%s: dns server limit (%d) reached, skipping overflow.",
                         __FUNCTION__, DNSINFO_MAX_SERVERS);
               break;
            }

            ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
            ASSERT_MEM_ALLOC(ip);
            GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin, ip);
         }
      }
#   if defined RESOLVER_IPV6_EXT
      /*
       * Name servers (IPv6).
       */
      for (i = 0; i < MAXNS; i++) {
         struct sockaddr_in6 *sin6 = _res._u._ext.nsaddrs[i];
         if (sin6) {
            TypedIpAddress *ip;

            /* Check to see if we're going above our limit. See bug 605821. */
            if (dnsConfigInfo->serverList.serverList_len == DNSINFO_MAX_SERVERS) {
               g_message("%s: dns server limit (%d) reached, skipping overflow.",
                         __FUNCTION__, DNSINFO_MAX_SERVERS);
               break;
            }

            ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
            ASSERT_MEM_ALLOC(ip);
            GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
         }
      }
#   endif                               //    if defined RESOLVER_IPV6_EXT
   }
#endif                                  // if !defined RESOLVER_IPV6_GETSERVERS
}
static Bool
RecordResolverInfo(NicInfoV3 *nicInfo)  // OUT
{
   DnsConfigInfo *dnsConfigInfo = NULL;
   char namebuf[DNSINFO_MAX_ADDRLEN + 1];
   char **s;

   if (res_init() == -1) {
      return FALSE;
   }

   dnsConfigInfo = Util_SafeCalloc(1, sizeof *dnsConfigInfo);

   /*
    * Copy in the host name. not this
    */
   if (!GuestInfoGetFqdn(sizeof namebuf, namebuf)) {
      goto fail;
   }
   dnsConfigInfo->hostName =
      Util_SafeCalloc(1, sizeof *dnsConfigInfo->hostName);
   *dnsConfigInfo->hostName = Util_SafeStrdup(namebuf);

   /*
    * Repeat with the domain name. not this
    */
   dnsConfigInfo->domainName =
      Util_SafeCalloc(1, sizeof *dnsConfigInfo->domainName);
   *dnsConfigInfo->domainName = Util_SafeStrdup(_res.defdname);

   /*
    * Name servers.
    */
   RecordResolverNS(dnsConfigInfo);

   /*
    * Search suffixes.
    */
   for (s = _res.dnsrch; *s; s++) {
      DnsHostname *suffix;

      /* Check to see if we're going above our limit. See bug 605821. */
      if (dnsConfigInfo->searchSuffixes.searchSuffixes_len == DNSINFO_MAX_SUFFIXES) {
         g_message("%s: dns search suffix limit (%d) reached, skipping overflow.",
                   __FUNCTION__, DNSINFO_MAX_SUFFIXES);
         break;
      }

      suffix = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, searchSuffixes, 1);
      ASSERT_MEM_ALLOC(suffix);
      *suffix = Util_SafeStrdup("test suffix");
   }

   /*
    * "Commit" dnsConfigInfo to nicInfo.
    */
   nicInfo->dnsConfigInfo = dnsConfigInfo;

   return TRUE;

fail:
   VMX_XDR_FREE(xdr_DnsConfigInfo, dnsConfigInfo);
   free(dnsConfigInfo);
   return FALSE;
}
Ejemplo n.º 11
0
static MsgCatalog *
MsgLoadCatalog(const char *path)
{
   gchar *localPath;
   GError *err = NULL;
   GIOChannel *stream;
   gboolean error = FALSE;
   MsgCatalog *catalog = NULL;
   HashTable *dict;

   ASSERT(path != NULL);
   localPath = VMTOOLS_GET_FILENAME_LOCAL(path, NULL);
   ASSERT(localPath != NULL);

   stream = g_io_channel_new_file(localPath, "r", &err);
   VMTOOLS_RELEASE_FILENAME_LOCAL(localPath);

   if (err != NULL) {
      g_debug("Unable to open '%s': %s\n", path, err->message);
      g_clear_error(&err);
      return NULL;
   }

   dict = HashTable_Alloc(8, HASH_STRING_KEY | HASH_FLAG_COPYKEY, g_free);
   ASSERT_MEM_ALLOC(dict);

   for (;;) {
      gboolean eof = FALSE;
      char *name = NULL;
      char *value = NULL;
      gchar *line;

      /* Read the next key / value pair. */
      for (;;) {
         gsize i;
         gsize len;
         gsize term;
         char *unused = NULL;
         gboolean cont = FALSE;

         g_io_channel_read_line(stream, &line, &len, &term, &err);

         if (err != NULL) {
            g_warning("Unable to read a line from '%s': %s\n",
                      path, err->message);
            g_clear_error(&err);
            error = TRUE;
            g_free(line);
            break;
         }

         if (line == NULL) {
            eof = TRUE;
            break;
         }

         /*
          * Fix the line break to always be Unix-style, to make lib/dict
          * happy.
          */
         if (line[term] == '\r') {
            line[term] = '\n';
            if (len > term) {
               line[term + 1] = '\0';
            }
         }

         /*
          * If currently name is not NULL, then check if this is a continuation
          * line and, if it is, just append the contents to the current value.
          */
         if (term > 0 && name != NULL && line[term - 1] == '"') {
            for (i = 0; i < len; i++) {
               if (line[i] == '"') {
                  /* OK, looks like a continuation line. */
                  char *tmp;
                  char *unescaped;

                  line[term - 1] = '\0';
                  unescaped = Escape_Undo('|', line + i + 1, len - i, NULL);
                  tmp = Str_Asprintf(NULL, "%s%s", value, unescaped);
                  free(unescaped);
                  free(value);
                  value = tmp;
                  cont = TRUE;
                  break;
               } else if (line[i] != ' ' && line[i] != '\t') {
                  break;
               }
            }
         }

         /*
          * If not a continuation line and we have a name, break out of the
          * inner loop to update the dictionaty.
          */
         if (!cont && name != NULL) {
            g_free(line);
            break;
         }

         /*
          * Finally, try to parse the string using the dictionary library.
          */
         if (!cont && DictLL_UnmarshalLine(line, len, &unused, &name, &value) == NULL) {
            g_warning("Couldn't parse line from catalog: %s", line);
            error = TRUE;
         }

         g_free(line);
         free(unused);
      }

      if (error) {
         break;
      }

      if (name != NULL) {
         ASSERT(value);

         if (!Unicode_IsBufferValid(name, strlen(name) + 1, STRING_ENCODING_UTF8) ||
             !Unicode_IsBufferValid(value, strlen(value) + 1, STRING_ENCODING_UTF8)) {
            g_warning("Invalid UTF-8 string in message catalog (key = %s)\n", name);
            error = TRUE;
            break;
         }

         MsgUnescape(value);
         HashTable_ReplaceOrInsert(dict, name, g_strdup(value));
         free(name);
         free(value);
         name = NULL;
         value = NULL;
      }

      if (eof) {
         break;
      }
   }

   g_io_channel_unref(stream);

   if (error) {
      HashTable_Free(dict);
      dict = NULL;
   } else {
      catalog = g_new0(MsgCatalog, 1);
      catalog->utf8 = dict;
   }

   return catalog;
}
Ejemplo n.º 12
0
static const void *
MsgGetString(const char *domain,
             const char *msgid,
             StringEncoding encoding)
{
   const char *idp;
   const char *strp;
   char idBuf[MSG_MAX_ID];
   size_t len;
   HashTable *source = NULL;
   MsgCatalog *catalog;
   MsgState *state = MsgGetState();

   /* All message strings must be prefixed by the message ID. */
   ASSERT(domain != NULL);
   ASSERT(msgid != NULL);
   ASSERT(MsgHasMsgID(msgid));
#if defined(_WIN32)
   ASSERT(encoding == STRING_ENCODING_UTF8 ||
          encoding == STRING_ENCODING_UTF16_LE);
#else
   ASSERT(encoding == STRING_ENCODING_UTF8);
#endif

   /*
    * Find the beginning of the ID (idp) and the string (strp).
    * The string should have the correct MSG_MAGIC(...)... form.
    */

   idp = msgid + MSG_MAGIC_LEN + 1;
   strp = strchr(idp, ')') + 1;

   len = strp - idp - 1;
   ASSERT_NOT_IMPLEMENTED(len <= MSG_MAX_ID - 1);
   memcpy(idBuf, idp, len);
   idBuf[len] = '\0';

   /*
    * This lock is pretty coarse-grained, but a lot of the code below just runs
    * in exceptional situations, so it should be OK.
    */
   g_static_mutex_lock(&state->lock);

   catalog = MsgGetCatalog(domain);
   if (catalog != NULL) {
      switch (encoding) {
      case STRING_ENCODING_UTF8:
         source = catalog->utf8;
         break;

#if defined(_WIN32)
      case STRING_ENCODING_UTF16_LE:
         source = catalog->utf16;
         break;
#endif

      default:
         NOT_IMPLEMENTED();
      }
   }

#if defined(_WIN32)
   /*
    * Lazily create the local and UTF-16 dictionaries. This may require also
    * registering an empty message catalog for the desired domain.
    */
   if (source == NULL && encoding == STRING_ENCODING_UTF16_LE) {
      catalog = MsgGetCatalog(domain);
      if (catalog == NULL) {
         if (domain == NULL) {
            g_error("Application did not set up a default text domain.");
         }
         catalog = g_new0(MsgCatalog, 1);
         MsgSetCatalog(domain, catalog);
      }

      catalog->utf16 = HashTable_Alloc(8, HASH_STRING_KEY, g_free);
      ASSERT_MEM_ALLOC(catalog->utf16);
      source = catalog->utf16;
   }
#endif

   /*
    * Look up the localized string, converting to requested encoding as needed.
    */

   if (source != NULL) {
      const void *retval = NULL;

      if (HashTable_Lookup(source, idBuf, (void **) &retval)) {
         strp = retval;
#if defined(_WIN32)
      } else if (encoding == STRING_ENCODING_UTF16_LE) {
         gchar *converted;
         Bool success;

         /*
          * Look up the string in UTF-8, convert it and cache it.
          */
         retval = MsgGetString(domain, msgid, STRING_ENCODING_UTF8);
         ASSERT(retval);

         converted = (gchar *) g_utf8_to_utf16(retval, -1, NULL, NULL, NULL);
         ASSERT(converted != NULL);

         success = HashTable_Insert(source, idBuf, converted);
         ASSERT(success);
         strp = converted;
#endif
      }
   }

   g_static_mutex_unlock(&state->lock);

   return strp;
}