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; }
int md_get_uio(struct mdchain *mdp, struct uio *uiop, int size) { char *uiocp; long left; int mtype, error; mtype = (uiop->uio_segflg == UIO_SYSSPACE) ? MB_MSYSTEM : MB_MUSER; while (size > 0 && uiop->uio_resid) { if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) return EFBIG; left = uiop->uio_iov->iov_len; if (left == 0) { uiop->uio_iov++; uiop->uio_iovcnt--; continue; } uiocp = uiop->uio_iov->iov_base; if (left > size) left = size; error = md_get_mem(mdp, uiocp, left, mtype); if (error) return error; uiop->uio_offset += left; uiop->uio_resid -= left; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + left; uiop->uio_iov->iov_len -= left; size -= left; } return 0; }
static int ncp_extract_file_info(struct nwmount *nmp, struct ncp_rq *rqp, struct nw_entry_info *target, int withname) { u_int8_t name_len; md_get_mem(&rqp->rp, (caddr_t)target, NCP_INFOSZ, MB_MSYSTEM); if (!withname) return 0; md_get_uint8(&rqp->rp, &name_len); target->nameLen = name_len; md_get_mem(&rqp->rp, (caddr_t)target->entryName, name_len, MB_MSYSTEM); target->entryName[name_len] = '\0'; ncp_path2unix(target->entryName, target->entryName, name_len, &nmp->m.nls); return 0; }
int ncp_initsearch(struct vnode *dvp, struct thread *td, struct ucred *cred) { struct nwmount *nmp = VTONWFS(dvp); struct ncp_conn *conn = NWFSTOCONN(nmp); struct nwnode *np = VTONW(dvp); struct ncp_rq *rqp; u_int8_t volnum = nmp->n_volume; u_int32_t dirent = np->n_fid.f_id; int error; NCPNDEBUG("vol=%d,dir=%d\n", volnum, dirent); error = ncp_rq_alloc(87, conn, td, cred, &rqp); if (error) return error; mb_put_uint8(&rqp->rq, 2); /* subfunction */ mb_put_uint8(&rqp->rq, nmp->name_space); mb_put_uint8(&rqp->rq, 0); /* reserved */ ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL); rqp->nr_minrplen = sizeof(np->n_seq); error = ncp_request(rqp); if (error) return error; md_get_mem(&rqp->rp, (caddr_t)&np->n_seq, sizeof(np->n_seq), MB_MSYSTEM); ncp_rq_done(rqp); return 0; }
static int md_get_ace(mdchain_t *mdp, i_ntace_t **acep) { mdchain_t tmp_md; i_ntace_hdr_t ace_hdr; i_ntace_t *ace = NULL; uint16_t alloc_size; int error; /* * The ACE is realy variable length, * with format determined by the type. * * There may also be padding after it, so * decode it using a copy of the mdchain, * and then consume the specified length. */ tmp_md = *mdp; /* Fixed-size ACE header */ ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_type)); ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_flags)); ERRCHK(md_get_uint16le(&tmp_md, &ace_hdr.ace_size)); switch (ace_hdr.ace_type) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_ALARM_ACE_TYPE: alloc_size = sizeof (i_ntace_v2_t); if ((ace = MALLOC(alloc_size)) == NULL) return (ENOMEM); bzero(ace, alloc_size); /* ACE header */ ace->ace_hdr.ace_type = ace_hdr.ace_type; ace->ace_hdr.ace_flags = ace_hdr.ace_flags; ace->ace_hdr.ace_size = alloc_size; /* Type-specific data. */ ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_v2.ace_rights)); ERRCHK(md_get_sid(&tmp_md, &ace->ace_v2.ace_sid)); break; /* other types todo */ default: error = EIO; goto errout; } /* Now actually consume ace_hdr.ace_size */ ERRCHK(md_get_mem(mdp, NULL, ace_hdr.ace_size, MB_MSYSTEM)); /* Success! */ *acep = ace; return (0); errout: ifree_ace(ace); 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; }
int md_get_mbuf(struct mdchain *mdp, int size, struct mbuf **ret) { struct mbuf *m = mdp->md_cur, *rm; rm = m_copym(m, mdp->md_pos - mtod(m, u_char*), size, M_WAIT); md_get_mem(mdp, NULL, size, MB_MZERO); *ret = rm; return 0; }
static int smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) { struct mdchain *mbp; struct smb_rq *rqp; char *cp; u_int8_t battr; u_int16_t xdate, xtime; u_int32_t size; int error; if (ctx->f_ecnt == 0) { if (ctx->f_flags & SMBFS_RDD_EOF) return ENOENT; ctx->f_left = ctx->f_limit = limit; error = smbfs_smb_search(ctx); if (error) return error; } rqp = ctx->f_rq; smb_rq_getreply(rqp, &mbp); md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); md_get_uint8(mbp, &battr); md_get_uint16le(mbp, &xtime); md_get_uint16le(mbp, &xdate); md_get_uint32le(mbp, &size); KASSERT(ctx->f_name == ctx->f_fname); cp = ctx->f_name; md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); cp[sizeof(ctx->f_fname) - 1] = '\0'; cp += strlen(cp) - 1; while(*cp == ' ' && cp > ctx->f_name) *cp-- = '\0'; ctx->f_attr.fa_attr = battr; smb_dos2unixtime(xdate, xtime, 0, rqp->sr_vc->vc_sopt.sv_tz, &ctx->f_attr.fa_mtime); ctx->f_attr.fa_size = size; ctx->f_nmlen = strlen(ctx->f_name); ctx->f_ecnt--; ctx->f_left--; return 0; }
/* * Extract resource record from the packet. Assume that there is only * one mbuf. */ int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp) { struct mbdata *mbp = &rqp->nr_rp; uchar_t *cp; int error, len; bzero(rrp, sizeof (*rrp)); cp = (uchar_t *)mbp->mb_pos; len = nb_encname_len(cp); if (len < 1) return (NBERROR(NBERR_INVALIDRESPONSE)); rrp->rr_name = cp; error = md_get_mem(mbp, NULL, len, MB_MSYSTEM); if (error) return (error); md_get_uint16be(mbp, &rrp->rr_type); md_get_uint16be(mbp, &rrp->rr_class); md_get_uint32be(mbp, &rrp->rr_ttl); md_get_uint16be(mbp, &rrp->rr_rdlength); rrp->rr_data = (uchar_t *)mbp->mb_pos; error = md_get_mem(mbp, NULL, rrp->rr_rdlength, MB_MSYSTEM); return (error); }
static int md_get_sid(mdchain_t *mdp, i_ntsid_t **sidp) { i_ntsid_t *sid = NULL; uint8_t revision, subauthcount; uint32_t *subauthp; size_t sidsz; int error, i; if ((error = md_get_uint8(mdp, &revision)) != 0) return (error); if ((error = md_get_uint8(mdp, &subauthcount)) != 0) return (error); sidsz = I_SID_SIZE(subauthcount); if ((sid = MALLOC(sidsz)) == NULL) return (ENOMEM); bzero(sid, sidsz); sid->sid_revision = revision; sid->sid_subauthcount = subauthcount; ERRCHK(md_get_mem(mdp, sid->sid_authority, 6, MB_MSYSTEM)); subauthp = &sid->sid_subauthvec[0]; for (i = 0; i < subauthcount; i++) { ERRCHK(md_get_uint32le(mdp, subauthp)); subauthp++; } /* Success! */ *sidp = sid; return (0); errout: ifree_sid(sid); return (error); }
int md_get_uint16(struct mdchain *mdp, uint16_t *x) { return md_get_mem(mdp, (caddr_t)x, 2, MB_MINLINE); }
int md_get_uint8(struct mdchain *mdp, uint8_t *x) { return md_get_mem(mdp, x, 1, MB_MINLINE); }
/* * Low level send rpc, here we do not attempt to restore any connection, * Connection expected to be locked */ int ncp_request_int(struct ncp_rq *rqp) { struct ncp_conn *conn = rqp->nr_conn; struct thread *td = conn->td; struct socket *so = conn->ncp_so; struct ncp_rqhdr *rq; struct ncp_rphdr *rp=NULL; struct timeval tv; struct mbuf *m, *mreply = NULL; struct mbchain *mbp; int error, len, dosend, plen = 0, gotpacket; if (so == NULL) { printf("%s: ncp_so is NULL !\n",__func__); ncp_conn_invalidate(conn); return ENOTCONN; } if (td == NULL) td = curthread; /* XXX maybe procpage ? */ /* * Flush out replies on previous reqs */ tv.tv_sec = 0; tv.tv_usec = 0; while (selsocket(so, POLLIN, &tv, td) == 0) { if (ncp_sock_recv(so, &m, &len) != 0) break; m_freem(m); } mbp = &rqp->rq; len = mb_fixhdr(mbp); rq = mtod(mbp->mb_top, struct ncp_rqhdr *); rq->seq = conn->seq; m = rqp->rq.mb_top; switch (rq->fn) { case 0x15: case 0x16: case 0x17: case 0x23: *(u_int16_t*)(rq + 1) = htons(len - 2 - sizeof(*rq)); break; } if (conn->flags & NCPFL_SIGNACTIVE) { error = ncp_sign_packet(conn, rqp, &len); if (error) return error; mbp->mb_top->m_pkthdr.len = len; } rq->conn_low = conn->connid & 0xff; /* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/ /* XXX: this is temporary fix till I find a better solution */ rq->task = rq->conn_low; rq->conn_high = conn->connid >> 8; rqp->rexmit = conn->li.retry_count; error = 0; for(dosend = 1;;) { if (rqp->rexmit-- == 0) { error = ETIMEDOUT; break; } error = 0; if (dosend) { NCPSDEBUG("send:%04x f=%02x c=%d l=%d s=%d t=%d\n",rq->type, rq->fn, (rq->conn_high << 8) + rq->conn_low, mbp->mb_top->m_pkthdr.len, rq->seq, rq->task ); error = ncp_sock_send(so, mbp->mb_top, rqp); if (error) break; } tv.tv_sec = conn->li.timeout; tv.tv_usec = 0; error = selsocket(so, POLLIN, &tv, td); if (error == EWOULDBLOCK ) /* timeout expired */ continue; error = ncp_chkintr(conn, td); if (error) break; /* * At this point it is possible to get more than one * reply from server. In general, last reply should be for * current request, but not always. So, we loop through * all replies to find the right answer and flush others. */ gotpacket = 0; /* nothing good found */ dosend = 1; /* resend rq if error */ for (;;) { error = 0; tv.tv_sec = 0; tv.tv_usec = 0; if (selsocket(so, POLLIN, &tv, td) != 0) break; /* if (so->so_rcv.sb_cc == 0) { break; }*/ error = ncp_sock_recv(so, &m, &len); if (error) break; /* must be more checks !!! */ if (m->m_len < sizeof(*rp)) { m = m_pullup(m, sizeof(*rp)); if (m == NULL) { printf("%s: reply too short\n",__func__); continue; } } rp = mtod(m, struct ncp_rphdr*); if (len == sizeof(*rp) && rp->type == NCP_POSITIVE_ACK) { NCPSDEBUG("got positive acknowledge\n"); m_freem(m); rqp->rexmit = conn->li.retry_count; dosend = 0; /* server just busy and will reply ASAP */ continue; } NCPSDEBUG("recv:%04x c=%d l=%d s=%d t=%d cc=%02x cs=%02x\n",rp->type, (rp->conn_high << 8) + rp->conn_low, len, rp->seq, rp->task, rp->completion_code, rp->connection_state); NCPDDEBUG(m); if ( (rp->type == NCP_REPLY) && ((rq->type == NCP_ALLOC_SLOT) || ((rp->conn_low == rq->conn_low) && (rp->conn_high == rq->conn_high) ))) { if (rq->seq > rp->seq || (rq->seq == 0 && rp->seq == 0xff)) { dosend = 1; } if (rp->seq == rq->seq) { if (gotpacket) { m_freem(m); } else { gotpacket = 1; mreply = m; plen = len; } continue; /* look up other for other packets */ } } m_freem(m); NCPSDEBUG("reply mismatch\n"); } /* for receive */ if (error || gotpacket) break; /* try to resend, or just wait */ } conn->seq++; if (error) { NCPSDEBUG("error=%d\n", error); /* * Any error except interruped call means that we have * to reconnect. So, eliminate future timeouts by invalidating * connection now. */ if (error != EINTR) ncp_conn_invalidate(conn); return (error); } if (conn->flags & NCPFL_SIGNACTIVE) { /* XXX: check reply signature */ m_adj(mreply, -8); plen -= 8; } rp = mtod(mreply, struct ncp_rphdr*); md_initm(&rqp->rp, mreply); rqp->nr_rpsize = plen - sizeof(*rp); rqp->nr_cc = error = rp->completion_code; if (error) error |= 0x8900; /* server error */ rqp->nr_cs = rp->connection_state; if (rqp->nr_cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) { NCPSDEBUG("server drop us\n"); ncp_conn_invalidate(conn); error = ECONNRESET; } md_get_mem(&rqp->rp, NULL, sizeof(*rp), MB_MSYSTEM); return error; }
/* * Generic routine that handles open/creates. */ int smbio_ntcreatex(void *smbctx, const char *path, const char *streamName, struct open_inparms *inparms, struct open_outparm *outparms, int *fid) { uint16_t *namelenp; struct smb_usr_rq *rqp; mbchain_t mbp; mdchain_t mdp; uint8_t wc; size_t nmlen; int error; u_int16_t fid16; /* * Since the reply will fit in one mbuf, pass zero which will cause a normal * mbuf to get created. */ error = smb_usr_rq_init(smbctx, SMB_COM_NT_CREATE_ANDX, 0, &rqp); if (error != 0) { return error; } mbp = smb_usr_rq_getrequest(rqp); smb_usr_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to next command (none) */ mb_put_uint8(mbp, 0); /* MBZ */ namelenp = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t)); /* * XP to W2K Server never sets the NTCREATEX_FLAGS_OPEN_DIRECTORY * for creating nor for opening a directory. Samba ignores the bit. * * Request the extended reply to get maximal access */ mb_put_uint32le(mbp, NTCREATEX_FLAGS_EXTENDED); /* NTCREATEX_FLAGS_* */ mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */ mb_put_uint32le(mbp, inparms->rights); mb_put_uint64le(mbp, inparms->allocSize); /* "initial allocation size" */ mb_put_uint32le(mbp, inparms->attrs); /* attributes */ mb_put_uint32le(mbp, inparms->shareMode); mb_put_uint32le(mbp, inparms->disp); mb_put_uint32le(mbp, inparms->createOptions); mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */ mb_put_uint8(mbp, 0); /* security flags (?) */ smb_usr_rq_wend(rqp); smb_usr_rq_bstart(rqp); nmlen = 0; if (streamName) { size_t snmlen = 0; error = smb_usr_put_dmem(smbctx, mbp, path, strlen(path), SMB_UTF_SFM_CONVERSIONS | SMB_FULLPATH_CONVERSIONS, &nmlen); if (!error) { /* Make sure the stream name starts with a colon */ if (*streamName != ':') { mb_put_uint16le(mbp, ':'); nmlen += 2; } error = smb_usr_rq_put_dstring(smbctx, mbp, streamName, strlen(streamName), NO_SFM_CONVERSIONS, &snmlen); } nmlen += snmlen; } else { error = smb_usr_rq_put_dstring(smbctx, mbp, path, strlen(path), SMB_UTF_SFM_CONVERSIONS | SMB_FULLPATH_CONVERSIONS, &nmlen); } if (error) { smb_log_info("%s: smb_usr_rq_put_dstring failed syserr = %s", ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error)); goto done; } /* Now the network name length into the reserved location */ *namelenp = htoles((uint16_t)nmlen); smb_usr_rq_bend(rqp); error = smb_usr_rq_simple(rqp); if (error != 0) { smb_log_info("%s: smb_usr_rq_simple failed, syserr = %s", ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error)); goto done; } mdp = smb_usr_rq_getreply(rqp); /* * Spec say 26 for word count, but 34 words are defined and observed from * all servers. * * The spec is wrong and word count should always be 34 unless we request * the extended reply. Now some server will always return 42 even it the * NTCREATEX_FLAGS_EXTENDED flag is not set. * * From the MS-SMB document concern the extend response: * * The word count for this response MUST be 0x2A (42). WordCount in this * case is not used as the count of parameter words but is just a number. */ if (md_get_uint8(mdp, &wc) != 0 || ((wc != NTCREATEX_NORMAL_WDCNT) && (wc != NTCREATEX_EXTENDED_WDCNT))) { error = EIO; smb_log_info("%s: bad word count, syserr = %s", ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error)); goto done; } md_get_uint8(mdp, NULL); /* secondary cmd */ md_get_uint8(mdp, NULL); /* mbz */ md_get_uint16le(mdp, NULL); /* andxoffset */ md_get_uint8(mdp, NULL); /* oplock lvl granted */ md_get_uint16le(mdp, &fid16); /* FID */ *fid = fid16; error = md_get_uint32le(mdp, NULL); /* create_action */ /* Only get the rest of the parameter values if they want request them */ if (outparms) { /* Should we convert the time, current we don't */ md_get_uint64le(mdp, &outparms->createTime); md_get_uint64le(mdp, &outparms->accessTime); md_get_uint64le(mdp, &outparms->writeTime); md_get_uint64le(mdp, &outparms->changeTime); md_get_uint32le(mdp, &outparms->attributes); md_get_uint64le(mdp, &outparms->allocationSize); md_get_uint64le(mdp, &outparms->fileSize); md_get_uint16le(mdp, NULL); /* file type */ md_get_uint16le(mdp, NULL); /* device state */ error = md_get_uint8(mdp, NULL); /* directory (boolean) */ /* Supports extended word count, so lets get them */ if (wc == NTCREATEX_EXTENDED_WDCNT) { md_get_mem(mdp, (caddr_t)outparms->volumeGID, sizeof(outparms->volumeGID), MB_MSYSTEM); md_get_uint64le(mdp, &outparms->fileInode); md_get_uint32le(mdp, &outparms->maxAccessRights); error = md_get_uint32le(mdp, &outparms->maxGuessAccessRights); } } done: smb_usr_rq_done(rqp); return error; }
static int smb_smb_read(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 bc, cnt, dlen, 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 reads. */ todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, 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); smb_rq_bend(rqp); if (timo == 0) timo = smb_timo_read; 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 != 5) { error = EBADRPC; goto out; } md_get_uint16le(mdp, &rcnt); /* ret. count */ md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */ md_get_uint16le(mdp, &bc); /* byte count */ md_get_uint8(mdp, NULL); /* buffer format */ error = md_get_uint16le(mdp, &dlen); /* data len */ if (error) goto out; if (dlen < rcnt) { SMBSDEBUG("oops: dlen=%d rcnt=%d\n", (int)dlen, (int)rcnt); rcnt = dlen; } if (rcnt == 0) { *lenp = 0; goto out; } /* paranoid */ if (rcnt > cnt) { SMBSDEBUG("bad server! rcnt %d, cnt %d\n", (int)rcnt, (int)cnt); rcnt = cnt; } error = md_get_uio(mdp, uiop, (int)rcnt); if (error) goto out; /* success */ *lenp = (int)rcnt; out: smb_rq_done(rqp); return (error); }
int md_get_uint32(struct mdchain *mdp, uint32_t *x) { return md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE); }
static int smb_nt_reply(struct smb_ntrq *ntp) { struct mdchain *mdp; struct smb_rq *rqp = ntp->nt_rq; int error, error2; u_int32_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp; u_int32_t tmp, dcount, totpgot, totdgot; u_int16_t bc; u_int8_t wc; ntp->nt_flags &= ~SMBT2_MOREDATA; error = smb_rq_reply(rqp); if (rqp->sr_flags & SMBR_MOREDATA) ntp->nt_flags |= SMBT2_MOREDATA; ntp->nt_sr_error = rqp->sr_error; ntp->nt_sr_rpflags2 = rqp->sr_rpflags2; if (error && !(rqp->sr_flags & SMBR_MOREDATA)) return (error); /* * Now we have to get all subseqent responses. The CIFS specification * says that they can be misordered which is weird. * TODO: timo */ totpgot = totdgot = 0; totpcount = totdcount = 0xffffffff; mdp = &rqp->sr_rp; for (;;) { DTRACE_PROBE2(smb_trans_reply, (smb_rq_t *), rqp, (mblk_t *), mdp->md_top); m_dumpm(mdp->md_top); if ((error2 = md_get_uint8(mdp, &wc)) != 0) break; if (wc < 18) { error2 = ENOENT; break; } md_get_mem(mdp, NULL, 3, MB_MSYSTEM); /* reserved */ if ((error2 = md_get_uint32le(mdp, &tmp)) != 0) break; if (totpcount > tmp) totpcount = tmp; if ((error2 = md_get_uint32le(mdp, &tmp)) != 0) break; if (totdcount > tmp) totdcount = tmp; if ((error2 = md_get_uint32le(mdp, &pcount)) != 0 || (error2 = md_get_uint32le(mdp, &poff)) != 0 || (error2 = md_get_uint32le(mdp, &pdisp)) != 0) break; if (pcount != 0 && pdisp != totpgot) { SMBSDEBUG("Can't handle misordered parameters %d:%d\n", pdisp, totpgot); error2 = EINVAL; break; } if ((error2 = md_get_uint32le(mdp, &dcount)) != 0 || (error2 = md_get_uint32le(mdp, &doff)) != 0 || (error2 = md_get_uint32le(mdp, &ddisp)) != 0) break; if (dcount != 0 && ddisp != totdgot) { SMBSDEBUG("Can't handle misordered data: dcount %d\n", dcount); error2 = EINVAL; break; } /* XXX: Skip setup words? We don't save them? */ md_get_uint8(mdp, &wc); /* SetupCount */ tmp = wc; while (tmp--) md_get_uint16le(mdp, NULL); if ((error2 = md_get_uint16le(mdp, &bc)) != 0) break; /* * There are pad bytes here, and the poff value * indicates where the next data are found. * No need to guess at the padding size. */ if (pcount) { error2 = smb_t2_placedata(mdp->md_top, poff, pcount, &ntp->nt_rparam); if (error2) break; } totpgot += pcount; if (dcount) { error2 = smb_t2_placedata(mdp->md_top, doff, dcount, &ntp->nt_rdata); if (error2) break; } totdgot += dcount; if (totpgot >= totpcount && totdgot >= totdcount) { error2 = 0; ntp->nt_flags |= SMBT2_ALLRECV; break; } /* * We're done with this reply, look for the next one. */ SMBRQ_LOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_UNLOCK(rqp); error2 = smb_rq_reply(rqp); if (rqp->sr_flags & SMBR_MOREDATA) ntp->nt_flags |= SMBT2_MOREDATA; if (!error2) continue; ntp->nt_sr_error = rqp->sr_error; ntp->nt_sr_rpflags2 = rqp->sr_rpflags2; error = error2; if (!(rqp->sr_flags & SMBR_MOREDATA)) break; } return (error ? error : error2); }
/* * Import a raw SD (mb chain) into "internal" form. * (like "absolute" form per. NT docs) * Returns allocated data in sdp * * Note: does NOT consume all the mdp data, so the * caller has to take care of that if necessary. */ int md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp) { i_ntsd_t *sd = NULL; mdchain_t top_md, tmp_md; uint32_t owneroff, groupoff, sacloff, dacloff; int error; if ((sd = MALLOC(sizeof (*sd))) == NULL) return (ENOMEM); bzero(sd, sizeof (*sd)); /* * Offsets below are relative to this point, * so save the mdp state for use below. */ top_md = *mdp; ERRCHK(md_get_uint8(mdp, &sd->sd_revision)); ERRCHK(md_get_uint8(mdp, &sd->sd_rmctl)); ERRCHK(md_get_uint16le(mdp, &sd->sd_flags)); ERRCHK(md_get_uint32le(mdp, &owneroff)); ERRCHK(md_get_uint32le(mdp, &groupoff)); ERRCHK(md_get_uint32le(mdp, &sacloff)); ERRCHK(md_get_uint32le(mdp, &dacloff)); /* * The SD is "self-relative" on the wire, * but not after this decodes it. */ sd->sd_flags &= ~SD_SELF_RELATIVE; /* * For each section make a temporary copy of the * top_md state, advance to the given offset, and * pass that to the lower md_get_xxx functions. * These could be marshalled in any order, but * are normally found in the order shown here. */ if (sacloff) { tmp_md = top_md; md_get_mem(&tmp_md, NULL, sacloff, MB_MSYSTEM); ERRCHK(md_get_acl(&tmp_md, &sd->sd_sacl)); } if (dacloff) { tmp_md = top_md; md_get_mem(&tmp_md, NULL, dacloff, MB_MSYSTEM); ERRCHK(md_get_acl(&tmp_md, &sd->sd_dacl)); } if (owneroff) { tmp_md = top_md; md_get_mem(&tmp_md, NULL, owneroff, MB_MSYSTEM); ERRCHK(md_get_sid(&tmp_md, &sd->sd_owner)); } if (groupoff) { tmp_md = top_md; md_get_mem(&tmp_md, NULL, groupoff, MB_MSYSTEM); ERRCHK(md_get_sid(&tmp_md, &sd->sd_group)); } /* Success! */ *sdp = sd; return (0); errout: smbfs_acl_free_sd(sd); return (error); }
int md_get_uint16(struct mdchain *mdp, u_int16_t *x) { return md_get_mem(mdp, (void *)x, 2, MB_MINLINE); }
int md_get_uint32(struct mdchain *mdp, u_int32_t *x) { return md_get_mem(mdp, (void *)x, 4, MB_MINLINE); }
int md_get_int64(struct mdchain *mdp, int64_t *x) { return md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE); }
int smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, struct smb_cred *scred) { struct smb_rq rq, *rqp = &rq; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc; u_int16_t bc; int error; switch (dp->ioc_cmd) { case SMB_COM_TRANSACTION2: case SMB_COM_TRANSACTION2_SECONDARY: case SMB_COM_CLOSE_AND_TREE_DISC: case SMB_COM_TREE_CONNECT: case SMB_COM_TREE_DISCONNECT: case SMB_COM_NEGOTIATE: case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_CONNECT_ANDX: return EPERM; } error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); if (error) return error; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER); if (error) goto bad; smb_rq_wend(rqp); smb_rq_bstart(rqp); error = mb_put_mem(mbp, dp->ioc_tbytes, dp->ioc_tbc, MB_MUSER); if (error) goto bad; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) goto bad; mdp = &rqp->sr_rp; md_get_uint8(mdp, &wc); dp->ioc_rwc = wc; wc *= 2; if (wc > dp->ioc_rpbufsz) { error = EBADRPC; goto bad; } error = md_get_mem(mdp, dp->ioc_rpbuf, wc, MB_MUSER); if (error) goto bad; md_get_uint16le(mdp, &bc); if ((wc + bc) > dp->ioc_rpbufsz) { error = EBADRPC; goto bad; } dp->ioc_rbc = bc; error = md_get_mem(mdp, dp->ioc_rpbuf + wc, bc, MB_MUSER); bad: dp->ioc_errclass = rqp->sr_errclass; dp->ioc_serror = rqp->sr_serror; dp->ioc_error = rqp->sr_error; smb_rq_done(rqp); return error; }
static int smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) { struct mdchain *mbp; struct smb_t2rq *t2p; char *cp; u_int8_t tb; u_int16_t date, time, wattr; u_int32_t size, next, dattr; int64_t lint; int error, svtz, cnt, fxsz, nmlen, recsz; if (ctx->f_ecnt == 0) { if (ctx->f_flags & SMBFS_RDD_EOF) return ENOENT; ctx->f_left = ctx->f_limit = limit; error = smbfs_smb_trans2find2(ctx); if (error) return error; } t2p = ctx->f_t2; mbp = &t2p->t2_rdata; svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; switch (ctx->f_infolevel) { case SMB_INFO_STANDARD: next = 0; fxsz = 0; md_get_uint16le(mbp, &date); md_get_uint16le(mbp, &time); /* creation time */ md_get_uint16le(mbp, &date); md_get_uint16le(mbp, &time); /* access time */ smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); md_get_uint16le(mbp, &date); md_get_uint16le(mbp, &time); /* access time */ smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); md_get_uint32le(mbp, &size); ctx->f_attr.fa_size = size; md_get_uint32(mbp, NULL); /* allocation size */ md_get_uint16le(mbp, &wattr); ctx->f_attr.fa_attr = wattr; md_get_uint8(mbp, &tb); size = nmlen = tb; fxsz = 23; recsz = next = 24 + nmlen; /* docs misses zero byte at end */ break; case SMB_FIND_FILE_DIRECTORY_INFO: md_get_uint32le(mbp, &next); md_get_uint32(mbp, NULL); /* file index */ md_get_int64(mbp, NULL); /* creation time */ md_get_int64le(mbp, &lint); smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); md_get_int64le(mbp, &lint); smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); md_get_int64le(mbp, &lint); smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); md_get_int64le(mbp, &lint); /* file size */ ctx->f_attr.fa_size = lint; md_get_int64(mbp, NULL); /* real size (should use) */ md_get_uint32le(mbp, &dattr); /* EA */ ctx->f_attr.fa_attr = dattr; md_get_uint32le(mbp, &size); /* name len */ fxsz = 64; recsz = next ? next : fxsz + size; break; default: SMBERROR("unexpected info level %d\n", ctx->f_infolevel); return EINVAL; } 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) return error; if (next) { cnt = next - nmlen - fxsz; if (cnt > 0) md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); else if (cnt < 0) { SMBERROR("out of sync\n"); return EBADRPC; } } 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; next = ctx->f_eofs + recsz; if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { /* * Server needs a resume filename. */ if (ctx->f_rnamelen <= nmlen) { if (ctx->f_rname) free(ctx->f_rname, M_SMBFSDATA); ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); ctx->f_rnamelen = nmlen; } bcopy(ctx->f_name, ctx->f_rname, nmlen); ctx->f_rname[nmlen] = 0; ctx->f_flags |= SMBFS_RDD_GOTRNAME; } ctx->f_nmlen = nmlen; ctx->f_eofs = next; ctx->f_ecnt--; ctx->f_left--; return 0; }
static int userfw_sosend(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr_, struct mbuf *control, struct thread *td) { int err = 0; struct userfwpcb *pcb = sotopcb(so); struct userfw_io_header msg; int cmd_ready = 0; unsigned char *data = NULL; struct mdchain chain; if (pcb == NULL) err = ENOTCONN; if (control != NULL) err = EINVAL; SOCKBUF_LOCK(&(so->so_snd)); if (err == 0) { sbappendstream_locked(&(so->so_snd), m); m = NULL; md_initm(&chain, so->so_snd.sb_mb); if (SOCKBUF_LEN(so->so_snd) >= sizeof(msg)) { md_get_mem(&chain, (caddr_t)(&msg), sizeof(msg), MB_MSYSTEM); if (SOCKBUF_LEN(so->so_snd) >= msg.length) cmd_ready = 1; } } if (err == 0 && cmd_ready) { if (msg.type != T_CONTAINER || (msg.subtype != ST_MESSAGE && msg.subtype != ST_CMDCALL)) { cmd_ready = 0; sbdrop_locked(&(so->so_snd), msg.length); } } if (err == 0 && cmd_ready) { data = malloc(msg.length, M_USERFW, M_WAITOK); md_initm(&chain, so->so_snd.sb_mb); md_get_mem(&chain, data, msg.length, MB_MSYSTEM); err = userfw_cmd_dispatch(data, so, td); sbdrop_locked(&(so->so_snd), msg.length); free(data, M_USERFW); } SOCKBUF_UNLOCK(&(so->so_snd)); if (control != NULL) m_freem(control); if (m != NULL) m_freem(m); return err; }
int smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp, struct smb_cred *scred) { struct smb_t2rq t2, *t2p = &t2; struct mdchain *mdp; int error, len; if (dp->ioc_setupcnt > 3) return EINVAL; error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred); if (error) return error; len = t2p->t2_setupcount = dp->ioc_setupcnt; if (len > 1) t2p->t2_setupdata = dp->ioc_setup; if (dp->ioc_name) { t2p->t_name = smb_strdupin(dp->ioc_name, 128); if (t2p->t_name == NULL) { error = ENOMEM; goto bad; } } t2p->t2_maxscount = 0; t2p->t2_maxpcount = dp->ioc_rparamcnt; t2p->t2_maxdcount = dp->ioc_rdatacnt; error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); if (error) goto bad; error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); if (error) goto bad; error = smb_t2_request(t2p); if (error) goto bad; mdp = &t2p->t2_rparam; if (mdp->md_top) { len = m_fixhdr(mdp->md_top); if (len > dp->ioc_rparamcnt) { error = EMSGSIZE; goto bad; } dp->ioc_rparamcnt = len; error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); if (error) goto bad; } else dp->ioc_rparamcnt = 0; mdp = &t2p->t2_rdata; if (mdp->md_top) { len = m_fixhdr(mdp->md_top); if (len > dp->ioc_rdatacnt) { error = EMSGSIZE; goto bad; } dp->ioc_rdatacnt = len; error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); } else dp->ioc_rdatacnt = 0; bad: if (t2p->t_name) smb_strfree(t2p->t_name); smb_t2_done(t2p); return error; }
static inline int smb_smb_readx(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_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, (void *)&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, *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_uint16(mdp, NULL); off += 2; md_get_uint16(mdp, NULL); off += 2; md_get_uint16(mdp, NULL); /* data compaction mode */ off += 2; md_get_uint16(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_uint16(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); }
static int smb_smb_readx(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 offlo, offhi, rlen; uint16_t lenhi, lenlo, off, doff; uint8_t wc; lenhi = (uint16_t)(*lenp >> 16); lenlo = (uint16_t)*lenp; offhi = (uint32_t)(uiop->uio_loffset >> 32); offlo = (uint32_t)uiop->uio_loffset; 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_uint16le(mbp, fid); mb_put_uint32le(mbp, offlo); /* offset (low part) */ mb_put_uint16le(mbp, lenlo); /* MaxCount */ mb_put_uint16le(mbp, 1); /* MinCount */ /* (only indicates blocking) */ mb_put_uint32le(mbp, lenhi); /* MaxCountHigh */ mb_put_uint16le(mbp, lenlo); /* Remaining ("obsolete") */ mb_put_uint32le(mbp, offhi); /* offset (high part) */ smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); if (timo == 0) timo = smb_timo_read; 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 != 12) { error = EBADRPC; goto out; } md_get_uint8(mdp, NULL); md_get_uint8(mdp, NULL); md_get_uint16le(mdp, NULL); md_get_uint16le(mdp, NULL); md_get_uint16le(mdp, NULL); /* data compaction mode */ md_get_uint16le(mdp, NULL); md_get_uint16le(mdp, &lenlo); /* data len ret. */ md_get_uint16le(mdp, &doff); /* data offset */ md_get_uint16le(mdp, &lenhi); rlen = (lenhi << 16) | lenlo; md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); error = md_get_uint16le(mdp, NULL); /* ByteCount */ if (error) goto out; /* * Does the data offset indicate padding? * The current offset is a constant, found * by counting the md_get_ calls above. */ off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */ if (doff > off) /* pad byte(s)? */ md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); if (rlen == 0) { *lenp = rlen; goto out; } /* paranoid */ if (rlen > *lenp) { SMBSDEBUG("bad server! rlen %d, len %d\n", rlen, *lenp); rlen = *lenp; } error = md_get_uio(mdp, uiop, rlen); if (error) goto out; /* Success */ *lenp = rlen; out: 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, __func__) != 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; }
int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) { struct smb_vc *vcp; struct smb_rq *rqp = NULL; struct mbchain *mbp; struct mdchain *mdp; char *pbuf, *unc_name = NULL; int error, tlen, plen, unc_len; uint16_t bcnt, options; uint8_t wc; vcp = SSTOVC(ssp); /* * Make this a "VC-level" request, so it will have * rqp->sr_share == NULL, and smb_iod_sendrq() * will send it with TID = SMB_TID_UNKNOWN * * This also serves to bypass the wait for * share state changes, which this call is * trying to carry out. */ error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); if (error) return (error); /* * Build the UNC name, i.e. "//server/share" * but with backslashes of course. * size math: three slashes, one null. */ unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name); unc_name = kmem_alloc(unc_len, KM_SLEEP); (void) snprintf(unc_name, unc_len, "\\\\%s\\%s", vcp->vc_srvname, ssp->ss_name); SMBSDEBUG("unc_name: \"%s\"", unc_name); /* * The password is now pre-computed in the * user-space helper process. */ plen = ssp->ss_pwlen; pbuf = ssp->ss_pass; /* * Build the request. */ 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); /* Tree connect password, if any */ error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM); if (error) goto out; /* UNC resource name */ error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE); if (error) goto out; /* * Put the type string (always ASCII), * including the null. */ tlen = strlen(ssp->ss_type_req) + 1; error = mb_put_mem(mbp, ssp->ss_type_req, tlen, MB_MSYSTEM); if (error) goto out; smb_rq_bend(rqp); /* * Run the request. * * Using NOINTR_RECV because we don't want to risk * missing a successful tree connect response, * which would "leak" Tree IDs. */ rqp->sr_flags |= SMBR_NOINTR_RECV; error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) { /* * If we get the server name wrong, i.e. due to * mis-configured name services, this will be * NT_STATUS_DUPLICATE_NAME. Log this error. */ SMBERROR("(%s) failed, status=0x%x", unc_name, rqp->sr_error); goto out; } /* * Parse the TCON response */ smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 3 && wc != 7) { error = EBADRPC; goto out; } md_get_uint16le(mdp, NULL); /* AndX cmd */ md_get_uint16le(mdp, NULL); /* AndX off */ md_get_uint16le(mdp, &options); /* option bits (DFS, search) */ if (wc == 7) { md_get_uint32le(mdp, NULL); /* MaximalShareAccessRights */ md_get_uint32le(mdp, NULL); /* GuestMaximalShareAcc... */ } error = md_get_uint16le(mdp, &bcnt); /* byte count */ if (error) goto out; /* * Get the returned share type string, * i.e. "IPC" or whatever. Don't care * if we get an error reading the type. */ tlen = sizeof (ssp->ss_type_ret); bzero(ssp->ss_type_ret, tlen--); if (tlen > bcnt) tlen = bcnt; md_get_mem(mdp, ssp->ss_type_ret, tlen, MB_MSYSTEM); /* Success! */ SMB_SS_LOCK(ssp); ssp->ss_tid = rqp->sr_rptid; ssp->ss_vcgenid = vcp->vc_genid; ssp->ss_options = options; ssp->ss_flags |= SMBS_CONNECTED; SMB_SS_UNLOCK(ssp); out: if (unc_name) kmem_free(unc_name, unc_len); smb_rq_done(rqp); return (error); }
int smbfs_smb_nt_dirnotify_fetch(struct smb_rq *rqp, int *hint) { int error; struct mdchain *mdp; u_int8_t sc; u_int32_t nextentry; error = smb_rq_reply(rqp); if (error) { /* * If we get EMSGSIZE, there is already too many notifications * available for the directory, and the internal buffer * overflew. Just flag any possible relevant change. */ if (error == EMSGSIZE) { *hint = NOTE_ATTRIB | NOTE_WRITE; error = 0; } goto bad; } smb_rq_getreply(rqp, &mdp); /* Parse reply */ error = md_get_mem(mdp, NULL, 4 + (8*4), MB_MZERO); /* skip */ if (error) goto bad; md_get_uint8(mdp, &sc); /* SetupCount */ if (sc > 0) md_get_mem(mdp, NULL, sc * sizeof(u_int16_t), MB_MZERO); md_get_uint16(mdp, NULL); /* ByteCount */ md_get_mem(mdp, NULL, 1 + (sc % 2) * 2, MB_MZERO); /* Pad */ /* * The notify data are blocks of * ULONG nextentry - offset of next entry from start of this one * ULONG action - type of notification * ULONG filenamelen - length of filename in bytes * WCHAR filename[filenamelen/2] - Unicode filename * nexentry == 0 means last notification, filename is in 16bit LE * unicode */ *hint = 0; do { u_int32_t action; #if 0 u_int32_t fnlen; u_int16_t fnc; #endif md_get_uint32le(mdp, &nextentry); md_get_uint32le(mdp, &action); if (nextentry) md_get_mem(mdp, NULL, nextentry - 2 * 4, MB_MZERO); #if 0 md_get_uint32le(mdp, &fnlen); printf("notify: next %u act %u fnlen %u fname '", nextentry, action, fnlen); for(; fnlen > 0; fnlen -= 2) { md_get_uint16le(mdp, &fnc); printf("%c", fnc&0xff); } printf("'\n"); #endif switch(action) { case FILE_ACTION_ADDED: case FILE_ACTION_REMOVED: case FILE_ACTION_RENAMED_OLD_NAME: case FILE_ACTION_RENAMED_NEW_NAME: *hint |= NOTE_ATTRIB | NOTE_WRITE; break; case FILE_ACTION_MODIFIED: *hint |= NOTE_ATTRIB; break; } } while(nextentry > 0); bad: smb_rq_done(rqp); return error; }