From 2b6abef3194d904b5d21e8317e1a38ae55960e4e Mon Sep 17 00:00:00 2001 From: "mcs%netscape.com" Date: Wed, 4 Dec 2002 17:21:55 +0000 Subject: [PATCH] Fix bug # 177756 - eliminate dependency on libNLS. If HAVE_LIBNLS is not defined, OS functions (iconv and Win32 native APIs) are used for character set conversion of command line arguments. Fix bug # 177766 - LDAP tools should reject second -h argument. A second -p argument is also rejected. Fix bug # 159139 - HP/UX: LDAP command line tools do no charset conversion. Removed special case makefile rules for convutf8.cpp on HP/UX. --- .../c-sdk/ldap/clients/tools/Makefile.client | 8 +- directory/c-sdk/ldap/clients/tools/common.c | 20 +- .../c-sdk/ldap/clients/tools/convutf8.cpp | 320 +++++++++++++----- .../c-sdk/ldap/clients/tools/ldapcompare.c | 4 +- .../c-sdk/ldap/clients/tools/ldapdelete.c | 2 +- .../c-sdk/ldap/clients/tools/ldapsearch.c | 4 +- directory/c-sdk/ldap/clients/tools/ldaptool.h | 2 +- 7 files changed, 267 insertions(+), 93 deletions(-) diff --git a/directory/c-sdk/ldap/clients/tools/Makefile.client b/directory/c-sdk/ldap/clients/tools/Makefile.client index 41df52a85db..cf6718b3882 100644 --- a/directory/c-sdk/ldap/clients/tools/Makefile.client +++ b/directory/c-sdk/ldap/clients/tools/Makefile.client @@ -92,7 +92,7 @@ LDAPMODIFY_OBJ = $(addprefix $(OBJDEST)/, ldapmodify.o) LDAPSEARCH_OBJ = $(addprefix $(OBJDEST)/, ldapsearch.o) LDAPCOMPARE_OBJ = $(addprefix $(OBJDEST)/, ldapcompare.o) LDAPCMP_OBJ = $(addprefix $(OBJDEST)/, ldapcmp.o) -ifeq ($(OS_ARCH), HP-UX) +ifeq ($(OS_ARCH), used-to-use-this-on-HP-UX) LDAPTOOLCOMMON_OBJ = $(addprefix $(OBJDEST)/, common.o) \ $(addprefix $(OBJDEST)/, fileurl.o) else @@ -106,7 +106,7 @@ LDAPTOOLCOMMON_OBJ += $(addprefix $(OBJDEST)/, argpin.o) \ endif endif -ifeq ($(OS_ARCH), HP-UX) +ifeq ($(OS_ARCH), used-to-use-this-on-HP-UX) LDAPTOOLCPPCOMMON_OBJ = $(addprefix $(OBJDEST)/, convutf8.o) endif @@ -238,7 +238,7 @@ LIBLOCATION = $(NSCP_DISTDIR)/$(OBJDIR_NAME)/lib ########################################################################### -all:: $(BINS) $(OBJDEST) linklibnls libdir $(BINS) +all:: $(OBJDEST) linklibnls libdir $(BINS) libdir: linklibnls ifeq ($(OS_ARCH), WINNT) @@ -324,7 +324,7 @@ endif $(LDAPTOOLCOMMON_OBJ): -ifeq ($(OS_ARCH), HP-UX) +ifeq ($(OS_ARCH), used-to-use-this-on-HP-UX) $(LDAPTOOLCPPCOMMON_OBJ): convutf8.cpp ifneq ($(USE_64), 1) /opt/aCC/bin/aCC -ext -DHPUX_ACC -D__STDC_EXT__ -D_POSIX_C_SOURCE=199506L -c -DHPUX11 -DHPUX11_00 +DAportable +DS1.1 -D_LARGEFILE64_SOURCE -D_PR_HAVE_OFF64_T -DNO_NODELOCK -DNO_LIBLCACHE -DXP_UNIX -DHPUX -DMCC_HTTPD -DNS_DOMESTIC -DNET_SSL -DCLIENT_AUTH -DNSPR20 -D_PR_NTHREAD -D_PR_USECPU -D_REENTRANT -DNS_DS -DSPAPI20 -DBUILD_NUM=\"01.081.1519\" -DCPU_hppa -DOS_hpux -D_NO_THREADS_ -Dhpux -Dhpux -D_HPUX_SOURCE -D_REENTRANT -Aa -DLDAP_REFERRALS -DLDAP_LDBM -DLDAP_LDIF -DLDBM_USE_DBBTREE -DSLAPD_PASSWD_SHA1 -D__DBINTERFACE_PRIVATE -DNO_LIBLCACHE -DNS_DIRECTORY -DNET_SSL -DUSE_NSPR_MT -O $(INCLUDES) convutf8.cpp -o $(OBJDIR_NAME)/convutf8.o diff --git a/directory/c-sdk/ldap/clients/tools/common.c b/directory/c-sdk/ldap/clients/tools/common.c index 05fe5c96904..c264712952a 100644 --- a/directory/c-sdk/ldap/clients/tools/common.c +++ b/directory/c-sdk/ldap/clients/tools/common.c @@ -140,7 +140,8 @@ ldaptool_common_usage( int two_hosts ) } /* globals */ -char *ldaptool_charset = ""; +char *ldaptool_charset = NULL; +char *ldaptool_convdir = NULL; char *ldaptool_host = LDAPTOOL_DEFHOST; char *ldaptool_host2 = LDAPTOOL_DEFHOST; int ldaptool_port = LDAP_PORT; @@ -383,8 +384,13 @@ ldaptool_process_args( int argc, char **argv, char *extra_opts, case 'h': /* ldap host */ if ( hostnum == 0 ) { ldaptool_host = strdup( optarg ); - } else { + } else if ( two_hosts ) { ldaptool_host2 = strdup( optarg ); + } else { + fprintf( stderr, + "%s: only one host (-h option) should be specified\n", + ldaptool_progname ); + return(-1); /* usage error */ } ++hostnum; break; @@ -400,10 +406,16 @@ ldaptool_process_args( int argc, char **argv, char *extra_opts, if ( !user_specified_port ) { ++user_specified_port; ldaptool_port = atoi( optarg ); - } else { + } else if ( two_hosts ) { ++user_specified_port2; ldaptool_port2 = atoi( optarg ); + } else { + fprintf( stderr, + "%s: only one port (-p option) should be specified\n", + ldaptool_progname ); + return(-1); /* usage error */ } + break; #if defined(NET_SSL) case 'P': /* path to security database */ @@ -1026,7 +1038,7 @@ ldaptool_bind( LDAP *ld ) /* * do the bind, backing off one LDAP version if necessary */ - conv = ldaptool_local2UTF8( binddn ); + conv = ldaptool_local2UTF8( binddn, "bind DN" ); /* * if using LDAPv3 and client auth., try a SASL EXTERNAL bind diff --git a/directory/c-sdk/ldap/clients/tools/convutf8.cpp b/directory/c-sdk/ldap/clients/tools/convutf8.cpp index 2a602b9227e..a38c8302bbf 100644 --- a/directory/c-sdk/ldap/clients/tools/convutf8.cpp +++ b/directory/c-sdk/ldap/clients/tools/convutf8.cpp @@ -20,55 +20,261 @@ * Contributor(s): */ -#include -#include + +#ifdef _WIN32 +#define VC_EXTRALEAN +#include +#include +static char *win_char_converter(const char *instr, int bFromUTF8); +#else +#include +#endif + +#include "ldaptool.h" #ifndef HAVE_LIBNLS +#ifndef _WIN32 +#include +#include /* for nl_langinfo() */ +#endif + #ifdef __cplusplus extern "C" { #endif -extern char *ldaptool_charset; -char *ldaptool_convdir = NULL; -static int charsetset = 0; -char *ldaptool_local2UTF8( const char *src ); +/* OS name for the UTF-8 character set */ +#if defined(_HPUX_SOURCE) +#define LDAPTOOL_CHARSET_UTF8 "utf8" /* HP/UX */ +#else +#define LDAPTOOL_CHARSET_UTF8 "UTF-8" /* all others */ +#endif +/* OS name for the default character set */ +#if defined(_HPUX_SOURCE) +#define LDAPTOOL_CHARSET_DEFAULT "roma8" /* HP/UX */ +#elif defined(__GLIBC__) +#define LDAPTOOL_CHARSET_DEFAULT "US-ASCII" /* glibc (Linux) */ +#else +#define LDAPTOOL_CHARSET_DEFAULT "646" /* all others */ +#endif + +/* Type used for the src parameter to iconv() (the 2nd parameter) */ +#if defined(_HPUX_SOURCE) || defined(__GLIBC__) +#define LDAPTOOL_ICONV_SRC_TYPE char ** /* HP/UX and glibc (Linux) */ +#else +#define LDAPTOOL_ICONV_SRC_TYPE const char ** /* all others */ +#endif + +#if defined(SOLARIS) +/* + * On some versions of Solaris, the inbytesleft parameter can't be NULL + * even in calls to iconv() where inbuf itself is NULL + */ +#define LDAPTOOL_ICONV_NO_NULL_INBYTESLEFT 1 +#endif + +static char *convert_to_utf8( const char *src ); +#ifndef _WIN32 +static const char *GetCurrentCharset(void); +#endif + + +/* Version that uses OS functions */ char * -ldaptool_local2UTF8( const char *src ) +ldaptool_local2UTF8( const char *src, const char *desc ) { - char *utf8; + char *utf8; - charsetset = 0; + if ( src == NULL ) { /* trivial case # 1 */ + utf8 = NULL; + } else if ( *src == '\0' ) { /* trivial case # 2 */ + utf8 = strdup( "" ); + } else { + utf8 = convert_to_utf8( src ); /* the real deal */ - if (src == NULL) - { - return NULL; + if ( NULL == utf8 ) { + utf8 = strdup( utf8); /* fallback: no conversion */ + fprintf( stderr, "%s: warning: no conversion of %s to " + LDAPTOOL_CHARSET_UTF8 "\n", desc, ldaptool_progname ); + } } - utf8 = strdup(src); - return ( utf8 ); + return utf8; } -#else /* HAVE_LIBNLS */ +#ifdef _WIN32 +/* + * Try to convert src to a UTF-8. + * Returns a malloc'd string or NULL upon error (with messages logged). + * src should not be NULL. + */ +static char * +convert_to_utf8( const char *src ) /* returns NULL on error */ +{ + return win_char_converter( src, FALSE ); +} +#else /* _WIN32 */ + +/* + * Try to convert src to a UTF-8. + * Returns a malloc'd string or NULL upon error (with messages logged). + * src should not be NULL. + */ +static char * +convert_to_utf8( const char *src ) +{ + static const char *src_charset = NULL; + iconv_t convdesc; + char *outbuf, *curoutbuf; + size_t inbytesleft, outbytesleft; + +#ifdef LDAPTOOL_ICONV_NO_NULL_INBYTESLEFT +#define LDAPTOOL_ICONV_UNUSED_INBYTESLEFT &inbytesleft +#else +#define LDAPTOOL_ICONV_UNUSED_INBYTESLEFT NULL +#endif + + /* Determine the source charset if not already done */ + if ( NULL == src_charset ) { + if ( NULL != ldaptool_charset && 0 != strcmp( ldaptool_charset, "" )) { + src_charset = ldaptool_charset; + } else { + src_charset = GetCurrentCharset(); + } + } + + if ( NULL != src_charset + && 0 == strcmp( LDAPTOOL_CHARSET_UTF8, src_charset )) { + /* no conversion needs to be done */ + return strdup( src ); + } + + /* Get a converter */ + convdesc = iconv_open( LDAPTOOL_CHARSET_UTF8, src_charset ); + if ( (iconv_t)-1 == convdesc ) { + if ( errno == EINVAL ) { + fprintf( stderr, "%s: conversion from %s to %s is not supported\n", + ldaptool_progname, src_charset, LDAPTOOL_CHARSET_UTF8 ); + } else { + perror( src_charset ); + } + return NULL; + } + + /* Allocate room for the UTF-8 equivalent (maximum expansion = 6 times) */ +/* XXX is that correct? */ + inbytesleft = strlen( src ); + outbytesleft = 6 * inbytesleft + 1; + if ( NULL == ( outbuf = (char *)malloc( outbytesleft ))) { + perror( "convert_to_utf8 - malloc" ); + iconv_close( convdesc ); + return NULL; + } + + curoutbuf = outbuf; + /* + * Three steps for a good conversion: + * 1) Insert the initial shift sequence if any. + * 2) Convert our characters. + * 3) Insert the closing shift sequence, if any. + */ + if ( (size_t)-1 == iconv( convdesc, + ( LDAPTOOL_ICONV_SRC_TYPE )0, LDAPTOOL_ICONV_UNUSED_INBYTESLEFT, + &curoutbuf, &outbytesleft ) /* initial shift seq. */ + || (size_t)-1 == iconv( convdesc, + ( LDAPTOOL_ICONV_SRC_TYPE ) &src, &inbytesleft, + &curoutbuf, &outbytesleft ) /* convert our chars. */ + || (size_t)-1 == iconv( convdesc, + ( LDAPTOOL_ICONV_SRC_TYPE )0, LDAPTOOL_ICONV_UNUSED_INBYTESLEFT, + &curoutbuf, &outbytesleft )) { /* closing shift seq. */ + perror( "convert_to_utf8 - iconv" ); + iconv_close( convdesc ); + free( outbuf ); + return NULL; + } + + iconv_close( convdesc ); + *curoutbuf = '\0'; /* zero-terminate the resulting string */ + + return outbuf; +} + + +/* returns a malloc'd string */ +static const char * +GetCurrentCharset(void) +{ + static char *locale = NULL; + const char *charset; + + if ( NULL == locale ) { + locale = setlocale(LC_CTYPE, ""); /* need to call this once */ + } + + charset = nl_langinfo( CODESET ); + if ( NULL == charset || '\0' == *charset ) { + charset = LDAPTOOL_CHARSET_DEFAULT; + } + return strdup( charset ); +} +#endif /* else _WIN32 */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* !HAVE_LIBNLS */ + + +#ifdef _WIN32 +/* returns a malloc'd string */ +static char * +win_char_converter(const char *instr, int bFromUTF8) +{ + char *outstr = NULL; + int inlen, wclen, outlen; + LPWSTR wcstr; + + if (instr == NULL) + return NULL; + + if ((inlen = strlen(instr)) <= 0) + return NULL; + + /* output never becomes longer than input, XXXmcs: really true? + ** thus we don't have to ask for the length + */ + wcstr = (LPWSTR) malloc( sizeof( WCHAR ) * (inlen+1) ); + if (!wcstr) + return NULL; + + wclen = MultiByteToWideChar(bFromUTF8 ? CP_UTF8 : CP_ACP, 0, instr, + inlen, wcstr, inlen); + outlen = WideCharToMultiByte(bFromUTF8 ? CP_ACP : CP_UTF8, 0, wcstr, + wclen, NULL, 0, NULL, NULL); + + if (outlen > 0) { + outstr = (char *) malloc(outlen + 2); + outlen = WideCharToMultiByte(bFromUTF8 ? CP_ACP : CP_UTF8, 0, wcstr, + wclen, outstr, outlen, NULL, NULL); + if (outlen > 0) + *(outstr+outlen) = _T('\0'); + else + return NULL; + } + free( wcstr ); + return outstr; +} +#endif /* _WIN32 */ + + +#ifdef HAVE_LIBNLS #define NSPR20 -#ifdef XP_WIN32 -#define VC_EXTRALEAN -#include -#include -#endif - -extern char *ldaptool_charset; static int charsetset = 0; -extern "C" { -char *ldaptool_convdir = NULL; -char *ldaptool_local2UTF8( const char * ); -} - -#ifndef XP_WIN32 +#ifndef _WIN32 char * GetNormalizedLocaleName(void); #include "unistring.h" @@ -78,7 +284,8 @@ extern NLS_StaticConverterRegistry _STATICLINK_NSJPN_; extern NLS_StaticConverterRegistry _STATICLINK_NSCCK_; extern NLS_StaticConverterRegistry _STATICLINK_NSSB_; -char * +/* returns a malloc'd string */ +static char * GetNormalizedLocaleName(void) { #ifdef _HPUX_SOURCE @@ -472,52 +679,14 @@ GetCharsetFromLocale(char *locale) return tmpcharset; } -#endif /* Not defined XP_WIN32 */ - -#ifdef XP_WIN32 -char *_convertor(const char *instr, int bFromUTF8) -{ - char *outstr = NULL; - int inlen, wclen, outlen; - LPWSTR wcstr; - - if (instr == NULL) - return NULL; - - if ((inlen = strlen(instr)) <= 0) - return NULL; - - /* output never becomes longer than input, - ** thus we don't have to ask for the length - */ - wcstr = (LPWSTR) malloc( sizeof( WCHAR ) * (inlen+1) ); - if (!wcstr) - return NULL; - - wclen = MultiByteToWideChar(bFromUTF8 ? CP_UTF8 : CP_ACP, 0, instr, - inlen, wcstr, inlen); - outlen = WideCharToMultiByte(bFromUTF8 ? CP_ACP : CP_UTF8, 0, wcstr, - wclen, NULL, 0, NULL, NULL); - - if (outlen > 0) { - outstr = (char *) malloc(outlen + 2); - outlen = WideCharToMultiByte(bFromUTF8 ? CP_ACP : CP_UTF8, 0, wcstr, - wclen, outstr, outlen, NULL, NULL); - if (outlen > 0) - *(outstr+outlen) = _T('\0'); - else - return NULL; - } - free( wcstr ); - return outstr; -} -#endif +#endif /* !_WIN32 */ +/* version that uses libNLS */ char * -ldaptool_local2UTF8( const char *src ) +ldaptool_local2UTF8( const char *src, const char *desc ) { char *utf8; -#ifndef XP_WIN32 +#ifndef _WIN32 char *locale, *newcharset; size_t outLen, resultLen; NLS_ErrorCode err; @@ -581,7 +750,7 @@ ldaptool_local2UTF8( const char *src ) NLS_EncTerminate(); #else - utf8 = _convertor(src, FALSE); + utf8 = win_char_converter(src, FALSE); if( utf8 == NULL ) utf8 = strdup(src); #endif @@ -589,10 +758,3 @@ ldaptool_local2UTF8( const char *src ) return utf8; } #endif /* HAVE_LIBNLS */ - -#ifndef HAVE_LIBNLS -#ifdef __cplusplus -} -#endif -#endif - diff --git a/directory/c-sdk/ldap/clients/tools/ldapcompare.c b/directory/c-sdk/ldap/clients/tools/ldapcompare.c index 0eed2a00a83..3f5638991bd 100644 --- a/directory/c-sdk/ldap/clients/tools/ldapcompare.c +++ b/directory/c-sdk/ldap/clients/tools/ldapcompare.c @@ -91,7 +91,7 @@ main( int argc, char **argv ) usage( LDAP_PARAM_ERROR ); } - typeval = ldaptool_local2UTF8( argv[optind] ); + typeval = ldaptool_local2UTF8( argv[optind], "type and value" ); if (( rc = typeval2berval( typeval, &type, &bv )) != LDAP_SUCCESS ) { fprintf( stderr, "%s: unable to parse \"%s\"\n", ldaptool_progname, argv[optind] ); @@ -107,7 +107,7 @@ main( int argc, char **argv ) ++optind ) { char *conv; - conv = ldaptool_local2UTF8( argv[ optind ] ); + conv = ldaptool_local2UTF8( argv[ optind ], "DN" ); rc = docompare( ld, conv, type, &bv, ldaptool_request_ctrls ); if ( conv != NULL ) { free( conv ); diff --git a/directory/c-sdk/ldap/clients/tools/ldapdelete.c b/directory/c-sdk/ldap/clients/tools/ldapdelete.c index 7034bad62a1..1b0e64337b2 100644 --- a/directory/c-sdk/ldap/clients/tools/ldapdelete.c +++ b/directory/c-sdk/ldap/clients/tools/ldapdelete.c @@ -89,7 +89,7 @@ main( int argc, char **argv ) for ( ; optind < argc; ++optind ) { char *conv; - conv = ldaptool_local2UTF8( argv[ optind ] ); + conv = ldaptool_local2UTF8( argv[ optind ], "DN" ); rc = dodelete( ld, conv, ldaptool_request_ctrls ); if( conv != NULL ) free( conv ); diff --git a/directory/c-sdk/ldap/clients/tools/ldapsearch.c b/directory/c-sdk/ldap/clients/tools/ldapsearch.c index dc37660210a..2ea6f99523c 100644 --- a/directory/c-sdk/ldap/clients/tools/ldapsearch.c +++ b/directory/c-sdk/ldap/clients/tools/ldapsearch.c @@ -175,7 +175,7 @@ main( int argc, char **argv ) filtpattern = "%s"; } else { /* there are additional args (filter + attrs) */ if ( ldaptool_fp == NULL || strstr( argv[ optind ], "%s" ) != NULL ) { - filtpattern = ldaptool_local2UTF8( argv[ optind ] ); + filtpattern = ldaptool_local2UTF8( argv[ optind ], "filter" ); ++optind; } else { filtpattern = "%s"; @@ -232,7 +232,7 @@ main( int argc, char **argv ) if ( ldaptool_fp == NULL ) { char *conv; - conv = ldaptool_local2UTF8( base ); + conv = ldaptool_local2UTF8( base, "base DN" ); rc = dosearch( ld, conv, scope, attrs, attrsonly, filtpattern, "" ); if( conv != NULL ) free( conv ); diff --git a/directory/c-sdk/ldap/clients/tools/ldaptool.h b/directory/c-sdk/ldap/clients/tools/ldaptool.h index b2c605b66cf..f0a11e79317 100644 --- a/directory/c-sdk/ldap/clients/tools/ldaptool.h +++ b/directory/c-sdk/ldap/clients/tools/ldaptool.h @@ -157,7 +157,7 @@ LDAPControl *ldaptool_create_proxyauth_control( LDAP *ld ); void ldaptool_add_control_to_array( LDAPControl *ctrl, LDAPControl **array); void ldaptool_reset_control_array( LDAPControl **array ); char *ldaptool_get_tmp_dir( void ); -char *ldaptool_local2UTF8( const char * ); +char *ldaptool_local2UTF8( const char *s, const char *desc ); int ldaptool_berval_is_ascii( const struct berval *bvp ); int ldaptool_sasl_bind_s( LDAP *ld, const char *dn, const char *mechanism, const struct berval *cred, LDAPControl **serverctrls,