int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) { struct smb_vc *vcp; struct smb_rq rq, *rqp = &rq; struct mbchain *mbp; char *pp, *pbuf, *encpass; int error, plen, caseopt; ssp->ss_tid = SMB_TID_UNKNOWN; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); if (error) return error; vcp = rqp->sr_vc; caseopt = SMB_CS_NONE; if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { plen = 1; pp = ""; pbuf = NULL; encpass = NULL; } else { pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); encpass = malloc(24, M_SMBTEMP, M_WAITOK); iconv_convstr(vcp->vc_toupper, pbuf, smb_share_getpass(ssp)); iconv_convstr(vcp->vc_toserver, pbuf, pbuf); if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { plen = 24; smb_encrypt(pbuf, vcp->vc_ch, encpass); pp = encpass; } else { plen = strlen(pbuf) + 1; pp = pbuf; } } mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); mb_put_uint8(mbp, 0); mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, 0); /* Flags */ mb_put_uint16le(mbp, plen); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_mem(mbp, pp, plen, MB_MSYSTEM); smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt); pp = vcp->vc_srvname; smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt); smb_put_dmem(mbp, vcp, "\\", 1, caseopt); pp = ssp->ss_name; smb_put_dstring(mbp, vcp, pp, caseopt); pp = smb_share_typename(ssp->ss_type); smb_put_dstring(mbp, vcp, pp, caseopt); smb_rq_bend(rqp); error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) goto bad; ssp->ss_tid = rqp->sr_rptid; ssp->ss_vcgenid = vcp->vc_genid; ssp->ss_flags |= SMBS_CONNECTED; bad: if (encpass) free(encpass, M_SMBTEMP); if (pbuf) free(pbuf, M_SMBTEMP); smb_rq_done(rqp); return error; }
int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) { struct smb_dialect *dp; struct smb_sopt *sp = NULL; struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc, stime[8], sblen; u_int16_t dindex, tw, tw1, swlen, bc; int error, maxqsz; if (smb_smb_nomux(vcp, scred, __FUNCTION__) != 0) return EINVAL; vcp->vc_hflags = 0; vcp->vc_hflags2 = 0; vcp->obj.co_flags &= ~(SMBV_ENCRYPT); sp = &vcp->vc_sopt; bzero(sp, sizeof(struct smb_sopt)); error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); smb_rq_wend(rqp); smb_rq_bstart(rqp); for(dp = smb_dialects; dp->d_id != -1; dp++) { mb_put_uint8(mbp, SMB_DT_DIALECT); smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE); } smb_rq_bend(rqp); error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) goto bad; smb_rq_getreply(rqp, &mdp); do { error = md_get_uint8(mdp, &wc); if (error) break; error = md_get_uint16le(mdp, &dindex); if (error) break; if (dindex > 7) { SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex); error = EBADRPC; break; } dp = smb_dialects + dindex; sp->sv_proto = dp->d_id; SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc); error = EBADRPC; if (dp->d_id >= SMB_DIALECT_NTLM0_12) { if (wc != 17) break; md_get_uint8(mdp, &sp->sv_sm); md_get_uint16le(mdp, &sp->sv_maxmux); md_get_uint16le(mdp, &sp->sv_maxvcs); md_get_uint32le(mdp, &sp->sv_maxtx); md_get_uint32le(mdp, &sp->sv_maxraw); md_get_uint32le(mdp, &sp->sv_skey); md_get_uint32le(mdp, &sp->sv_caps); md_get_mem(mdp, stime, 8, MB_MSYSTEM); md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); md_get_uint8(mdp, &sblen); if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) { if (sblen != SMB_MAXCHALLENGELEN) { SMBERROR("Unexpected length of security blob (%d)\n", sblen); break; } error = md_get_uint16(mdp, &bc); if (error) break; if (sp->sv_caps & SMB_CAP_EXT_SECURITY) md_get_mem(mdp, NULL, 16, MB_MSYSTEM); error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM); if (error) break; vcp->vc_chlen = sblen; vcp->obj.co_flags |= SMBV_ENCRYPT; } vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; if (dp->d_id == SMB_DIALECT_NTLM0_12 && sp->sv_maxtx < 4096 && (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) { vcp->obj.co_flags |= SMBV_WIN95; SMBSDEBUG("Win95 detected\n"); } } else if (dp->d_id > SMB_DIALECT_CORE) { md_get_uint16le(mdp, &tw); sp->sv_sm = tw; md_get_uint16le(mdp, &tw); sp->sv_maxtx = tw; md_get_uint16le(mdp, &sp->sv_maxmux); md_get_uint16le(mdp, &sp->sv_maxvcs); md_get_uint16le(mdp, &tw); /* rawmode */ md_get_uint32le(mdp, &sp->sv_skey); if (wc == 13) { /* >= LANMAN1 */ md_get_uint16(mdp, &tw); /* time */ md_get_uint16(mdp, &tw1); /* date */ md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); md_get_uint16le(mdp, &swlen); if (swlen > SMB_MAXCHALLENGELEN) break; md_get_uint16(mdp, NULL); /* mbz */ if (md_get_uint16(mdp, &bc) != 0) break; if (bc < swlen) break; if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) { error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM); if (error) break; vcp->vc_chlen = swlen; vcp->obj.co_flags |= SMBV_ENCRYPT; } } vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; } else { /* an old CORE protocol */ sp->sv_maxmux = 1; } error = 0; } while (0); if (error == 0) { vcp->vc_maxvcs = sp->sv_maxvcs; if (vcp->vc_maxvcs <= 1) { if (vcp->vc_maxvcs == 0) vcp->vc_maxvcs = 1; } if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff) sp->sv_maxtx = 1024; SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz); vcp->vc_txmax = min(sp->sv_maxtx, maxqsz); SMBSDEBUG("TZ = %d\n", sp->sv_tz); SMBSDEBUG("CAPS = %x\n", sp->sv_caps); SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux); SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs); SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw); SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx); } bad: smb_rq_done(rqp); return error; }
static __inline int smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc; int error; u_int16_t residhi, residlo, off, doff; u_int32_t resid; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* no secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to secondary */ mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint32le(mbp, uio->uio_offset); *len = min(SSTOVC(ssp)->vc_rxmax, *len); mb_put_uint16le(mbp, *len); /* MaxCount */ mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */ mb_put_uint32le(mbp, (unsigned)*len >> 16); /* MaxCountHigh */ mb_put_uint16le(mbp, *len); /* Remaining ("obsolete") */ mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); do { error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); off = SMB_HDRLEN; md_get_uint8(mdp, &wc); off++; if (wc != 12) { error = EBADRPC; break; } md_get_uint8(mdp, NULL); off++; md_get_uint8(mdp, NULL); off++; md_get_uint16le(mdp, NULL); off += 2; md_get_uint16le(mdp, NULL); off += 2; md_get_uint16le(mdp, NULL); /* data compaction mode */ off += 2; md_get_uint16le(mdp, NULL); off += 2; md_get_uint16le(mdp, &residlo); off += 2; md_get_uint16le(mdp, &doff); /* data offset */ off += 2; md_get_uint16le(mdp, &residhi); off += 2; resid = (residhi << 16) | residlo; md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); off += 4*2; md_get_uint16le(mdp, NULL); /* ByteCount */ off += 2; if (doff > off) /* pad byte(s)? */ md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); if (resid == 0) { *rresid = resid; break; } error = md_get_uio(mdp, uio, resid); if (error) break; *rresid = resid; } while(0); smb_rq_done(rqp); return (error); }
int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; /* u_int8_t wc; u_int16_t tw, tw1;*/ smb_uniptr unipp, ntencpass = NULL; char *pp, *up, *pbuf, *encpass; int error, plen, uniplen, ulen; vcp->vc_smbuid = SMB_UID_UNKNOWN; if (smb_smb_nomux(vcp, scred, __FUNCTION__) != 0) return EINVAL; error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp); if (error) return error; pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); encpass = malloc(24, M_SMBTEMP, M_WAITOK); if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { iconv_convstr(vcp->vc_toupper, pbuf, smb_vc_getpass(vcp)); iconv_convstr(vcp->vc_toserver, pbuf, pbuf); if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { uniplen = plen = 24; smb_encrypt(pbuf, vcp->vc_ch, encpass); ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); iconv_convstr(vcp->vc_toserver, pbuf, smb_vc_getpass(vcp)); smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass); pp = encpass; unipp = ntencpass; } else { plen = strlen(pbuf) + 1; pp = pbuf; uniplen = plen * 2; ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); smb_strtouni(ntencpass, smb_vc_getpass(vcp)); plen--; uniplen = 0/*-= 2*/; unipp = ntencpass; } } else { /* * In the share security mode password will be used * only in the tree authentication */ pp = ""; plen = 1; unipp = &smb_unieol; uniplen = sizeof(smb_unieol); } smb_rq_wstart(rqp); mbp = &rqp->sr_rq; up = vcp->vc_username; ulen = strlen(up) + 1; mb_put_uint8(mbp, 0xff); mb_put_uint8(mbp, 0); mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx); mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux); mb_put_uint16le(mbp, vcp->vc_number); mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey); mb_put_uint16le(mbp, plen); if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) { mb_put_uint32le(mbp, 0); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_mem(mbp, pp, plen, MB_MSYSTEM); smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); } else { mb_put_uint16le(mbp, uniplen); mb_put_uint32le(mbp, 0); /* reserved */ mb_put_uint32le(mbp, 0); /* my caps */ smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_mem(mbp, pp, plen, MB_MSYSTEM); mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM); smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */ smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */ smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */ smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */ } smb_rq_bend(rqp); if (ntencpass) free(ntencpass, M_SMBTEMP); error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) { if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess) error = EAUTH; goto bad; } vcp->vc_smbuid = rqp->sr_rpuid; bad: free(encpass, M_SMBTEMP); free(pbuf, M_SMBTEMP); smb_rq_done(rqp); return error; }
int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; /* u_int8_t wc; u_int16_t tw, tw1;*/ smb_uniptr unipp, ntencpass = NULL; char *pp, *up, *pbuf, *encpass; int error, plen, uniplen, ulen, upper; upper = 0; again: vcp->vc_smbuid = SMB_UID_UNKNOWN; if (smb_smb_nomux(vcp, scred, __func__) != 0) return EINVAL; error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp); if (error) return error; pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); encpass = malloc(24, M_SMBTEMP, M_WAITOK); if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { /* * We try w/o uppercasing first so Samba mixed case * passwords work. If that fails we come back and try * uppercasing to satisfy OS/2 and Windows for Workgroups. */ if (upper++) { iconv_convstr(vcp->vc_toupper, pbuf, smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/); } else { strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN); pbuf[SMB_MAXPASSWORDLEN] = '\0'; } if (!SMB_UNICODE_STRINGS(vcp)) iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*, SMB_MAXPASSWORDLEN*/); if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { uniplen = plen = 24; smb_encrypt(pbuf, vcp->vc_ch, encpass); ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); if (SMB_UNICODE_STRINGS(vcp)) { strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN); pbuf[SMB_MAXPASSWORDLEN] = '\0'; } else iconv_convstr(vcp->vc_toserver, pbuf, smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/); smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass); pp = encpass; unipp = ntencpass; } else { plen = strlen(pbuf) + 1; pp = pbuf; uniplen = plen * 2; ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); smb_strtouni(ntencpass, smb_vc_getpass(vcp)); plen--; /* * The uniplen is zeroed because Samba cannot deal * with this 2nd cleartext password. This Samba * "bug" is actually a workaround for problems in * Microsoft clients. */ uniplen = 0/*-= 2*/; unipp = ntencpass; } } else { /* * In the share security mode password will be used * only in the tree authentication */ pp = ""; plen = 1; unipp = &smb_unieol; uniplen = 0 /* sizeof(smb_unieol) */; } smb_rq_wstart(rqp); mbp = &rqp->sr_rq; up = vcp->vc_username; ulen = strlen(up) + 1; /* * If userid is null we are attempting anonymous browse login * so passwords must be zero length. */ if (ulen == 1) plen = uniplen = 0; mb_put_uint8(mbp, 0xff); mb_put_uint8(mbp, 0); mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx); mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux); mb_put_uint16le(mbp, vcp->vc_number); mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey); mb_put_uint16le(mbp, plen); if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) { mb_put_uint32le(mbp, 0); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_mem(mbp, pp, plen, MB_MSYSTEM); smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); } 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); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_mem(mbp, pp, plen, MB_MSYSTEM); mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM); smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */ smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */ smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */ smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */ } smb_rq_bend(rqp); if (ntencpass) free(ntencpass, M_SMBTEMP); if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) smb_calcmackey(vcp); error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) { if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess) error = EAUTH; goto bad; } vcp->vc_smbuid = rqp->sr_rpuid; bad: free(encpass, M_SMBTEMP); free(pbuf, M_SMBTEMP); smb_rq_done(rqp); if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER) goto again; return error; }
int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) { struct smb_vc *vcp; struct smb_rq rq, *rqp = &rq; struct mbchain *mbp; char *pp, *pbuf, *encpass; int error, plen, caseopt, upper; 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_hflags2 &= ~SMB_FLAGS2_UNICODE; } #endif ssp->ss_tid = SMB_TID_UNKNOWN; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); if (error) return error; vcp = rqp->sr_vc; caseopt = SMB_CS_NONE; if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { plen = 1; pp = ""; pbuf = NULL; encpass = NULL; } else { pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); encpass = malloc(24, M_SMBTEMP, M_WAITOK); /* * We try w/o uppercasing first so Samba mixed case * passwords work. If that fails we come back and try * uppercasing to satisfy OS/2 and Windows for Workgroups. */ if (upper++) { iconv_convstr(vcp->vc_toupper, pbuf, smb_share_getpass(ssp)/*, SMB_MAXPASSWORDLEN*/); } else { strncpy(pbuf, smb_share_getpass(ssp), SMB_MAXPASSWORDLEN); pbuf[SMB_MAXPASSWORDLEN] = '\0'; } if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { plen = 24; smb_encrypt(pbuf, vcp->vc_ch, encpass); pp = encpass; } else { plen = strlen(pbuf) + 1; pp = pbuf; } } mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); mb_put_uint8(mbp, 0); mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, 0); /* Flags */ mb_put_uint16le(mbp, plen); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_mem(mbp, pp, plen, MB_MSYSTEM); smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt); pp = vcp->vc_srvname; smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt); smb_put_dmem(mbp, vcp, "\\", 1, caseopt); pp = ssp->ss_name; smb_put_dstring(mbp, vcp, pp, caseopt); pp = smb_share_typename(ssp->ss_type); smb_put_dstring(mbp, vcp, pp, caseopt); smb_rq_bend(rqp); error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) goto bad; ssp->ss_tid = rqp->sr_rptid; ssp->ss_vcgenid = vcp->vc_genid; ssp->ss_flags |= SMBS_CONNECTED; bad: if (encpass) free(encpass, M_SMBTEMP); if (pbuf) free(pbuf, M_SMBTEMP); smb_rq_done(rqp); if (error && upper == 1) goto again; return error; }
/* * Perform a full round of TRANS2 request */ static int smb_t2_request_int(struct smb_t2rq *t2p) { struct smb_vc *vcp = t2p->t2_vc; struct smb_cred *scred = t2p->t2_cred; struct mbchain *mbp; struct mdchain *mdp, mbparam, mbdata; struct mbuf *m; struct smb_rq *rqp; int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i; int error, doff, poff, txdcount, txpcount, nmlen; m = t2p->t2_tparam.mb_top; if (m) { md_initm(&mbparam, m); /* do not free it! */ totpcount = m_fixhdr(m); if (totpcount > 0xffff) /* maxvalue for u_short */ return EINVAL; } else totpcount = 0; m = t2p->t2_tdata.mb_top; if (m) { md_initm(&mbdata, m); /* do not free it! */ totdcount = m_fixhdr(m); if (totdcount > 0xffff) return EINVAL; } else totdcount = 0; leftdcount = totdcount; leftpcount = totpcount; txmax = vcp->vc_txmax; error = smb_rq_alloc(t2p->t2_source, t2p->t_name ? SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp); if (error) return error; rqp->sr_flags |= SMBR_MULTIPACKET; t2p->t2_rq = rqp; rqp->sr_t2 = t2p; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); mb_put_uint16le(mbp, t2p->t2_maxpcount); mb_put_uint16le(mbp, t2p->t2_maxdcount); mb_put_uint8(mbp, t2p->t2_maxscount); mb_put_uint8(mbp, 0); /* reserved */ mb_put_uint16le(mbp, 0); /* flags */ mb_put_uint32le(mbp, 0); /* Timeout */ mb_put_uint16le(mbp, 0); /* reserved 2 */ len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1), * and need to decide which parts should go into the first request */ nmlen = t2p->t_name ? strlen(t2p->t_name) : 0; len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } leftpcount -= txpcount; leftdcount -= txdcount; mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint8(mbp, t2p->t2_setupcount); mb_put_uint8(mbp, 0); for (i = 0; i < t2p->t2_setupcount; i++) mb_put_uint16le(mbp, t2p->t2_setupdata[i]); smb_rq_wend(rqp); smb_rq_bstart(rqp); /* TDUNICODE */ if (t2p->t_name) mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM); mb_put_uint8(mbp, 0); /* terminating zero */ len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto freerq; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); /* incredible, but thats it... */ error = smb_rq_enqueue(rqp); if (error) goto freerq; if (leftpcount == 0 && leftdcount == 0) t2p->t2_flags |= SMBT2_ALLSENT; error = smb_t2_reply(t2p); if (error) goto bad; while (leftpcount || leftdcount) { t2p->t2_flags |= SMBT2_SECONDARY; error = smb_rq_new(rqp, t2p->t_name ? SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY); if (error) goto bad; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one, * and need to decide which parts should go into request */ len = ALIGN4(len + 6 * 2 + 2); if (t2p->t_name == NULL) len += 2; if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, totpcount - leftpcount); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint16le(mbp, totdcount - leftdcount); leftpcount -= txpcount; leftdcount -= txdcount; if (t2p->t_name == NULL) mb_put_uint16le(mbp, t2p->t2_fid); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, 0); /* name */ len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); rqp->sr_state = SMBRQ_NOTSENT; error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL); if (error) goto bad; } /* while left params or data */ t2p->t2_flags |= SMBT2_ALLSENT; mdp = &t2p->t2_rdata; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &t2p->t2_rparam; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: smb_iod_removerq(rqp); freerq: smb_rq_done(rqp); if (error) { if (rqp->sr_flags & SMBR_RESTART) t2p->t2_flags |= SMBT2_RESTART; md_done(&t2p->t2_rparam); md_done(&t2p->t2_rdata); } return error; }
/* * Export an "internal" SD into an raw SD (mb chain). * (a.k.a "self-relative" form per. NT docs) * Returns allocated mbchain in mbp. */ int mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd) { uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp; uint32_t owneroff, groupoff, sacloff, dacloff; uint16_t flags; int cnt0, error; cnt0 = mbp->mb_count; owneroff = groupoff = sacloff = dacloff = 0; /* The SD is "self-relative" on the wire. */ flags = sd->sd_flags | SD_SELF_RELATIVE; ERRCHK(mb_put_uint8(mbp, sd->sd_revision)); ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl)); ERRCHK(mb_put_uint16le(mbp, flags)); owneroffp = mb_reserve(mbp, sizeof (*owneroffp)); groupoffp = mb_reserve(mbp, sizeof (*groupoffp)); sacloffp = mb_reserve(mbp, sizeof (*sacloffp)); dacloffp = mb_reserve(mbp, sizeof (*dacloffp)); if (owneroffp == NULL || groupoffp == NULL || sacloffp == NULL || dacloffp == NULL) { error = ENOMEM; goto errout; } /* * These could be marshalled in any order, but * are normally found in the order shown here. */ if (sd->sd_sacl) { sacloff = mbp->mb_count - cnt0; ERRCHK(mb_put_acl(mbp, sd->sd_sacl)); } if (sd->sd_dacl) { dacloff = mbp->mb_count - cnt0; ERRCHK(mb_put_acl(mbp, sd->sd_dacl)); } if (sd->sd_owner) { owneroff = mbp->mb_count - cnt0; ERRCHK(mb_put_sid(mbp, sd->sd_owner)); } if (sd->sd_group) { groupoff = mbp->mb_count - cnt0; ERRCHK(mb_put_sid(mbp, sd->sd_group)); } /* Fill in the offsets */ *owneroffp = htolel(owneroff); *groupoffp = htolel(groupoff); *sacloffp = htolel(sacloff); *dacloffp = htolel(dacloff); /* Success! */ return (0); errout: return (error); }
/* * Perform a full round of TRANS2 request */ static int smb_t2_request_int(struct smb_t2rq *t2p) { struct smb_vc *vcp = t2p->t2_vc; struct smb_cred *scred = t2p->t2_cred; struct mbchain *mbp; struct mdchain *mdp, mbparam, mbdata; mblk_t *m; struct smb_rq *rqp; int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i; int error, doff, poff, txdcount, txpcount, nmlen, nmsize; m = t2p->t2_tparam.mb_top; if (m) { md_initm(&mbparam, m); /* do not free it! */ totpcount = m_fixhdr(m); if (totpcount > 0xffff) /* maxvalue for ushort_t */ return (EINVAL); } else totpcount = 0; m = t2p->t2_tdata.mb_top; if (m) { md_initm(&mbdata, m); /* do not free it! */ totdcount = m_fixhdr(m); if (totdcount > 0xffff) return (EINVAL); } else totdcount = 0; leftdcount = totdcount; leftpcount = totpcount; txmax = vcp->vc_txmax; error = smb_rq_alloc(t2p->t2_source, t2p->t_name ? SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp); if (error) return (error); rqp->sr_timo = smb_timo_default; rqp->sr_flags |= SMBR_MULTIPACKET; t2p->t2_rq = rqp; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); mb_put_uint16le(mbp, t2p->t2_maxpcount); mb_put_uint16le(mbp, t2p->t2_maxdcount); mb_put_uint8(mbp, t2p->t2_maxscount); mb_put_uint8(mbp, 0); /* reserved */ mb_put_uint16le(mbp, 0); /* flags */ mb_put_uint32le(mbp, 0); /* Timeout */ mb_put_uint16le(mbp, 0); /* reserved 2 */ len = mb_fixhdr(mbp); /* * Now we know the size of the trans overhead stuff: * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + nmsize), * where nmsize is the OTW size of the name, including * the unicode null terminator and any alignment. * Use this to decide which parts (and how much) * can go into this request: params, data */ nmlen = t2p->t_name ? t2p->t_name_len : 0; nmsize = nmlen + 1; /* null term. */ if (SMB_UNICODE_STRINGS(vcp)) { nmsize *= 2; /* we know put_dmem will need to align */ nmsize += 1; } len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmsize); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; /* * Other client traffic seems to "ALIGN2" here. The extra * 2 byte pad we use has no observed downside and may be * required for some old servers(?) */ len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } leftpcount -= txpcount; leftdcount -= txdcount; mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint8(mbp, t2p->t2_setupcount); mb_put_uint8(mbp, 0); for (i = 0; i < t2p->t2_setupcount; i++) { mb_put_uint16le(mbp, t2p->t2_setupdata[i]); } smb_rq_wend(rqp); smb_rq_bstart(rqp); if (t2p->t_name) { /* Put the string and terminating null. */ smb_put_dmem(mbp, vcp, t2p->t_name, nmlen + 1, SMB_CS_NONE, NULL); } else { /* nmsize accounts for padding, char size. */ mb_put_mem(mbp, NULL, nmsize, MB_MZERO); } len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto freerq; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); /* incredible, but thats it... */ error = smb_rq_enqueue(rqp); if (error) goto freerq; if (leftpcount || leftdcount) { error = smb_rq_reply(rqp); if (error) goto bad; /* * this is an interim response, ignore it. */ SMBRQ_LOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_UNLOCK(rqp); } while (leftpcount || leftdcount) { error = smb_rq_new(rqp, t2p->t_name ? SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY); if (error) goto bad; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one, * and need to decide which parts should go into request */ len = ALIGN4(len + 6 * 2 + 2); if (t2p->t_name == NULL) len += 2; if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, totpcount - leftpcount); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint16le(mbp, totdcount - leftdcount); leftpcount -= txpcount; leftdcount -= txdcount; if (t2p->t_name == NULL) mb_put_uint16le(mbp, t2p->t2_fid); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, 0); /* name */ len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); error = smb_iod_multirq(rqp); if (error) goto bad; } /* while left params or data */ error = smb_t2_reply(t2p); if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) goto bad; mdp = &t2p->t2_rdata; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &t2p->t2_rparam; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: smb_iod_removerq(rqp); freerq: if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) { if (rqp->sr_flags & SMBR_RESTART) t2p->t2_flags |= SMBT2_RESTART; md_done(&t2p->t2_rparam); md_done(&t2p->t2_rdata); } smb_rq_done(rqp); return (error); }
/* * Perform a full round of NT_TRANSACTION request */ static int smb_nt_request_int(struct smb_ntrq *ntp) { struct smb_vc *vcp = ntp->nt_vc; struct smb_cred *scred = ntp->nt_cred; struct mbchain *mbp; struct mdchain *mdp, mbsetup, mbparam, mbdata; mblk_t *m; struct smb_rq *rqp; int totpcount, leftpcount, totdcount, leftdcount, len, txmax; int error, doff, poff, txdcount, txpcount; int totscount; m = ntp->nt_tsetup.mb_top; if (m) { md_initm(&mbsetup, m); /* do not free it! */ totscount = m_fixhdr(m); if (totscount > 2 * 0xff) return (EINVAL); } else totscount = 0; m = ntp->nt_tparam.mb_top; if (m) { md_initm(&mbparam, m); /* do not free it! */ totpcount = m_fixhdr(m); if (totpcount > 0x7fffffff) return (EINVAL); } else totpcount = 0; m = ntp->nt_tdata.mb_top; if (m) { md_initm(&mbdata, m); /* do not free it! */ totdcount = m_fixhdr(m); if (totdcount > 0x7fffffff) return (EINVAL); } else totdcount = 0; leftdcount = totdcount; leftpcount = totpcount; txmax = vcp->vc_txmax; error = smb_rq_alloc(ntp->nt_source, SMB_COM_NT_TRANSACT, scred, &rqp); if (error) return (error); rqp->sr_timo = smb_timo_default; rqp->sr_flags |= SMBR_MULTIPACKET; ntp->nt_rq = rqp; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint8(mbp, ntp->nt_maxscount); mb_put_uint16le(mbp, 0); /* reserved (flags?) */ mb_put_uint32le(mbp, totpcount); mb_put_uint32le(mbp, totdcount); mb_put_uint32le(mbp, ntp->nt_maxpcount); mb_put_uint32le(mbp, ntp->nt_maxdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2), * and need to decide which parts should go into the first request */ len = ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } leftpcount -= txpcount; leftdcount -= txdcount; mb_put_uint32le(mbp, txpcount); mb_put_uint32le(mbp, poff); mb_put_uint32le(mbp, txdcount); mb_put_uint32le(mbp, doff); mb_put_uint8(mbp, (totscount+1)/2); mb_put_uint16le(mbp, ntp->nt_function); if (totscount) { error = md_get_mbuf(&mbsetup, totscount, &m); SMBSDEBUG("%d:%d:%d\n", error, totscount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); if (totscount & 1) mb_put_uint8(mbp, 0); /* setup is in words */ } smb_rq_wend(rqp); smb_rq_bstart(rqp); len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto freerq; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); /* incredible, but thats it... */ error = smb_rq_enqueue(rqp); if (error) goto freerq; if (leftpcount || leftdcount) { error = smb_rq_reply(rqp); if (error) goto bad; /* * this is an interim response, ignore it. */ SMBRQ_LOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_UNLOCK(rqp); } while (leftpcount || leftdcount) { error = smb_rq_new(rqp, SMB_COM_NT_TRANSACT_SECONDARY); if (error) goto bad; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_mem(mbp, NULL, 3, MB_MZERO); mb_put_uint32le(mbp, totpcount); mb_put_uint32le(mbp, totdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 6 * 4 + 2) * and need to decide which parts should go into request */ len = ALIGN4(len + 6 * 4 + 2); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } mb_put_uint32le(mbp, txpcount); mb_put_uint32le(mbp, poff); mb_put_uint32le(mbp, totpcount - leftpcount); mb_put_uint32le(mbp, txdcount); mb_put_uint32le(mbp, doff); mb_put_uint32le(mbp, totdcount - leftdcount); leftpcount -= txpcount; leftdcount -= txdcount; smb_rq_wend(rqp); smb_rq_bstart(rqp); len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); error = smb_iod_multirq(rqp); if (error) goto bad; } /* while left params or data */ error = smb_nt_reply(ntp); if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) goto bad; mdp = &ntp->nt_rdata; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &ntp->nt_rparam; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: smb_iod_removerq(rqp); freerq: if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) { if (rqp->sr_flags & SMBR_RESTART) ntp->nt_flags |= SMBT2_RESTART; md_done(&ntp->nt_rparam); md_done(&ntp->nt_rdata); } smb_rq_done(rqp); return (error); }
static int smbfs_smb_search(struct smbfs_fctx *ctx) { struct smb_vc *vcp = SSTOVC(ctx->f_ssp); struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc, bt; u_int16_t ec, dlen, bc; int maxent, error; maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); if (ctx->f_rq) { smb_rq_done(ctx->f_rq); ctx->f_rq = NULL; } error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); if (error) return error; ctx->f_rq = rqp; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint16le(mbp, maxent); /* max entries to return */ mb_put_uint16le(mbp, ctx->f_attrmask); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); if (error) return error; mb_put_uint8(mbp, SMB_DT_VARIABLE); mb_put_uint16le(mbp, 0); /* context length */ ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; } else { mb_put_uint8(mbp, 0); /* file name length */ mb_put_uint8(mbp, SMB_DT_VARIABLE); mb_put_uint16le(mbp, SMB_SKEYLEN); mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); } smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) { if (error == ENOENT) ctx->f_flags |= SMBFS_RDD_EOF; return error; } smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 1) return EBADRPC; md_get_uint16le(mdp, &ec); if (ec == 0) return ENOENT; ctx->f_ecnt = ec; md_get_uint16le(mdp, &bc); if (bc < 3) return EBADRPC; bc -= 3; md_get_uint8(mdp, &bt); if (bt != SMB_DT_VARIABLE) return EBADRPC; md_get_uint16le(mdp, &dlen); if (dlen != bc || dlen % SMB_DENTRYLEN != 0) return EBADRPC; return 0; }
/* * This call is used to fetch FID for directories. For normal files, * SMB_COM_OPEN is used. */ int smbfs_smb_ntcreatex(struct smbnode *np, int accmode, struct smb_cred *scred) { struct smb_rq *rqp; struct smb_share *ssp = np->n_mount->sm_share; struct mbchain *mbp; struct mdchain *mdp; int error; u_int8_t wc; u_int8_t *nmlen; u_int16_t flen; KASSERT(SMBTOV(np)->v_type == VDIR); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* Secondary command; 0xFF = None */ mb_put_uint8(mbp, 0); /* Reserved (must be 0) */ mb_put_uint16le(mbp, 0); /* Off to next cmd WordCount */ mb_put_uint8(mbp, 0); /* Reserved (must be 0) */ nmlen = mb_reserve(mbp, sizeof(u_int16_t)); /* Length of Name[] in bytes */ mb_put_uint32le(mbp, SMB_FL_CANONICAL_PATHNAMES); /* Flags - Create bit set */ mb_put_uint32le(mbp, 0); /* If nonzero, open relative to this */ mb_put_uint32le(mbp, NT_FILE_LIST_DIRECTORY); /* Access mask */ mb_put_uint32le(mbp, 0); /* Low 32bit */ mb_put_uint32le(mbp, 0); /* Hi 32bit */ /* Initial allocation size */ mb_put_uint32le(mbp, 0); /* File attributes */ mb_put_uint32le(mbp, NT_FILE_SHARE_READ|NT_FILE_SHARE_WRITE); /* Type of share access */ mb_put_uint32le(mbp, NT_OPEN_EXISTING); /* Create disposition - just open */ mb_put_uint32le(mbp, NT_FILE_DIRECTORY_FILE); /* Options to use if creating a file */ mb_put_uint32le(mbp, 0); /* Security QOS information */ mb_put_uint8(mbp, 0); /* Security tracking mode flags */ smb_rq_wend(rqp); smb_rq_bstart(rqp); error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); if (error) return error; /* Windows XP seems to include the final zero. Better do that too. */ mb_put_uint8(mbp, 0); flen = mbp->mb_count; SMBRQ_PUTLE16(nmlen, flen); smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) goto bad; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); /* WordCount - check? */ md_get_uint8(mdp, NULL); /* AndXCommand */ md_get_uint8(mdp, NULL); /* Reserved - must be zero */ md_get_uint16(mdp, NULL); /* Offset to next cmd WordCount */ md_get_uint8(mdp, NULL); /* Oplock level granted */ md_get_uint16(mdp, &np->n_fid); /* FID */ /* ignore rest */ bad: smb_rq_done(rqp); return (error); }
/* * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect */ static int smbfs_smb_trans2find2(struct smbfs_fctx *ctx) { struct smb_t2rq *t2p; struct smb_vc *vcp = SSTOVC(ctx->f_ssp); struct mbchain *mbp; struct mdchain *mdp; u_int16_t tw, flags; int error; if (ctx->f_t2) { smb_t2_done(ctx->f_t2); ctx->f_t2 = NULL; } ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; flags = 8 | 2; /* <resume> | <close if EOS> */ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { flags |= 1; /* close search after this request */ ctx->f_flags |= SMBFS_RDD_NOCLOSE; } if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, ctx->f_scred, &t2p); if (error) return error; ctx->f_t2 = t2p; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_uint16le(mbp, ctx->f_attrmask); mb_put_uint16le(mbp, ctx->f_limit); mb_put_uint16le(mbp, flags); mb_put_uint16le(mbp, ctx->f_infolevel); mb_put_uint32le(mbp, 0); error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); if (error) return error; } else { error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, ctx->f_scred, &t2p); if (error) return error; ctx->f_t2 = t2p; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_mem(mbp, (void *)&ctx->f_Sid, 2, MB_MSYSTEM); mb_put_uint16le(mbp, ctx->f_limit); mb_put_uint16le(mbp, ctx->f_infolevel); 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); else mb_put_uint8(mbp, 0); /* resume file name */ #if 0 struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 200 * 1000; /* 200ms */ if (vcp->vc_flags & SMBC_WIN95) { /* * some implementations suggests to sleep here * for 200ms, due to the bug in the Win95. * I've didn't notice any problem, but put code * for it. */ tsleep(&flags, PVFS, "fix95", tvtohz(&tv)); } #endif } t2p->t2_maxpcount = 5 * 2; t2p->t2_maxdcount = vcp->vc_txmax; error = smb_t2_request(t2p); if (error) return error; mdp = &t2p->t2_rparam; if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) return error; ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; } if ((error = md_get_uint16le(mdp, &tw)) != 0) return error; ctx->f_ecnt = tw; if ((error = md_get_uint16le(mdp, &tw)) != 0) return error; if (tw) ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; if ((error = md_get_uint16le(mdp, &tw)) != 0) return error; if ((error = md_get_uint16le(mdp, &tw)) != 0) return error; if (ctx->f_ecnt == 0) { ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; return ENOENT; } ctx->f_rnameofs = tw; mdp = &t2p->t2_rdata; KASSERT(mdp->md_top != NULL); KASSERT(mdp->md_top->m_len != 0); ctx->f_eofs = 0; return 0; }