Skip to content

Commit

Permalink
Add openconnect_utf8_to_legacy() helper function for charset conversion
Browse files Browse the repository at this point in the history
In some cases, the library itself really is going to have to know about
legacy non-UTF8 locales — when opening files or setting environment
variables, for example.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Jul 31, 2014
1 parent b504080 commit c071217
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 2 deletions.
6 changes: 5 additions & 1 deletion Makefile.am
Expand Up @@ -25,6 +25,7 @@ lib_srcs_openssl = openssl.c
lib_srcs_win32 = tun-win32.c sspi.c
lib_srcs_posix = tun.c
lib_srcs_gssapi = gssapi.c
lib_srcs_iconv = iconv.c

POTFILES = $(openconnect_SOURCES) $(lib_srcs_openssl) $(lib_srcs_gnutls) \
$(library_srcs) $(lib_srcs_win32) $(lib_srcs_posix) $(lib_srcs_gssapi)
Expand All @@ -38,6 +39,9 @@ endif
if OPENCONNECT_OPENSSL
library_srcs += $(lib_srcs_openssl)
endif
if OPENCONNECT_ICONV
library_srcs += $(lib_srcs_iconv)
endif
if OPENCONNECT_WIN32
library_srcs += $(lib_srcs_win32)
else
Expand All @@ -46,7 +50,7 @@ endif

libopenconnect_la_SOURCES = version.c $(library_srcs)
libopenconnect_la_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(P11KIT_CFLAGS) $(TSS_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) $(GSSAPI_CFLAGS)
libopenconnect_la_LIBADD = $(SSL_LIBS) $(DTLS_SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(ZLIB_LIBS) $(LIBINTL) $(P11KIT_LIBS) $(TSS_LIBS) $(LIBSTOKEN_LIBS) $(LIBOATH_LIBS) $(GSSAPI_LIBS)
libopenconnect_la_LIBADD = $(SSL_LIBS) $(DTLS_SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(ZLIB_LIBS) $(LIBINTL) $(P11KIT_LIBS) $(TSS_LIBS) $(LIBSTOKEN_LIBS) $(LIBOATH_LIBS) $(GSSAPI_LIBS) $(LIBICONV)
if OPENBSD_LIBTOOL
# OpenBSD's libtool doesn't have -version-number, but its -version-info arg
# does what GNU libtool's -version-number does. Which arguably is what the
Expand Down
3 changes: 2 additions & 1 deletion configure.ac
Expand Up @@ -181,8 +181,8 @@ AC_DISABLE_STATIC

AC_CHECK_FUNC(nl_langinfo, [AC_DEFINE(HAVE_NL_LANGINFO, 1, [Have nl_langinfo() function])], [])

have_iconv=no
if test "$ac_cv_func_nl_langinfo" = "yes"; then
have_iconv=no
LIBICONV=
AC_MSG_CHECKING([for iconv support])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
Expand All @@ -205,6 +205,7 @@ if test "$ac_cv_func_nl_langinfo" = "yes"; then
AC_DEFINE(HAVE_ICONV, 1, [Have iconv() function])
fi
fi
AM_CONDITIONAL(OPENCONNECT_ICONV, [test "$have_iconv" = "yes"])

AC_ARG_ENABLE([nls],
[ --disable-nls do not use Native Language Support],
Expand Down
91 changes: 91 additions & 0 deletions iconv.c
@@ -0,0 +1,91 @@
/*
* OpenConnect (SSL + DTLS) VPN client
*
* Copyright © 2008-2014 Intel Corporation.
*
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/

#include <config.h>

#include <iconv.h>
#include <errno.h>
#include <string.h>

#include "openconnect-internal.h"

static char *convert_str(struct openconnect_info *vpninfo, iconv_t ic,
char *instr)

{
char *ic_in, *ic_out, *outstr;
size_t insize, outsize;
int addq = 0;

if (ic == (iconv_t)-1)
return instr;

iconv(ic, NULL, NULL, NULL, NULL);

insize = strlen(instr) + 1;
ic_in = instr;

outsize = insize;
ic_out = outstr = malloc(outsize);
if (!outstr)
return instr;

while (insize) {
if (iconv(ic, &ic_in, &insize, &ic_out, &outsize) == (size_t)-1) {
perror("iconv");
if (errno == EILSEQ) {
do {
ic_in++;
insize--;
} while (insize && (ic_in[0] & 0xc0) == 0x80);
addq = 1;
}

if (!outsize || errno == E2BIG) {
int outlen = ic_out - outstr;
realloc_inplace(outstr, outlen + 10);
if (!outstr)
return instr;
ic_out = outstr + outlen;
outsize = 10;
} else if (errno != EILSEQ) {
/* Should never happen */
free(outstr);
return instr;
}
if (addq) {
addq = 0;
*(ic_out++) = '?';
outsize--;
}
}
}

return outstr;
}

char *openconnect_legacy_to_utf8(struct openconnect_info *vpninfo,
const char *legacy)
{
return convert_str(vpninfo, vpninfo->ic_legacy_to_utf8, (char *)legacy);
}

char *openconnect_utf8_to_legacy(struct openconnect_info *vpninfo,
const char *utf8)
{
return convert_str(vpninfo, vpninfo->ic_utf8_to_legacy, (char *)utf8);
}
17 changes: 17 additions & 0 deletions library.c
Expand Up @@ -45,10 +45,22 @@ struct openconnect_info *openconnect_vpninfo_new(char *useragent,
void *privdata)
{
struct openconnect_info *vpninfo = calloc(sizeof(*vpninfo), 1);
#ifdef HAVE_ICONV
char *charset = nl_langinfo(CODESET);
#endif

if (!vpninfo)
return NULL;

#ifdef HAVE_ICONV
if (charset && strcmp(charset, "UTF-8")) {
vpninfo->ic_utf8_to_legacy = iconv_open(charset, "UTF-8");
vpninfo->ic_legacy_to_utf8 = iconv_open("UTF-8", charset);
} else {
vpninfo->ic_utf8_to_legacy = (iconv_t)-1;
vpninfo->ic_legacy_to_utf8 = (iconv_t)-1;
}
#endif
#ifndef _WIN32
vpninfo->tun_fd = -1;
#endif
Expand Down Expand Up @@ -141,6 +153,11 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
close(vpninfo->cmd_fd);
close(vpninfo->cmd_fd_write);
}

#ifdef HAVE_ICONV
iconv_close(vpninfo->ic_utf8_to_legacy);
iconv_close(vpninfo->ic_legacy_to_utf8);
#endif
#ifdef _WIN32
if (vpninfo->cmd_event)
CloseHandle(vpninfo->cmd_event);
Expand Down
18 changes: 18 additions & 0 deletions openconnect-internal.h
Expand Up @@ -62,6 +62,11 @@
#endif
#endif

#ifdef HAVE_ICONV
#include <langinfo.h>
#include <iconv.h>
#endif

#include <zlib.h>
#include <stdint.h>
#include <sys/time.h>
Expand Down Expand Up @@ -174,6 +179,10 @@ struct proxy_auth_state {
};

struct openconnect_info {
#ifdef HAVE_ICONV
iconv_t ic_legacy_to_utf8;
iconv_t ic_utf8_to_legacy;
#endif
char *redirect_url;
int redirect_type;

Expand Down Expand Up @@ -521,6 +530,15 @@ int dumb_socketpair(int socks[2], int make_overlapped);

/****************************************************************************/

/* iconv.c */
#ifdef HAVE_ICONV
char *openconnect_utf8_to_legacy(struct openconnect_info *vpninfo, const char *utf8);
char *openconnect_legacy_to_utf8(struct openconnect_info *vpninfo, const char *legacy);
#else
#define openconnect_utf8_to_legacy(v, str) ((char *)str)
#define openconnect_legacy_to_utf8(v, str) ((char *)str)
#endif

/* script.c */
int setenv_int(const char *opt, int value);
void set_script_env(struct openconnect_info *vpninfo);
Expand Down

0 comments on commit c071217

Please sign in to comment.