aboutsummaryrefslogtreecommitdiff
path: root/sys/netsmb
diff options
context:
space:
mode:
authorKevin Lo <kevlo@FreeBSD.org>2011-11-18 03:05:20 +0000
committerKevin Lo <kevlo@FreeBSD.org>2011-11-18 03:05:20 +0000
commit41f1dccceb3c3950da343297dc6e7c85086dffbf (patch)
tree91e05f3019c9e61d84d991446d61ad595184fef3 /sys/netsmb
parente8ca9d33da6f7b7ff83dfb15fb032b78f51ec9c0 (diff)
downloadsrc-41f1dccceb3c3950da343297dc6e7c85086dffbf.tar.gz
src-41f1dccceb3c3950da343297dc6e7c85086dffbf.zip
Add unicode support to msdosfs and smbfs; original pathes from imura,
bug fixes by Kuan-Chung Chiu <buganini at gmail dot com>. Tested by me in production for several days at work.
Notes
Notes: svn path=/head/; revision=227650
Diffstat (limited to 'sys/netsmb')
-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
4 files changed, 84 insertions, 22 deletions
diff --git a/sys/netsmb/smb_conn.c b/sys/netsmb/smb_conn.c
index 2095eb19ef55..2ee851bd4aec 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 370f6cfaa7f0..94a7a820ed4e 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 d3fb94aececf..6c732f9d4043 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 c92f865fee86..3846b75f71c1 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);
}