summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libkiconv/xlat16_iconv.c12
-rw-r--r--sys/conf/files1
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c112
-rw-r--r--sys/fs/smbfs/smbfs_smb.c44
-rw-r--r--sys/fs/smbfs/smbfs_subr.c28
-rw-r--r--sys/kern/subr_mchain.c15
-rw-r--r--sys/libkern/iconv.c12
-rw-r--r--sys/libkern/iconv_ucs.c540
-rw-r--r--sys/modules/libiconv/Makefile5
-rw-r--r--sys/modules/libmchain/Makefile1
-rw-r--r--sys/netsmb/smb_conn.c32
-rw-r--r--sys/netsmb/smb_conn.h6
-rw-r--r--sys/netsmb/smb_smb.c64
-rw-r--r--sys/netsmb/smb_subr.c4
-rw-r--r--sys/sys/iconv.h3
-rw-r--r--sys/sys/mchain.h1
16 files changed, 780 insertions, 100 deletions
diff --git a/lib/libkiconv/xlat16_iconv.c b/lib/libkiconv/xlat16_iconv.c
index ce06324..dc9dc86 100644
--- a/lib/libkiconv/xlat16_iconv.c
+++ b/lib/libkiconv/xlat16_iconv.c
@@ -74,6 +74,18 @@ kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag)
struct xlat16_table xt;
void *data;
char *p;
+ const char unicode[] = ENCODING_UNICODE;
+
+ if ((flag & KICONV_WCTYPE) == 0 &&
+ strcmp(unicode, tocode) != 0 &&
+ strcmp(unicode, fromcode) != 0 &&
+ kiconv_lookupconv(unicode) == 0) {
+ error = kiconv_add_xlat16_cspair(unicode, fromcode, flag);
+ if (error)
+ return (-1);
+ error = kiconv_add_xlat16_cspair(tocode, unicode, flag);
+ return (error);
+ }
if (kiconv_lookupcs(tocode, fromcode) == 0)
return (0);
diff --git a/sys/conf/files b/sys/conf/files
index b448be6..2ae85e9 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2557,6 +2557,7 @@ libkern/fnmatch.c standard
libkern/gets.c standard
libkern/iconv.c optional libiconv
libkern/iconv_converter_if.m optional libiconv
+libkern/iconv_ucs.c optional libiconv
libkern/iconv_xlat.c optional libiconv
libkern/iconv_xlat16.c optional libiconv
libkern/index.c standard
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c
index 8dc1d07..fde6512 100644
--- a/sys/fs/msdosfs/msdosfs_conv.c
+++ b/sys/fs/msdosfs/msdosfs_conv.c
@@ -61,9 +61,9 @@
extern struct iconv_functions *msdosfs_iconv;
static int mbsadjpos(const char **, size_t, size_t, int, int, void *handle);
-static u_int16_t dos2unixchr(const u_char **, size_t *, int, struct msdosfsmount *);
+static u_char * dos2unixchr(const u_char **, size_t *, int, struct msdosfsmount *);
static u_int16_t unix2doschr(const u_char **, size_t *, struct msdosfsmount *);
-static u_int16_t win2unixchr(u_int16_t, struct msdosfsmount *);
+static u_char * win2unixchr(u_int16_t, struct msdosfsmount *);
static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *);
/*
@@ -242,7 +242,7 @@ dos2unixfn(dn, un, lower, pmp)
{
size_t i;
int thislong = 0;
- u_int16_t c;
+ u_char *c;
/*
* If first char of the filename is SLOT_E5 (0x05), then the real
@@ -259,12 +259,10 @@ dos2unixfn(dn, un, lower, pmp)
for (i = 8; i > 0 && *dn != ' ';) {
c = dos2unixchr((const u_char **)&dn, &i, lower & LCASE_BASE,
pmp);
- if (c & 0xff00) {
- *un++ = c >> 8;
+ while (*c != '\0') {
+ *un++ = *c++;
thislong++;
}
- *un++ = c;
- thislong++;
}
dn += i;
@@ -278,12 +276,10 @@ dos2unixfn(dn, un, lower, pmp)
for (i = 3; i > 0 && *dn != ' ';) {
c = dos2unixchr((const u_char **)&dn, &i,
lower & LCASE_EXT, pmp);
- if (c & 0xff00) {
- *un++ = c >> 8;
+ while (*c != '\0') {
+ *un++ = *c++;
thislong++;
}
- *un++ = c;
- thislong++;
}
}
*un++ = 0;
@@ -652,8 +648,9 @@ win2unixfn(nbp, wep, chksum, pmp)
int chksum;
struct msdosfsmount *pmp;
{
+ u_char *c;
u_int8_t *cp;
- u_int8_t *np, name[WIN_CHARS * 2 + 1];
+ u_int8_t *np, name[WIN_CHARS * 3 + 1];
u_int16_t code;
int i;
@@ -686,10 +683,9 @@ win2unixfn(nbp, wep, chksum, pmp)
*np = '\0';
return -1;
default:
- code = win2unixchr(code, pmp);
- if (code & 0xff00)
- *np++ = code >> 8;
- *np++ = code;
+ c = win2unixchr(code, pmp);
+ while (*c != '\0')
+ *np++ = *c++;
break;
}
cp += 2;
@@ -705,10 +701,9 @@ win2unixfn(nbp, wep, chksum, pmp)
*np = '\0';
return -1;
default:
- code = win2unixchr(code, pmp);
- if (code & 0xff00)
- *np++ = code >> 8;
- *np++ = code;
+ c = win2unixchr(code, pmp);
+ while (*c != '\0')
+ *np++ = *c++;
break;
}
cp += 2;
@@ -724,10 +719,9 @@ win2unixfn(nbp, wep, chksum, pmp)
*np = '\0';
return -1;
default:
- code = win2unixchr(code, pmp);
- if (code & 0xff00)
- *np++ = code >> 8;
- *np++ = code;
+ c = win2unixchr(code, pmp);
+ while (*c != '\0')
+ *np++ = *c++;
break;
}
cp += 2;
@@ -817,24 +811,22 @@ mbsadjpos(const char **instr, size_t inlen, size_t outlen, int weight, int flag,
/*
* Convert DOS char to Local char
*/
-static u_int16_t
+static u_char *
dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp)
{
- u_char c;
- char *outp, outbuf[3];
- u_int16_t wc;
+ u_char c, *outp, outbuf[5];
size_t len, olen;
+ outp = outbuf;
if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
- olen = len = 2;
- outp = outbuf;
+ olen = len = 4;
if (lower & (LCASE_BASE | LCASE_EXT))
msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr,
- ilen, &outp, &olen, KICONV_LOWER);
+ ilen, (char **)&outp, &olen, KICONV_LOWER);
else
msdosfs_iconv->convchr(pmp->pm_d2u, (const char **)instr,
- ilen, &outp, &olen);
+ ilen, (char **)&outp, &olen);
len -= olen;
/*
@@ -843,21 +835,21 @@ dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *
if (len == 0) {
(*ilen)--;
(*instr)++;
- return ('?');
+ *outp++ = '?';
}
-
- wc = 0;
- while(len--)
- wc |= (*(outp - len - 1) & 0xff) << (len << 3);
- return (wc);
+ } else {
+ (*ilen)--;
+ c = *(*instr)++;
+ c = dos2unix[c];
+ if (lower & (LCASE_BASE | LCASE_EXT))
+ c = u2l[c];
+ *outp++ = c;
+ outbuf[1] = '\0';
}
- (*ilen)--;
- c = *(*instr)++;
- c = dos2unix[c];
- if (lower & (LCASE_BASE | LCASE_EXT))
- c = u2l[c];
- return ((u_int16_t)c);
+ *outp = '\0';
+ outp = outbuf;
+ return (outp);
}
/*
@@ -940,23 +932,21 @@ unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp)
/*
* Convert Windows char to Local char
*/
-static u_int16_t
+static u_char *
win2unixchr(u_int16_t wc, struct msdosfsmount *pmp)
{
- u_char *inp, *outp, inbuf[3], outbuf[3];
+ u_char *inp, *outp, inbuf[3], outbuf[5];
size_t ilen, olen, len;
- if (wc == 0)
- return (0);
-
+ outp = outbuf;
if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
inbuf[0] = (u_char)(wc>>8);
inbuf[1] = (u_char)wc;
inbuf[2] = '\0';
- ilen = olen = len = 2;
+ ilen = 2;
+ olen = len = 4;
inp = inbuf;
- outp = outbuf;
msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen,
(char **)&outp, &olen);
len -= olen;
@@ -964,21 +954,15 @@ win2unixchr(u_int16_t wc, struct msdosfsmount *pmp)
/*
* return '?' if failed to convert
*/
- if (len == 0) {
- wc = '?';
- return (wc);
- }
-
- wc = 0;
- while(len--)
- wc |= (*(outp - len - 1) & 0xff) << (len << 3);
- return (wc);
+ if (len == 0)
+ *outp++ = '?';
+ } else {
+ *outp++ = (wc & 0xff00) ? '?' : (u_char)(wc & 0xff);
}
- if (wc & 0xff00)
- wc = '?';
-
- return (wc);
+ *outp = '\0';
+ outp = outbuf;
+ return (outp);
}
/*
diff --git a/sys/fs/smbfs/smbfs_smb.c b/sys/fs/smbfs/smbfs_smb.c
index bebc8ee..05162d5 100644
--- a/sys/fs/smbfs/smbfs_smb.c
+++ b/sys/fs/smbfs/smbfs_smb.c
@@ -34,6 +34,7 @@
#include <sys/vnode.h>
#include <sys/mbuf.h>
#include <sys/mount.h>
+#include <sys/endian.h>
#ifdef USE_MD5_HASH
#include <sys/md5.h>
@@ -393,6 +394,10 @@ smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
if (error)
break;
mb_put_uint8(mbp, SMB_DT_ASCII);
+ if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
+ mb_put_padbyte(mbp);
+ mb_put_uint8(mbp, 0); /* 1st byte of NULL Unicode char */
+ }
mb_put_uint8(mbp, 0);
smb_rq_bend(rqp);
error = smb_rq_simple(rqp);
@@ -909,6 +914,10 @@ smbfs_smb_search(struct smbfs_fctx *ctx)
mb_put_uint16le(mbp, 0); /* context length */
ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
} else {
+ if (SMB_UNICODE_STRINGS(vcp)) {
+ mb_put_padbyte(mbp);
+ mb_put_uint8(mbp, 0);
+ }
mb_put_uint8(mbp, 0); /* file name length */
mb_put_uint8(mbp, SMB_DT_VARIABLE);
mb_put_uint16le(mbp, SMB_SKEYLEN);
@@ -1069,7 +1078,7 @@ smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
mb_put_uint32le(mbp, 0); /* resume key */
mb_put_uint16le(mbp, flags);
if (ctx->f_rname)
- mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
+ mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM);
else
mb_put_uint8(mbp, 0); /* resume file name */
#if 0
@@ -1152,7 +1161,10 @@ static int
smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
const char *wildcard, int wclen, int attr, struct smb_cred *scred)
{
- ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
+ ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
+ } else
+ ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
if (ctx->f_name == NULL)
return ENOMEM;
ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
@@ -1231,7 +1243,10 @@ smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
return EINVAL;
}
- nmlen = min(size, SMB_MAXFNAMELEN);
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
+ nmlen = min(size, SMB_MAXFNAMELEN * 2);
+ } else
+ nmlen = min(size, SMB_MAXFNAMELEN);
cp = ctx->f_name;
error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
if (error)
@@ -1245,8 +1260,12 @@ smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
return EBADRPC;
}
}
- if (nmlen && cp[nmlen - 1] == 0)
- nmlen--;
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
+ if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
+ nmlen -= 2;
+ } else
+ if (nmlen && cp[nmlen - 1] == 0)
+ nmlen--;
if (nmlen == 0)
return EBADRPC;
@@ -1330,10 +1349,17 @@ smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
error = smbfs_findnextLM2(ctx, limit);
if (error)
return error;
- if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
- (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
- ctx->f_name[1] == '.'))
- continue;
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
+ if ((ctx->f_nmlen == 2 &&
+ *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
+ (ctx->f_nmlen == 4 &&
+ *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
+ continue;
+ } else
+ if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
+ (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
+ ctx->f_name[1] == '.'))
+ continue;
break;
}
smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
diff --git a/sys/fs/smbfs/smbfs_subr.c b/sys/fs/smbfs/smbfs_subr.c
index b775dff..51ee4d5 100644
--- a/sys/fs/smbfs/smbfs_subr.c
+++ b/sys/fs/smbfs/smbfs_subr.c
@@ -130,7 +130,10 @@ smb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np,
return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/
while (i--) {
np = *--npp;
- error = mb_put_uint8(mbp, '\\');
+ if (SMB_UNICODE_STRINGS(vcp))
+ error = mb_put_uint16le(mbp, '\\');
+ else
+ error = mb_put_uint8(mbp, '\\');
if (error)
break;
error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt);
@@ -148,6 +151,11 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
int caseopt = SMB_CS_NONE;
int error;
+ if (SMB_UNICODE_STRINGS(vcp)) {
+ error = mb_put_padbyte(mbp);
+ if (error)
+ return error;
+ }
if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
caseopt |= SMB_CS_UPPER;
if (dnp != NULL) {
@@ -156,7 +164,10 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
return error;
}
if (name) {
- error = mb_put_uint8(mbp, '\\');
+ if (SMB_UNICODE_STRINGS(vcp))
+ error = mb_put_uint16le(mbp, '\\');
+ else
+ error = mb_put_uint8(mbp, '\\');
if (error)
return error;
error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt);
@@ -164,6 +175,8 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
return error;
}
error = mb_put_uint8(mbp, 0);
+ if (SMB_UNICODE_STRINGS(vcp) && error == 0)
+ error = mb_put_uint8(mbp, 0);
return error;
}
@@ -191,6 +204,17 @@ smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int *nmlen, int caseopt)
error = iconv_conv_case
(vcp->vc_tolocal, (const char **)&ibuf, &ilen, &obuf, &olen, copt);
+ if (error && SMB_UNICODE_STRINGS(vcp)) {
+ /*
+ * If using unicode, leaving a file name as it was when
+ * convert fails will cause a problem because the file name
+ * will contain NULL.
+ * Here, put '?' and give converted file name.
+ */
+ *obuf = '?';
+ olen--;
+ error = 0;
+ }
if (!error) {
*nmlen = sizeof(outbuf) - olen;
memcpy(name, outbuf, *nmlen);
diff --git a/sys/kern/subr_mchain.c b/sys/kern/subr_mchain.c
index e40e5ff..3fd265b 100644
--- a/sys/kern/subr_mchain.c
+++ b/sys/kern/subr_mchain.c
@@ -128,6 +128,21 @@ mb_reserve(struct mbchain *mbp, int size)
}
int
+mb_put_padbyte(struct mbchain *mbp)
+{
+ caddr_t dst;
+ char x = 0;
+
+ dst = mtod(mbp->mb_cur, caddr_t) + mbp->mb_cur->m_len;
+
+ /* only add padding if address is odd */
+ if ((unsigned long)dst & 1)
+ return mb_put_mem(mbp, (caddr_t)&x, 1, MB_MSYSTEM);
+ else
+ return 0;
+}
+
+int
mb_put_uint8(struct mbchain *mbp, uint8_t x)
{
return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
diff --git a/sys/libkern/iconv.c b/sys/libkern/iconv.c
index 9b46db6..92b04c2 100644
--- a/sys/libkern/iconv.c
+++ b/sys/libkern/iconv.c
@@ -377,6 +377,18 @@ iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE,
NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs");
+int
+iconv_add(const char *converter, const char *to, const char *from)
+{
+ struct iconv_converter_class *dcp;
+ struct iconv_cspair *csp;
+
+ if (iconv_lookupconv(converter, &dcp) != 0)
+ return EINVAL;
+
+ return iconv_register_cspair(to, from, dcp, NULL, &csp);
+}
+
/*
* Add new charset pair
*/
diff --git a/sys/libkern/iconv_ucs.c b/sys/libkern/iconv_ucs.c
new file mode 100644
index 0000000..c6f2823
--- /dev/null
+++ b/sys/libkern/iconv_ucs.c
@@ -0,0 +1,540 @@
+/*-
+ * Copyright (c) 2003, 2005 Ryuichiro Imura
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/iconv.h>
+
+#include "iconv_converter_if.h"
+
+/*
+ * "UCS" converter
+ */
+
+#define KICONV_UCS_COMBINE 0x1
+#define KICONV_UCS_FROM_UTF8 0x2
+#define KICONV_UCS_TO_UTF8 0x4
+#define KICONV_UCS_FROM_LE 0x8
+#define KICONV_UCS_TO_LE 0x10
+#define KICONV_UCS_FROM_UTF16 0x20
+#define KICONV_UCS_TO_UTF16 0x40
+#define KICONV_UCS_UCS4 0x80
+
+#define ENCODING_UTF16 "UTF-16BE"
+#define ENCODING_UTF8 "UTF-8"
+
+static struct {
+ const char *name;
+ int from_flag, to_flag;
+} unicode_family[] = {
+ { "UTF-8", KICONV_UCS_FROM_UTF8, KICONV_UCS_TO_UTF8 },
+ { "UCS-2LE", KICONV_UCS_FROM_LE, KICONV_UCS_TO_LE },
+ { "UTF-16BE", KICONV_UCS_FROM_UTF16, KICONV_UCS_TO_UTF16 },
+ { "UTF-16LE", KICONV_UCS_FROM_UTF16|KICONV_UCS_FROM_LE,
+ KICONV_UCS_TO_UTF16|KICONV_UCS_TO_LE },
+ { NULL, 0, 0 }
+};
+
+static uint32_t utf8_to_ucs4(const char *src, size_t *utf8width, size_t srclen);
+static u_char *ucs4_to_utf8(uint32_t ucs4, char * dst, size_t *utf8width, size_t dstlen);
+static uint32_t encode_surrogate(uint32_t code);
+static uint32_t decode_surrogate(const u_char *ucs);
+
+#ifdef MODULE_DEPEND
+MODULE_DEPEND(iconv_ucs, libiconv, 2, 2, 2);
+#endif
+
+/*
+ * UCS converter instance
+ */
+struct iconv_ucs {
+ KOBJ_FIELDS;
+ int convtype;
+ struct iconv_cspair * d_csp;
+ struct iconv_cspair * d_cspf;
+ void * f_ctp;
+ void * t_ctp;
+ void * ctype;
+};
+
+static int
+iconv_ucs_open(struct iconv_converter_class *dcp,
+ struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp)
+{
+ struct iconv_ucs *dp;
+ int i;
+ const char *from, *to;
+
+ dp = (struct iconv_ucs *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK);
+ to = csp->cp_to;
+ from = cspf ? cspf->cp_from : csp->cp_from;
+
+ dp->convtype = 0;
+
+ if (cspf)
+ dp->convtype |= KICONV_UCS_COMBINE;
+ for (i = 0; unicode_family[i].name; i++) {
+ if (strcmp(from, unicode_family[i].name) == 0)
+ dp->convtype |= unicode_family[i].from_flag;
+ if (strcmp(to, unicode_family[i].name) == 0)
+ dp->convtype |= unicode_family[i].to_flag;
+ }
+ if (strcmp(ENCODING_UNICODE, ENCODING_UTF16) == 0)
+ dp->convtype |= KICONV_UCS_UCS4;
+ else
+ dp->convtype &= ~KICONV_UCS_UCS4;
+
+ dp->f_ctp = dp->t_ctp = NULL;
+ if (dp->convtype & KICONV_UCS_COMBINE) {
+ if ((dp->convtype & KICONV_UCS_FROM_UTF8) == 0 &&
+ (dp->convtype & KICONV_UCS_FROM_LE) == 0) {
+ iconv_open(ENCODING_UNICODE, from, &dp->f_ctp);
+ }
+ if ((dp->convtype & KICONV_UCS_TO_UTF8) == 0 &&
+ (dp->convtype & KICONV_UCS_TO_LE) == 0) {
+ iconv_open(to, ENCODING_UNICODE, &dp->t_ctp);
+ }
+ }
+
+ dp->ctype = NULL;
+ if (dp->convtype & (KICONV_UCS_FROM_UTF8 | KICONV_UCS_TO_UTF8))
+ iconv_open(KICONV_WCTYPE_NAME, ENCODING_UTF8, &dp->ctype);
+
+ dp->d_csp = csp;
+ if (dp->convtype & (KICONV_UCS_FROM_UTF8 | KICONV_UCS_FROM_LE)) {
+ if (cspf) {
+ dp->d_cspf = cspf;
+ cspf->cp_refcount++;
+ } else
+ csp->cp_refcount++;
+ }
+ if (dp->convtype & (KICONV_UCS_TO_UTF8 | KICONV_UCS_TO_LE))
+ csp->cp_refcount++;
+ *dpp = (void*)dp;
+ return 0;
+}
+
+static int
+iconv_ucs_close(void *data)
+{
+ struct iconv_ucs *dp = data;
+
+ if (dp->f_ctp)
+ iconv_close(dp->f_ctp);
+ if (dp->t_ctp)
+ iconv_close(dp->t_ctp);
+ if (dp->ctype)
+ iconv_close(dp->ctype);
+ if (dp->d_cspf)
+ dp->d_cspf->cp_refcount--;
+ else if (dp->convtype & (KICONV_UCS_FROM_UTF8 | KICONV_UCS_FROM_LE))
+ dp->d_csp->cp_refcount--;
+ if (dp->convtype & (KICONV_UCS_TO_UTF8 | KICONV_UCS_TO_LE))
+ dp->d_csp->cp_refcount--;
+ kobj_delete((struct kobj*)data, M_ICONV);
+ return 0;
+}
+
+static int
+iconv_ucs_conv(void *d2p, const char **inbuf,
+ size_t *inbytesleft, char **outbuf, size_t *outbytesleft,
+ int convchar, int casetype)
+{
+ struct iconv_ucs *dp = (struct iconv_ucs*)d2p;
+ int ret = 0, i;
+ size_t in, on, ir, or, inlen, outlen, ucslen;
+ const char *src, *p;
+ char *dst;
+ u_char ucs[4], *q;
+ uint32_t code;
+
+ if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL)
+ return 0;
+ ir = in = *inbytesleft;
+ or = on = *outbytesleft;
+ src = *inbuf;
+ dst = *outbuf;
+
+ while (ir > 0 && or > 0) {
+
+ /*
+ * The first half of conversion.
+ * (convert any code into ENCODING_UNICODE)
+ */
+ code = 0;
+ p = src;
+ if (dp->convtype & KICONV_UCS_FROM_UTF8) {
+ /* convert UTF-8 to ENCODING_UNICODE */
+ inlen = 0;
+ code = utf8_to_ucs4(p, &inlen, ir);
+ if (code == 0) {
+ ret = -1;
+ break;
+ }
+
+ if (casetype == KICONV_FROM_LOWER && dp->ctype) {
+ code = towlower(code, dp->ctype);
+ } else if (casetype == KICONV_FROM_UPPER && dp->ctype) {
+ code = towupper(code, dp->ctype);
+ }
+
+ if ((code >= 0xd800 && code < 0xe000) || code >= 0x110000 ) {
+ /* reserved for utf-16 surrogate pair */
+ /* invalid unicode */
+ ret = -1;
+ break;
+ }
+
+ if (inlen == 4) {
+ if (dp->convtype & KICONV_UCS_UCS4) {
+ ucslen = 4;
+ code = encode_surrogate(code);
+ } else {
+ /* can't handle with ucs-2 */
+ ret = -1;
+ break;
+ }
+ } else {
+ ucslen = 2;
+ }
+
+ /* save UCS-4 into ucs[] */
+ for (q = ucs, i = ucslen - 1 ; i >= 0 ; i--)
+ *q++ = (code >> (i << 3)) & 0xff;
+
+ } else if (dp->convtype & KICONV_UCS_COMBINE && dp->f_ctp) {
+ /* convert local code to ENCODING_UNICODE */
+ ucslen = 4;
+ inlen = ir;
+ q = ucs;
+ ret = iconv_convchr_case(dp->f_ctp, &p, &inlen, (char **)&q,
+ &ucslen, casetype & (KICONV_FROM_LOWER | KICONV_FROM_UPPER));
+ if (ret)
+ break;
+ inlen = ir - inlen;
+ ucslen = 4 - ucslen;
+
+ } else {
+ /* src code is a proper subset of ENCODING_UNICODE */
+ q = ucs;
+ if (dp->convtype & KICONV_UCS_FROM_LE) {
+ *q = *(p + 1);
+ *(q + 1) = *p;
+ p += 2;
+ } else {
+ *q = *p++;
+ *(q + 1) = *p++;
+ }
+ if ((*q & 0xfc) == 0xd8) {
+ if (dp->convtype & KICONV_UCS_UCS4 &&
+ dp->convtype & KICONV_UCS_FROM_UTF16) {
+ inlen = ucslen = 4;
+ } else {
+ /* invalid unicode */
+ ret = -1;
+ break;
+ }
+ } else {
+ inlen = ucslen = 2;
+ }
+ if (ir < inlen) {
+ ret = -1;
+ break;
+ }
+ if (ucslen == 4) {
+ q += 2;
+ if (dp->convtype & KICONV_UCS_FROM_LE) {
+ *q = *(p + 1);
+ *(q + 1) = *p;
+ } else {
+ *q = *p++;
+ *(q + 1) = *p;
+ }
+ if ((*q & 0xfc) != 0xdc) {
+ /* invalid unicode */
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ /*
+ * The second half of conversion.
+ * (convert ENCODING_UNICODE into any code)
+ */
+ p = ucs;
+ if (dp->convtype & KICONV_UCS_TO_UTF8) {
+ q = (u_char *)dst;
+ if (ucslen == 4 && dp->convtype & KICONV_UCS_UCS4) {
+ /* decode surrogate pair */
+ code = decode_surrogate(p);
+ } else {
+ code = (ucs[0] << 8) | ucs[1];
+ }
+
+ if (casetype == KICONV_LOWER && dp->ctype) {
+ code = towlower(code, dp->ctype);
+ } else if (casetype == KICONV_UPPER && dp->ctype) {
+ code = towupper(code, dp->ctype);
+ }
+
+ outlen = 0;
+ if (ucs4_to_utf8(code, q, &outlen, or) == NULL) {
+ ret = -1;
+ break;
+ }
+
+ src += inlen;
+ ir -= inlen;
+ dst += outlen;
+ or -= outlen;
+
+ } else if (dp->convtype & KICONV_UCS_COMBINE && dp->t_ctp) {
+ ret = iconv_convchr_case(dp->t_ctp, &p, &ucslen, &dst,
+ &or, casetype & (KICONV_LOWER | KICONV_UPPER));
+ if (ret)
+ break;
+
+ src += inlen;
+ ir -= inlen;
+
+ } else {
+ /* dst code is a proper subset of ENCODING_UNICODE */
+ if (or < ucslen) {
+ ret = -1;
+ break;
+ }
+ src += inlen;
+ ir -= inlen;
+ or -= ucslen;
+ if (dp->convtype & KICONV_UCS_TO_LE) {
+ *dst++ = *(p + 1);
+ *dst++ = *p;
+ p += 2;
+ } else {
+ *dst++ = *p++;
+ *dst++ = *p++;
+ }
+ if (ucslen == 4) {
+ if ((dp->convtype & KICONV_UCS_UCS4) == 0 ||
+ (dp->convtype & KICONV_UCS_TO_UTF16) == 0) {
+ ret = -1;
+ break;
+ }
+ if (dp->convtype & KICONV_UCS_TO_LE) {
+ *dst++ = *(p + 1);
+ *dst++ = *p;
+ } else {
+ *dst++ = *p++;
+ *dst++ = *p;
+ }
+ }
+ }
+
+ if (convchar == 1)
+ break;
+ }
+
+ *inbuf += in - ir;
+ *outbuf += on - or;
+ *inbytesleft -= in - ir;
+ *outbytesleft -= on - or;
+ return (ret);
+}
+
+static int
+iconv_ucs_init(struct iconv_converter_class *dcp)
+{
+ int error;
+
+ error = iconv_add(ENCODING_UNICODE, ENCODING_UNICODE, ENCODING_UTF8);
+ if (error)
+ return (error);
+ error = iconv_add(ENCODING_UNICODE, ENCODING_UTF8, ENCODING_UNICODE);
+ if (error)
+ return (error);
+ return (0);
+}
+
+static int
+iconv_ucs_done(struct iconv_converter_class *dcp)
+{
+ return (0);
+}
+
+static const char *
+iconv_ucs_name(struct iconv_converter_class *dcp)
+{
+ return (ENCODING_UNICODE);
+}
+
+static kobj_method_t iconv_ucs_methods[] = {
+ KOBJMETHOD(iconv_converter_open, iconv_ucs_open),
+ KOBJMETHOD(iconv_converter_close, iconv_ucs_close),
+ KOBJMETHOD(iconv_converter_conv, iconv_ucs_conv),
+ KOBJMETHOD(iconv_converter_init, iconv_ucs_init),
+ KOBJMETHOD(iconv_converter_done, iconv_ucs_done),
+ KOBJMETHOD(iconv_converter_name, iconv_ucs_name),
+ {0, 0}
+};
+
+KICONV_CONVERTER(ucs, sizeof(struct iconv_ucs));
+
+static uint32_t
+utf8_to_ucs4(const char *src, size_t *utf8width, size_t srclen)
+{
+ size_t i, w = 0;
+ uint32_t ucs4 = 0;
+
+ /*
+ * get leading 1 byte from utf-8
+ */
+ if ((*src & 0x80) == 0) {
+ /*
+ * leading 1 bit is "0"
+ * utf-8: 0xxxxxxx
+ * ucs-4: 00000000 00000000 00000000 0xxxxxxx
+ */
+ w = 1;
+ /* get trailing 7 bits */
+ ucs4 = *src & 0x7f;
+ } else if ((*src & 0xe0) == 0xc0) {
+ /*
+ * leading 3 bits are "110"
+ * utf-8: 110xxxxx 10yyyyyy
+ * ucs-4: 00000000 00000000 00000xxx xxyyyyyy
+ */
+ w = 2;
+ /* get trailing 5 bits */
+ ucs4 = *src & 0x1f;
+ } else if ((*src & 0xf0) == 0xe0) {
+ /*
+ * leading 4 bits are "1110"
+ * utf-8: 1110xxxx 10yyyyyy 10zzzzzz
+ * ucs-4: 00000000 00000000 xxxxyyyy yyzzzzzz
+ */
+ w = 3;
+ /* get trailing 4 bits */
+ ucs4 = *src & 0x0f;
+ } else if ((*src & 0xf8) == 0xf0) {
+ /*
+ * leading 5 bits are "11110"
+ * utf-8: 11110www 10xxxxxx 10yyyyyy 10zzzzzz
+ * ucs-4: 00000000 000wwwxx xxxxyyyy yyzzzzzz
+ */
+ w = 4;
+ /* get trailing 3 bits */
+ ucs4 = *src & 0x07;
+ } else {
+ /* out of utf-16 range or having illegal bits */
+ return (0);
+ }
+ if (w == 0)
+ return (0);
+
+ if (srclen < w)
+ return (0);
+
+ /*
+ * get left parts from utf-8
+ */
+ for (i = 1 ; i < w ; i++) {
+ if ((*(src + i) & 0xc0) != 0x80) {
+ /* invalid: leading 2 bits are not "10" */
+ return (0);
+ }
+ /* concatenate trailing 6 bits into ucs4 */
+ ucs4 <<= 6;
+ ucs4 |= *(src + i) & 0x3f;
+ }
+
+ *utf8width = w;
+ return (ucs4);
+}
+
+static u_char *
+ucs4_to_utf8(uint32_t ucs4, char *dst, size_t *utf8width, size_t dstlen)
+{
+ u_char lead, *p;
+ size_t i, w;
+
+ /*
+ * determine utf-8 width and leading bits
+ */
+ if (ucs4 < 0x80) {
+ w = 1;
+ lead = 0; /* "0" */
+ } else if (ucs4 < 0x800) {
+ w = 2;
+ lead = 0xc0; /* "11" */
+ } else if (ucs4 < 0x10000) {
+ w = 3;
+ lead = 0xe0; /* "111" */
+ } else if (ucs4 < 0x200000) {
+ w = 4;
+ lead = 0xf0; /* "1111" */
+ } else {
+ return (NULL);
+ }
+
+ if (dstlen < w)
+ return (NULL);
+
+ /*
+ * construct utf-8
+ */
+ p = dst;
+ for (i = w - 1 ; i >= 1 ; i--) {
+ /* get trailing 6 bits and put it with leading bit as "1" */
+ *(p + i) = (ucs4 & 0x3f) | 0x80;
+ ucs4 >>= 6;
+ }
+ *p = ucs4 | lead;
+
+ *utf8width = w;
+
+ return (p);
+}
+
+static uint32_t
+encode_surrogate(register uint32_t code)
+{
+ return ((((code - 0x10000) << 6) & 0x3ff0000) |
+ ((code - 0x10000) & 0x3ff) | 0xd800dc00);
+}
+
+static uint32_t
+decode_surrogate(register const u_char *ucs)
+{
+ return ((((ucs[0] & 0x3) << 18) | (ucs[1] << 10) |
+ ((ucs[2] & 0x3) << 8) | ucs[3]) + 0x10000);
+}
+
diff --git a/sys/modules/libiconv/Makefile b/sys/modules/libiconv/Makefile
index 6646064..1b51970 100644
--- a/sys/modules/libiconv/Makefile
+++ b/sys/modules/libiconv/Makefile
@@ -3,12 +3,13 @@
.PATH: ${.CURDIR}/../../libkern ${.CURDIR}/../../sys
KMOD= libiconv
-SRCS= iconv.c iconv_xlat.c iconv_xlat16.c
+SRCS= iconv.c iconv_ucs.c iconv_xlat.c iconv_xlat16.c
SRCS+= iconv.h
SRCS+= iconv_converter_if.c iconv_converter_if.h
MFILES= libkern/iconv_converter_if.m
-EXPORT_SYMS= iconv_open \
+EXPORT_SYMS= iconv_add \
+ iconv_open \
iconv_close \
iconv_conv \
iconv_conv_case \
diff --git a/sys/modules/libmchain/Makefile b/sys/modules/libmchain/Makefile
index fd151ec..b8ab48e 100644
--- a/sys/modules/libmchain/Makefile
+++ b/sys/modules/libmchain/Makefile
@@ -11,6 +11,7 @@ EXPORT_SYMS= mb_init \
mb_detach \
mb_fixhdr \
mb_reserve \
+ mb_put_padbyte \
mb_put_uint8 \
mb_put_uint16be \
mb_put_uint16le \
diff --git a/sys/netsmb/smb_conn.c b/sys/netsmb/smb_conn.c
index 2095eb1..2ee851b 100644
--- a/sys/netsmb/smb_conn.c
+++ b/sys/netsmb/smb_conn.c
@@ -444,13 +444,29 @@ smb_vc_create(struct smb_vcspec *vcspec,
goto fail;
if (vcspec->servercs[0]) {
error = (int)iconv_open(vcspec->servercs, vcspec->localcs,
- &vcp->vc_toserver);
+ &vcp->vc_cp_toserver);
if (error)
goto fail;
error = (int)iconv_open(vcspec->localcs, vcspec->servercs,
- &vcp->vc_tolocal);
+ &vcp->vc_cp_tolocal);
if (error)
goto fail;
+ vcp->vc_toserver = vcp->vc_cp_toserver;
+ vcp->vc_tolocal = vcp->vc_cp_tolocal;
+ iconv_add(ENCODING_UNICODE, ENCODING_UNICODE, SMB_UNICODE_NAME);
+ iconv_add(ENCODING_UNICODE, SMB_UNICODE_NAME, ENCODING_UNICODE);
+ error = (int)iconv_open(SMB_UNICODE_NAME, vcspec->localcs,
+ &vcp->vc_ucs_toserver);
+ if (!error) {
+ error = (int)iconv_open(vcspec->localcs, SMB_UNICODE_NAME,
+ &vcp->vc_ucs_tolocal);
+ }
+ if (error) {
+ if (vcp->vc_ucs_toserver)
+ iconv_close(vcp->vc_ucs_toserver);
+ vcp->vc_ucs_toserver = NULL;
+ vcp->vc_ucs_tolocal = NULL;
+ }
}
error = (int)smb_iod_create(vcp);
if (error)
@@ -486,9 +502,17 @@ smb_vc_free(struct smb_connobj *cp)
if (vcp->vc_toupper)
iconv_close(vcp->vc_toupper);
if (vcp->vc_tolocal)
- iconv_close(vcp->vc_tolocal);
+ vcp->vc_tolocal = NULL;
if (vcp->vc_toserver)
- iconv_close(vcp->vc_toserver);
+ vcp->vc_toserver = NULL;
+ if (vcp->vc_cp_tolocal)
+ iconv_close(vcp->vc_cp_tolocal);
+ if (vcp->vc_cp_toserver)
+ iconv_close(vcp->vc_cp_toserver);
+ if (vcp->vc_ucs_tolocal)
+ iconv_close(vcp->vc_ucs_tolocal);
+ if (vcp->vc_ucs_toserver)
+ iconv_close(vcp->vc_ucs_toserver);
smb_co_done(VCTOCP(vcp));
smb_sl_destroy(&vcp->vc_stlock);
free(vcp, M_SMBCONN);
diff --git a/sys/netsmb/smb_conn.h b/sys/netsmb/smb_conn.h
index 370f6cf..94a7a82 100644
--- a/sys/netsmb/smb_conn.h
+++ b/sys/netsmb/smb_conn.h
@@ -242,6 +242,10 @@ struct smb_vc {
void * vc_toupper; /* local charset */
void * vc_toserver; /* local charset to server one */
void * vc_tolocal; /* server charset to local one */
+ void * vc_cp_toserver; /* local charset to server one (using CodePage) */
+ void * vc_cp_tolocal; /* server charset to local one (using CodePage) */
+ void * vc_ucs_toserver; /* local charset to server one (using UCS-2) */
+ void * vc_ucs_tolocal; /* server charset to local one (using UCS-2) */
int vc_number; /* number of this VC from the client side */
int vc_genid;
uid_t vc_uid; /* user id of connection */
@@ -272,6 +276,8 @@ struct smb_vc {
#define SMB_UNICODE_STRINGS(vcp) ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE)
+#define SMB_UNICODE_NAME "UCS-2LE"
+
/*
* smb_share structure describes connection to the given SMB share (tree).
* Connection to share is always built on top of the VC.
diff --git a/sys/netsmb/smb_smb.c b/sys/netsmb/smb_smb.c
index d3fb94a..6c732f9d 100644
--- a/sys/netsmb/smb_smb.c
+++ b/sys/netsmb/smb_smb.c
@@ -121,9 +121,17 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
u_int8_t wc, stime[8], sblen;
u_int16_t dindex, tw, tw1, swlen, bc;
int error, maxqsz;
+ int unicode = SMB_UNICODE_STRINGS(vcp);
+ void * servercharset = vcp->vc_toserver;
+ void * localcharset = vcp->vc_tolocal;
if (smb_smb_nomux(vcp, scred, __func__) != 0)
return EINVAL;
+ /* Disable Unicode for SMB_COM_NEGOTIATE requests */
+ if (unicode) {
+ vcp->vc_toserver = vcp->vc_cp_toserver;
+ vcp->vc_tolocal = vcp->vc_cp_tolocal;
+ }
vcp->vc_hflags = 0;
vcp->vc_hflags2 = 0;
vcp->obj.co_flags &= ~(SMBV_ENCRYPT);
@@ -180,7 +188,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
SMBERROR("Unexpected length of security blob (%d)\n", sblen);
break;
}
- error = md_get_uint16(mdp, &bc);
+ error = md_get_uint16le(mdp, &bc);
if (error)
break;
if (sp->sv_caps & SMB_CAP_EXT_SECURITY)
@@ -193,6 +201,13 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
}
if (sp->sv_sm & SMB_SM_SIGS_REQUIRE)
vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+ if (vcp->vc_ucs_toserver &&
+ sp->sv_caps & SMB_CAP_UNICODE) {
+ /*
+ * They do Unicode.
+ */
+ vcp->obj.co_flags |= SMBV_UNICODE;
+ }
vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
sp->sv_maxtx < 4096 &&
@@ -200,7 +215,13 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
vcp->obj.co_flags |= SMBV_WIN95;
SMBSDEBUG("Win95 detected\n");
}
- } else if (dp->d_id > SMB_DIALECT_CORE) {
+ error = 0;
+ break;
+ }
+ vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS|
+ SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE);
+ unicode = 0;
+ if (dp->d_id > SMB_DIALECT_CORE) {
md_get_uint16le(mdp, &tw);
sp->sv_sm = tw;
md_get_uint16le(mdp, &tw);
@@ -217,7 +238,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
if (swlen > SMB_MAXCHALLENGELEN)
break;
md_get_uint16(mdp, NULL); /* mbz */
- if (md_get_uint16(mdp, &bc) != 0)
+ if (md_get_uint16le(mdp, &bc) != 0)
break;
if (bc < swlen)
break;
@@ -259,6 +280,12 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx);
}
bad:
+ /* Restore Unicode conversion state */
+ if (unicode) {
+ vcp->vc_toserver = servercharset;
+ vcp->vc_tolocal = localcharset;
+ vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
+ }
smb_rq_done(rqp);
return error;
}
@@ -273,9 +300,13 @@ smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
smb_uniptr unipp, ntencpass = NULL;
char *pp, *up, *pbuf, *encpass;
int error, plen, uniplen, ulen, upper;
+ u_int32_t caps = 0;
upper = 0;
+ if (vcp->obj.co_flags & SMBV_UNICODE)
+ caps |= SMB_CAP_UNICODE;
+
again:
vcp->vc_smbuid = SMB_UID_UNKNOWN;
@@ -374,8 +405,7 @@ again:
} else {
mb_put_uint16le(mbp, uniplen);
mb_put_uint32le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ?
- SMB_CAP_UNICODE : 0);
+ mb_put_uint32le(mbp, caps);
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
@@ -477,24 +507,13 @@ smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
upper = 0;
again:
-
-#if 0
/* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */
if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) {
vcp = SSTOVC(ssp);
- if (vcp->vc_toserver) {
- iconv_close(vcp->vc_toserver);
- /* Use NULL until UTF-8 -> ASCII works */
- vcp->vc_toserver = NULL;
- }
- if (vcp->vc_tolocal) {
- iconv_close(vcp->vc_tolocal);
- /* Use NULL until ASCII -> UTF-8 works*/
- vcp->vc_tolocal = NULL;
- }
+ vcp->vc_toserver = vcp->vc_cp_toserver;
+ vcp->vc_tolocal = vcp->vc_cp_tolocal;
vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
}
-#endif
ssp->ss_tid = SMB_TID_UNKNOWN;
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
@@ -559,6 +578,15 @@ again:
ssp->ss_tid = rqp->sr_rptid;
ssp->ss_vcgenid = vcp->vc_genid;
ssp->ss_flags |= SMBS_CONNECTED;
+ /*
+ * If the server can speak Unicode then switch
+ * our converters to do Unicode <--> Local
+ */
+ if (vcp->obj.co_flags & SMBV_UNICODE) {
+ vcp->vc_toserver = vcp->vc_ucs_toserver;
+ vcp->vc_tolocal = vcp->vc_ucs_tolocal;
+ vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
+ }
bad:
if (encpass)
free(encpass, M_SMBTEMP);
diff --git a/sys/netsmb/smb_subr.c b/sys/netsmb/smb_subr.c
index c92f865..3846b75 100644
--- a/sys/netsmb/smb_subr.c
+++ b/sys/netsmb/smb_subr.c
@@ -350,6 +350,8 @@ smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
}
mbp->mb_copy = smb_copy_iconv;
mbp->mb_udata = dp;
+ if (SMB_UNICODE_STRINGS(vcp))
+ mb_put_padbyte(mbp);
return mb_put_mem(mbp, src, size, MB_MCUSTOM);
}
@@ -362,6 +364,8 @@ smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
if (error)
return error;
+ if (SMB_UNICODE_STRINGS(vcp))
+ return mb_put_uint16le(mbp, 0);
return mb_put_uint8(mbp, 0);
}
diff --git a/sys/sys/iconv.h b/sys/sys/iconv.h
index 7ca84b5..671b24e 100644
--- a/sys/sys/iconv.h
+++ b/sys/sys/iconv.h
@@ -47,6 +47,7 @@
#define KICONV_FROM_UPPER 8 /* toupper source character, then convert */
#define KICONV_WCTYPE 16 /* towlower/towupper characters */
+#define ENCODING_UNICODE "UTF-16BE"
#define KICONV_WCTYPE_NAME "_wctype"
/*
@@ -85,7 +86,6 @@ struct iconv_add_out {
__BEGIN_DECLS
-#define ENCODING_UNICODE "UTF-16BE"
#define KICONV_VENDOR_MICSFT 1 /* Microsoft Vendor Code for quirk */
int kiconv_add_xlat_table(const char *, const char *, const u_char *);
@@ -162,6 +162,7 @@ int iconv_convchr(void *handle, const char **inbuf,
size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
int iconv_convchr_case(void *handle, const char **inbuf,
size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype);
+int iconv_add(const char *converter, const char *to, const char *from);
char* iconv_convstr(void *handle, char *dst, const char *src);
void* iconv_convmem(void *handle, void *dst, const void *src, int size);
int iconv_vfs_refcount(const char *fsname);
diff --git a/sys/sys/mchain.h b/sys/sys/mchain.h
index 4ee32e4..b89cbfd 100644
--- a/sys/sys/mchain.h
+++ b/sys/sys/mchain.h
@@ -67,6 +67,7 @@ struct mbuf *mb_detach(struct mbchain *mbp);
int mb_fixhdr(struct mbchain *mbp);
caddr_t mb_reserve(struct mbchain *mbp, int size);
+int mb_put_padbyte(struct mbchain *mbp);
int mb_put_uint8(struct mbchain *mbp, u_int8_t x);
int mb_put_uint16be(struct mbchain *mbp, u_int16_t x);
int mb_put_uint16le(struct mbchain *mbp, u_int16_t x);
OpenPOWER on IntegriCloud