Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
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);
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
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;
}
Beispiel #9
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);
}
Beispiel #10
0
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);
}
Beispiel #11
0
int
md_get_uint16(struct mdchain *mdp, uint16_t *x)
{
	return md_get_mem(mdp, (caddr_t)x, 2, MB_MINLINE);
}
Beispiel #12
0
int
md_get_uint8(struct mdchain *mdp, uint8_t *x)
{
	return md_get_mem(mdp, x, 1, MB_MINLINE);
}
Beispiel #13
0
/*
 * 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;
}
Beispiel #14
0
/*
 * 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;
}
Beispiel #15
0
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);
}
Beispiel #16
0
int
md_get_uint32(struct mdchain *mdp, uint32_t *x)
{
	return md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE);
}
Beispiel #17
0
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);
}
Beispiel #18
0
/*
 * 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);
}
Beispiel #19
0
int
md_get_uint16(struct mdchain *mdp, u_int16_t *x)
{
	return md_get_mem(mdp, (void *)x, 2, MB_MINLINE);
}
Beispiel #20
0
int
md_get_uint32(struct mdchain *mdp, u_int32_t *x)
{
	return md_get_mem(mdp, (void *)x, 4, MB_MINLINE);
}
Beispiel #21
0
int
md_get_int64(struct mdchain *mdp, int64_t *x)
{
	return md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE);
}
Beispiel #22
0
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;

}
Beispiel #23
0
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;
}
Beispiel #24
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;
}
Beispiel #25
0
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;
}
Beispiel #26
0
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);
}
Beispiel #27
0
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);
}
Beispiel #28
0
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;
}
Beispiel #29
0
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);
}
Beispiel #30
0
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;
}