From 41f1dccceb3c3950da343297dc6e7c85086dffbf Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Fri, 18 Nov 2011 03:05:20 +0000 Subject: Add unicode support to msdosfs and smbfs; original pathes from imura, bug fixes by Kuan-Chung Chiu . Tested by me in production for several days at work. --- sys/netsmb/smb_conn.c | 32 ++++++++++++++++++++++---- sys/netsmb/smb_conn.h | 6 +++++ sys/netsmb/smb_smb.c | 64 ++++++++++++++++++++++++++++++++++++--------------- sys/netsmb/smb_subr.c | 4 ++++ 4 files changed, 84 insertions(+), 22 deletions(-) (limited to 'sys/netsmb') 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); } -- cgit v1.2.3