static int smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred) { struct smb_t2rq *t2p; struct smb_share *ssp = np->n_mount->sm_share; struct mbchain *mbp; int error; error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, scred, &t2p); if (error) return error; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO); mb_put_uint32le(mbp, 0); mbp = &t2p->t2_tdata; mb_init(mbp); mb_put_int64le(mbp, newsize); mb_put_uint32le(mbp, 0); /* padding */ mb_put_uint16le(mbp, 0); t2p->t2_maxpcount = 2; t2p->t2_maxdcount = 0; error = smb_t2_request(t2p); smb_t2_done(t2p); return error; }
/* * NT level. Specially for win9x */ int smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, struct timespec *atime, struct smb_cred *scred) { struct smb_t2rq *t2p; struct smb_share *ssp = np->n_mount->sm_share; struct smb_vc *vcp = SSTOVC(ssp); struct mbchain *mbp; int64_t tm; int error, tzoff; /* * SMB_SET_FILE_BASIC_INFO isn't supported for * SMB_TRANS2_SET_PATH_INFORMATION, * so use SMB_SET_FILE_BASIC_INFORMATION instead, * but it requires SMB_CAP_INFOLEVEL_PASSTHRU capability. */ if ((SMB_CAPS(vcp) & SMB_CAP_INFOLEVEL_PASSTHRU) == 0) return smbfs_smb_setptime2(np, mtime, atime, attr, scred); error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, scred, &t2p); if (error) return error; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFORMATION); mb_put_uint32le(mbp, 0); /* MBZ */ error = smbfs_fullpath(mbp, vcp, np, NULL, 0); if (error) { smb_t2_done(t2p); return error; } tzoff = vcp->vc_sopt.sv_tz; mbp = &t2p->t2_tdata; mb_init(mbp); mb_put_int64le(mbp, 0); /* creation time */ if (atime) { smb_time_local2NT(atime, tzoff, &tm); } else tm = 0; mb_put_int64le(mbp, tm); if (mtime) { smb_time_local2NT(mtime, tzoff, &tm); } else tm = 0; mb_put_int64le(mbp, tm); mb_put_int64le(mbp, tm); /* change time */ mb_put_uint32le(mbp, attr); /* attr */ mb_put_uint32le(mbp, 0); /* padding */ t2p->t2_maxpcount = 2; t2p->t2_maxdcount = 0; error = smb_t2_request(t2p); smb_t2_done(t2p); return error; }
static inline int smb_smb_writex(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; int error; u_int8_t wc; u_int16_t resid; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_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, (void *)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ mb_put_uint16le(mbp, 0); /* !write-thru */ mb_put_uint16le(mbp, 0); *len = min(SSTOVC(ssp)->vc_wxmax, *len); mb_put_uint16le(mbp, *len >> 16); mb_put_uint16le(mbp, *len); mb_put_uint16le(mbp, 64); /* data offset from header start */ mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ smb_rq_wend(rqp); smb_rq_bstart(rqp); do { mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */ error = mb_put_uio(mbp, uio, *len); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 6) { error = EBADRPC; break; } md_get_uint8(mdp, NULL); md_get_uint8(mdp, NULL); md_get_uint16(mdp, NULL); md_get_uint16le(mdp, &resid); *rresid = resid; } while(0); smb_rq_done(rqp); return (error); }
/* * Note, win95 doesn't support this call. */ int smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, struct timespec *atime, int attr, struct smb_cred *scred) { struct smb_t2rq *t2p; struct smb_share *ssp = np->n_mount->sm_share; struct smb_vc *vcp = SSTOVC(ssp); struct mbchain *mbp; u_int16_t date, time; int error, tzoff; error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, scred, &t2p); if (error) return error; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_uint16le(mbp, SMB_INFO_STANDARD); mb_put_uint32le(mbp, 0); /* MBZ */ /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ error = smbfs_fullpath(mbp, vcp, np, NULL, 0); if (error) { smb_t2_done(t2p); return error; } tzoff = vcp->vc_sopt.sv_tz; mbp = &t2p->t2_tdata; mb_init(mbp); mb_put_uint32le(mbp, 0); /* creation time */ if (atime) smb_time_unix2dos(atime, tzoff, &date, &time, NULL); else time = date = 0; mb_put_uint16le(mbp, date); mb_put_uint16le(mbp, time); if (mtime) smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); else time = date = 0; mb_put_uint16le(mbp, date); mb_put_uint16le(mbp, time); mb_put_uint32le(mbp, 0); /* file size */ mb_put_uint32le(mbp, 0); /* allocation unit size */ mb_put_uint16le(mbp, attr); /* DOS attr */ mb_put_uint32le(mbp, 0); /* EA size */ t2p->t2_maxpcount = 5 * 2; t2p->t2_maxdcount = vcp->vc_txmax; error = smb_t2_request(t2p); smb_t2_done(t2p); return error; }
/* * If both dir and name are NULL, then in target there's already a looked-up * entry that wants to be opened. */ int ncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp,int namelen, char *name, int open_create_mode, u_int32_t create_attributes, int desired_acc_rights, struct ncp_open_info *nop, struct thread *td,struct ucred *cred) { struct ncp_conn *conn=NWFSTOCONN(nmp); struct ncp_rq *rqp; u_int16_t search_attribs = SA_ALL & (~SA_SUBDIR_FILES); u_int8_t volnum; u_int32_t dirent; int error; error = ncp_rq_alloc(87, conn, td, cred, &rqp); if (error) return error; volnum = nmp->n_volume; dirent = VTONW(dvp)->n_fid.f_id; if ((create_attributes & aDIR) != 0) { search_attribs |= SA_SUBDIR_FILES; } mb_put_uint8(&rqp->rq, 1);/* subfunction */ mb_put_uint8(&rqp->rq, nmp->name_space); mb_put_uint8(&rqp->rq, open_create_mode); mb_put_uint16le(&rqp->rq, search_attribs); mb_put_uint32le(&rqp->rq, IM_ALL); mb_put_uint32le(&rqp->rq, create_attributes); /* * The desired acc rights seem to be the inherited rights mask for * directories */ mb_put_uint16le(&rqp->rq, desired_acc_rights); ncp_rq_dbase_path(rqp, volnum, dirent, namelen, name, &nmp->m.nls); error = ncp_request(rqp); if (error) { if (error == NWE_FILE_NO_CREATE_PRIV) error = EACCES; return error; } md_get_uint32le(&rqp->rp, &nop->origfh); md_get_uint8(&rqp->rp, &nop->action); md_get_uint8(&rqp->rp, NULL); /* skip */ error = ncp_extract_file_info(nmp, rqp, &nop->fattr, 1); ncp_rq_done(rqp); ConvertToNWfromDWORD(nop->origfh, &nop->fh); return error; }
int ncp_search_for_file_or_subdir(struct nwmount *nmp, struct nw_search_seq *seq, struct nw_entry_info *target, struct thread *td,struct ucred *cred) { struct ncp_conn *conn = NWFSTOCONN(nmp); struct ncp_rq *rqp; int error; error = ncp_rq_alloc(87, conn, td, cred, &rqp); if (error) return error; mb_put_uint8(&rqp->rq, 3); /* subfunction */ mb_put_uint8(&rqp->rq, nmp->name_space); mb_put_uint8(&rqp->rq, 0); /* data stream */ mb_put_uint16le(&rqp->rq, 0xffff); /* Search attribs */ mb_put_uint32le(&rqp->rq, IM_ALL); /* return info mask */ mb_put_mem(&rqp->rq, (caddr_t)seq, 9, MB_MSYSTEM); mb_put_uint8(&rqp->rq, 2); /* 2 byte pattern */ mb_put_uint8(&rqp->rq, 0xff); /* following is a wildcard */ mb_put_uint8(&rqp->rq, '*'); rqp->nr_minrplen = sizeof(*seq) + 1 + NCP_INFOSZ + 1; error = ncp_request(rqp); if (error) return error; md_get_mem(&rqp->rp, (caddr_t)seq, sizeof(*seq), MB_MSYSTEM); md_get_uint8(&rqp->rp, NULL); /* skip */ error = ncp_extract_file_info(nmp, rqp, target, 1); ncp_rq_done(rqp); return error; }
/* * Returns information for a (one-component) name relative to the specified * directory. */ int ncp_obtain_info(struct nwmount *nmp, u_int32_t dirent, int namelen, char *path, struct nw_entry_info *target, struct thread *td,struct ucred *cred) { struct ncp_conn *conn=NWFSTOCONN(nmp); struct ncp_rq *rqp; int error; u_char volnum = nmp->n_volume, ns; if (target == NULL) { NCPFATAL("target == NULL\n"); return EINVAL; } ns = (path == NULL || path[0] == 0) ? NW_NS_DOS : nmp->name_space; error = ncp_rq_alloc(87, conn, td, cred, &rqp); if (error) return error; mb_put_uint8(&rqp->rq, 6); /* subfunction */ mb_put_uint8(&rqp->rq, ns); mb_put_uint8(&rqp->rq, ns); /* DestNameSpace */ mb_put_uint16le(&rqp->rq, 0xff); /* get all */ mb_put_uint32le(&rqp->rq, IM_ALL); ncp_rq_dbase_path(rqp, volnum, dirent, namelen, path, &nmp->m.nls); error = ncp_request(rqp); if (error) return error; error = ncp_extract_file_info(nmp, rqp, target, path != NULL); ncp_rq_done(rqp); return error; }
int smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; u_long time; int error; rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); if (error) { free(rqp, M_SMBFSDATA); return error; } smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); if (mtime) { smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); } else time = 0; mb_put_uint32le(mbp, time); smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); error = smb_rq_simple(rqp); smb_rq_done(rqp); free(rqp, M_SMBFSDATA); return error; }
static int mb_put_sid(mbchain_t *mbp, i_ntsid_t *sid) { uint32_t *subauthp; int error, i; if (sid == NULL) return (EINVAL); ERRCHK(mb_put_uint8(mbp, sid->sid_revision)); ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount)); ERRCHK(mb_put_mem(mbp, sid->sid_authority, 6, MB_MSYSTEM)); subauthp = &sid->sid_subauthvec[0]; for (i = 0; i < sid->sid_subauthcount; i++) { ERRCHK(mb_put_uint32le(mbp, *subauthp)); subauthp++; } /* Success! */ return (0); errout: return (error); }
/* * Given a request with it's body already composed, * rewind to the start and fill in the SMB header. * This is called after the request is enqueued, * so we have the final MID, seq num. etc. */ void smb_rq_fillhdr(struct smb_rq *rqp) { struct mbchain mbtmp, *mbp = &mbtmp; mblk_t *m; /* * Fill in the SMB header using a dup of the first mblk, * which points at the same data but has its own wptr, * so we can rewind without trashing the message. */ m = dupb(rqp->sr_rq.mb_top); m->b_wptr = m->b_rptr; /* rewind */ mb_initm(mbp, m); mb_put_mem(mbp, SMB_SIGNATURE, 4, MB_MSYSTEM); mb_put_uint8(mbp, rqp->sr_cmd); mb_put_uint32le(mbp, 0); /* status */ mb_put_uint8(mbp, rqp->sr_rqflags); mb_put_uint16le(mbp, rqp->sr_rqflags2); mb_put_uint16le(mbp, 0); /* pid-high */ mb_put_mem(mbp, NULL, 8, MB_MZERO); /* MAC sig. (later) */ mb_put_uint16le(mbp, 0); /* reserved */ mb_put_uint16le(mbp, rqp->sr_rqtid); mb_put_uint16le(mbp, rqp->sr_pid); mb_put_uint16le(mbp, rqp->sr_rquid); mb_put_uint16le(mbp, rqp->sr_mid); /* This will free the mblk from dupb. */ mb_done(mbp); }
int smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; u_long xtime; int error; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); if (mtime) { smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &xtime); } else xtime = 0; mb_put_uint32le(mbp, xtime); smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); error = smb_rq_simple(rqp); smb_rq_done(rqp); return error; }
int smbfs_smb_setfsize(struct smbnode *np, u_quad_t newsize, struct smb_cred *scred) { struct smb_share *ssp = np->n_mount->sm_share; struct smb_rq *rqp; struct mbchain *mbp; int error; if (newsize >= (1LL << 32)) { if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES)) return EFBIG; return smbfs_smb_seteof(np, (int64_t)newsize, scred); } error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint16le(mbp, 0); mb_put_uint32le(mbp, newsize); mb_put_uint16le(mbp, 0); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, 0); smb_rq_bend(rqp); error = smb_rq_simple(rqp); smb_rq_done(rqp); return error; }
int ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp, u_int32_t info_mask, struct nw_modify_dos_info *info, struct thread *td,struct ucred *cred) { struct nwnode *np=VTONW(vp); struct ncp_rq *rqp; u_int8_t volnum = nmp->n_volume; u_int32_t dirent = np->n_fid.f_id; struct ncp_conn *conn=NWFSTOCONN(nmp); int error; error = ncp_rq_alloc(87, conn, td, cred, &rqp); if (error) return error; mb_put_uint8(&rqp->rq, 7); /* subfunction */ mb_put_uint8(&rqp->rq, nmp->name_space); mb_put_uint8(&rqp->rq, 0); /* reserved */ mb_put_uint16le(&rqp->rq, SA_ALL); /* search attribs: all */ mb_put_uint32le(&rqp->rq, info_mask); mb_put_mem(&rqp->rq, (caddr_t)info, sizeof(*info), MB_MSYSTEM); ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL); error = ncp_request(rqp); if (!error) ncp_rq_done(rqp); return error; }
int smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo) { struct smb_rq *rqp; struct mbchain *mbp; int error; error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp); if (error) return (error); mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, 1); /* echo count */ smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes)); smb_rq_bend(rqp); /* * Note: the IOD calls this, so * this request must not wait for * connection state changes, etc. */ rqp->sr_flags |= SMBR_NORECONNECT; error = smb_rq_simple_timed(rqp, timo); SMBSDEBUG("%d\n", error); smb_rq_done(rqp); return (error); }
int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) { struct smb_share *ssp = np->n_mount->sm_share; struct smb_rq *rqp; struct mbchain *mbp; int error; if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) { np->n_flag |= NFLUSHWIRE; return (0); } rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); if (error) { free(rqp, M_SMBFSDATA); return error; } smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint16le(mbp, 0); mb_put_uint32le(mbp, newsize); mb_put_uint16le(mbp, 0); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, 0); smb_rq_bend(rqp); error = smb_rq_simple(rqp); smb_rq_done(rqp); free(rqp, M_SMBFSDATA); return error; }
int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) { struct smb_share *ssp = np->n_mount->sm_share; struct smb_rq rq, *rqp = &rq; struct mbchain *mbp; int error; error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint16le(mbp, 0); mb_put_uint32le(mbp, newsize); mb_put_uint16le(mbp, 0); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, 0); smb_rq_bend(rqp); error = smb_rq_simple(rqp); smb_rq_done(rqp); return error; }
int smbio_close_file(void *ctx, int fid) { struct smb_usr_rq *rqp; mbchain_t mbp; int error; u_int16_t fid16 = fid; error = smb_usr_rq_init(ctx, SMB_COM_CLOSE, 0, &rqp); if (error) return error; mbp = smb_usr_rq_getrequest(rqp); smb_usr_rq_wstart(rqp); mb_put_uint16le(mbp, fid16); /* * Never set the modify time on close. Just a really bad idea! * * Leach and SNIA docs say to send zero here. X/Open says * 0 and -1 both are leaving timestamp up to the server. * Win9x treats zero as a real time-to-be-set! We send -1, * same as observed with smbclient. */ mb_put_uint32le(mbp, -1); smb_usr_rq_wend(rqp); smb_usr_rq_bstart(rqp); smb_usr_rq_bend(rqp); error = smb_usr_rq_simple(rqp); smb_usr_rq_done(rqp); return error; }
static int smb_rq_new(struct smb_rq *rqp, u_char cmd) { struct smb_vc *vcp = rqp->sr_vc; struct mbchain *mbp = &rqp->sr_rq; int error; rqp->sr_sendcnt = 0; mb_done(mbp); md_done(&rqp->sr_rp); error = mb_init(mbp); if (error) return error; mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM); mb_put_uint8(mbp, cmd); mb_put_uint32le(mbp, 0); /* DosError */ mb_put_uint8(mbp, vcp->vc_hflags); mb_put_uint16le(mbp, vcp->vc_hflags2); mb_put_mem(mbp, tzero, 12, MB_MSYSTEM); rqp->sr_rqtid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t)); mb_put_uint16le(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/); rqp->sr_rquid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t)); mb_put_uint16le(mbp, rqp->sr_mid); return 0; }
/* * NT level. Specially for win9x */ int smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, struct timespec *atime, struct smb_cred *scred) { struct smb_t2rq *t2p; struct smb_share *ssp = np->n_mount->sm_share; struct smb_vc *vcp = SSTOVC(ssp); struct mbchain *mbp; int64_t tm; int error, tzoff; error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, scred, &t2p); if (error) return error; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); mb_put_uint32le(mbp, 0); /* MBZ */ /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ error = smbfs_fullpath(mbp, vcp, np, NULL, 0); if (error) { smb_t2_done(t2p); return error; } tzoff = vcp->vc_sopt.sv_tz; mbp = &t2p->t2_tdata; mb_init(mbp); mb_put_int64le(mbp, 0); /* creation time */ if (atime) { smb_time_local2NT(atime, tzoff, &tm); } else tm = 0; mb_put_int64le(mbp, tm); if (mtime) { smb_time_local2NT(mtime, tzoff, &tm); } else tm = 0; mb_put_int64le(mbp, tm); mb_put_int64le(mbp, tm); /* change time */ mb_put_uint32le(mbp, attr); /* attr */ t2p->t2_maxpcount = 24; t2p->t2_maxdcount = 56; error = smb_t2_request(t2p); smb_t2_done(t2p); return error; }
static int smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; int error; uint32_t off32; uint16_t cnt, rcnt, todo; uint8_t wc; ASSERT(uiop->uio_loffset <= UINT32_MAX); off32 = (uint32_t)uiop->uio_loffset; ASSERT(*lenp <= UINT16_MAX); cnt = (uint16_t)*lenp; /* This next is an "estimate" of planned writes. */ todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); if (error) return (error); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint16le(mbp, fid); mb_put_uint16le(mbp, cnt); mb_put_uint32le(mbp, off32); mb_put_uint16le(mbp, todo); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, cnt); error = mb_put_uio(mbp, uiop, *lenp); if (error) goto out; smb_rq_bend(rqp); if (timo == 0) timo = smb_timo_write; error = smb_rq_simple_timed(rqp, timo); if (error) goto out; smb_rq_getreply(rqp, &mdp); error = md_get_uint8(mdp, &wc); if (error) goto out; if (wc != 1) { error = EBADRPC; goto out; } error = md_get_uint16le(mdp, &rcnt); if (error) goto out; *lenp = rcnt; out: smb_rq_done(rqp); return (error); }
static inline int smb_smb_read(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int16_t resid, bc; u_int8_t wc; int error, rlen, blksz; /* Cannot read at/beyond 4G */ if (uio->uio_offset >= (1LL << 32)) return (EFBIG); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); if (error) return error; blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; rlen = *len = min(blksz, *len); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint16le(mbp, rlen); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); 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); md_get_uint8(mdp, &wc); if (wc != 5) { error = EBADRPC; break; } md_get_uint16le(mdp, &resid); md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); md_get_uint16le(mdp, &bc); md_get_uint8(mdp, NULL); /* ignore buffer type */ md_get_uint16le(mdp, &resid); 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; }
/* * Setup a request for NT DIRECTORY CHANGE NOTIFY. */ int smbfs_smb_nt_dirnotify_setup(struct smbnode *dnp, struct smb_rq **rqpp, struct smb_cred *scred, void (*notifyhook)(void *), void *notifyarg) { struct smb_rq *rqp; struct smb_share *ssp = dnp->n_mount->sm_share; struct mbchain *mbp; int error; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_TRANSACT, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* Max setup words to return */ mb_put_uint16le(mbp, 0); /* Flags (according to Samba) */ mb_put_uint32le(mbp, 0); /* Total parameter bytes being sent*/ mb_put_uint32le(mbp, 0); /* Total data bytes being sent */ mb_put_uint32le(mbp, 10*1024); /* Max parameter bytes to return */ mb_put_uint32le(mbp, 0); /* Max data bytes to return */ mb_put_uint32le(mbp, 0); /* Parameter bytes sent this buffer */ mb_put_uint32le(mbp, 0); /* Offset (from h. start) to Param */ mb_put_uint32le(mbp, 0); /* Data bytes sent this buffer */ mb_put_uint32le(mbp, 0); /* Offset (from h. start) to Data */ mb_put_uint8(mbp, 4); /* Count of setup words */ mb_put_uint16le(mbp, SMB_NTTRANS_NOTIFY_CHANGE); /* Trans func code */ /* NT TRANSACT NOTIFY CHANGE: Request Change Notification */ mb_put_uint32le(mbp, FILE_NOTIFY_CHANGE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES| FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE| FILE_NOTIFY_CHANGE_CREATION); /* CompletionFilter */ mb_put_mem(mbp, (void *)&dnp->n_fid, 2, MB_MSYSTEM); /* FID */ mb_put_uint8(mbp, 0); /* WatchTree - Watch all subdirs too */ mb_put_uint8(mbp, 0); /* Reserved - must be zero */ smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); /* No timeout */ rqp->sr_timo = -1; smb_rq_setcallback(rqp, notifyhook, notifyarg); error = smb_rq_enqueue(rqp); if (!error) *rqpp = rqp; else smb_rq_done(rqp); return (error); }
/* * Set DOS file attributes. * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on. */ int smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, struct timespec *atime, struct smb_cred *scred) { struct smb_t2rq *t2p; struct smb_share *ssp = np->n_mount->sm_share; struct mbchain *mbp; int64_t tm; int error, svtz; error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, scred, &t2p); if (error) return error; svtz = SSTOVC(ssp)->vc_sopt.sv_tz; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); mb_put_uint32le(mbp, 0); mbp = &t2p->t2_tdata; mb_init(mbp); mb_put_int64le(mbp, 0); /* creation time */ if (atime) { smb_time_local2NT(atime, svtz, &tm); } else tm = 0; mb_put_int64le(mbp, tm); if (mtime) { smb_time_local2NT(mtime, svtz, &tm); } else tm = 0; mb_put_int64le(mbp, tm); mb_put_int64le(mbp, tm); /* change time */ mb_put_uint16le(mbp, attr); mb_put_uint32le(mbp, 0); /* padding */ mb_put_uint16le(mbp, 0); t2p->t2_maxpcount = 2; t2p->t2_maxdcount = 0; error = smb_t2_request(t2p); smb_t2_done(t2p); return error; }
static inline int smb_smb_write(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int16_t resid; u_int8_t wc; int error, blksz; /* Cannot write at/beyond 4G */ if (uio->uio_offset >= (1LL << 32)) return (EFBIG); blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; if (blksz > 0xffff) blksz = 0xffff; resid = *len = min(blksz, *len); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint16le(mbp, resid); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, resid); do { error = mb_put_uio(mbp, uio, resid); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 1) { error = EBADRPC; break; } md_get_uint16le(mdp, &resid); *rresid = resid; } while(0); smb_rq_done(rqp); return error; }
static __inline int smb_smb_write(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_int16_t resid; u_int8_t wc; int error, blksz; /* write data must be real */ KKASSERT(uio->uio_segflg != UIO_NOCOPY); blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; if (blksz > 0xffff) blksz = 0xffff; resid = *len = min(blksz, *len); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint16le(mbp, resid); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint16le(mbp, (unsigned short)szmin(uio->uio_resid, 0xffff)); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, resid); do { error = mb_put_uio(mbp, uio, resid); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 1) { error = EBADRPC; break; } md_get_uint16le(mdp, &resid); *rresid = resid; } while(0); smb_rq_done(rqp); return error; }
static int smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end, struct smb_cred *scred) { struct smb_share *ssp = np->n_mount->sm_share; struct smb_rq *rqp; struct mbchain *mbp; u_char ltype = 0; int error; if (op == SMB_LOCK_SHARED) ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred); if (error) { free(rqp, M_SMBFSDATA); return error; } smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint8(mbp, ltype); /* locktype */ mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ mb_put_uint32le(mbp, 0); /* timeout - break immediately */ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint16le(mbp, pid); mb_put_uint32le(mbp, start); mb_put_uint32le(mbp, end - start); smb_rq_bend(rqp); error = smb_rq_simple(rqp); smb_rq_done(rqp); free(rqp, M_SMBFSDATA); return error; }
int smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, struct smb_cred *scred) { struct smb_rq *rqp; struct smb_share *ssp = dnp->n_mount->sm_share; struct mbchain *mbp; struct mdchain *mdp; struct timespec ctime; u_int8_t wc; u_int16_t fid; u_long tm; int error; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_NEW, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); /* get current time */ getnanotime(&ctime); smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); smb_rq_wstart(rqp); mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ mb_put_uint32le(mbp, tm); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); if (!error) { smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (!error) { smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc == 1) md_get_uint16(mdp, &fid); else error = EBADRPC; } } smb_rq_done(rqp); if (!error) smbfs_smb_close(ssp, fid, &ctime, scred); return (error); }
/* * Set DOS file attributes. mtime should be NULL for dialects above lm10 */ int smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, struct smb_cred *scred) { struct smb_rq *rqp; struct smb_share *ssp = np->n_mount->sm_share; struct mbchain *mbp; u_long time; int error, svtz; rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred); if (error) { free(rqp, M_SMBFSDATA); return error; } svtz = SSTOVC(ssp)->vc_sopt.sv_tz; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint16le(mbp, attr); if (mtime) { smb_time_local2server(mtime, svtz, &time); } else time = 0; mb_put_uint32le(mbp, time); /* mtime */ mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); do { error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 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); if (error) { SMBERROR("smb_rq_simple(rqp) => error %d\n", error); break; } } while(0); smb_rq_done(rqp); free(rqp, M_SMBFSDATA); return error; }
static int mb_put_ace(mbchain_t *mbp, i_ntace_t *ace) { int cnt0, error; uint16_t ace_len, *ace_len_p; if (ace == NULL) return (EINVAL); cnt0 = mbp->mb_count; /* * Put the (fixed-size) ACE header * Will fill in the length later. */ ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_type)); ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_flags)); ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p)); if (ace_len_p == NULL) { error = ENOMEM; goto errout; } switch (ace->ace_hdr.ace_type) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_ALARM_ACE_TYPE: /* Put type-specific data. */ ERRCHK(mb_put_uint32le(mbp, ace->ace_v2.ace_rights)); ERRCHK(mb_put_sid(mbp, ace->ace_v2.ace_sid)); break; /* other types todo */ default: error = EIO; goto errout; } /* Fill in the (OtW) ACE length. */ ace_len = mbp->mb_count - cnt0; *ace_len_p = htoles(ace_len); /* Success! */ return (0); errout: return (error); }
static int smbfs_smb_lockandx(struct smbnode *np, int op, void *id, off_t start, off_t end, struct smb_cred *scred) { struct smb_share *ssp = np->n_mount->sm_share; struct smb_rq *rqp; struct mbchain *mbp; u_char ltype = 0; int error; if (op == SMB_LOCK_SHARED) ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint8(mbp, ltype); /* locktype */ mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ mb_put_uint32le(mbp, 0); /* timeout - break immediately */ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint16le(mbp, (((long) id) & 0xffff)); /* process ID */ mb_put_uint32le(mbp, start); mb_put_uint32le(mbp, end - start); smb_rq_bend(rqp); error = smb_rq_simple(rqp); smb_rq_done(rqp); return error; }