예제 #1
0
int
smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
{
	struct smb_rq *rqp;
	struct smb_share *ssp = np->n_mount->sm_share;
	struct mbchain *mbp;
	struct mdchain *mdp;
	u_int8_t wc;
	u_int16_t fid, wattr, grantedmode;
	int error;

	rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK);
	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
	if (error) {
		free(rqp, M_SMBFSDATA);
		return error;
	}
	smb_rq_getrequest(rqp, &mbp);
	smb_rq_wstart(rqp);
	mb_put_uint16le(mbp, accmode);
	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
	smb_rq_wend(rqp);
	smb_rq_bstart(rqp);
	mb_put_uint8(mbp, SMB_DT_ASCII);
	do {
		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
		if (error)
			break;
		smb_rq_bend(rqp);
		error = smb_rq_simple(rqp);
		if (error)
			break;
		smb_rq_getreply(rqp, &mdp);
		if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
			error = EBADRPC;
			break;
		}
		md_get_uint16(mdp, &fid);
		md_get_uint16le(mdp, &wattr);
		md_get_uint32(mdp, NULL);	/* mtime */
		md_get_uint32(mdp, NULL);	/* fsize */
		md_get_uint16le(mdp, &grantedmode);
		/*
		 * TODO: refresh attributes from this reply
		 */
	} while(0);
	smb_rq_done(rqp);
	free(rqp, M_SMBFSDATA);
	if (error)
		return error;
	np->n_fid = fid;
	np->n_rwstate = grantedmode;
	return 0;
}
예제 #2
0
파일: smb_rq.c 프로젝트: AhmadTux/freebsd
/*
 * Wait for reply on the request
 */
static int
smb_rq_reply(struct smb_rq *rqp)
{
	struct mdchain *mdp = &rqp->sr_rp;
	u_int32_t tdw;
	u_int8_t tb;
	int error, rperror = 0;

	error = smb_iod_waitrq(rqp);
	if (error)
		return error;
	error = md_get_uint32(mdp, &tdw);
	if (error)
		return error;
	error = md_get_uint8(mdp, &tb);
	if (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_ERR_STATUS) {
		error = md_get_uint32le(mdp, &rqp->sr_error);
	} else {
		error = md_get_uint8(mdp, &rqp->sr_errclass);
		error = md_get_uint8(mdp, &tb);
		error = md_get_uint16le(mdp, &rqp->sr_serror);
		if (!error)
			rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
	}
	error = md_get_uint8(mdp, &rqp->sr_rpflags);
	error = md_get_uint16le(mdp, &rqp->sr_rpflags2);

	error = md_get_uint32(mdp, &tdw);
	error = md_get_uint32(mdp, &tdw);
	error = md_get_uint32(mdp, &tdw);

	error = md_get_uint16le(mdp, &rqp->sr_rptid);
	error = md_get_uint16le(mdp, &rqp->sr_rppid);
	error = md_get_uint16le(mdp, &rqp->sr_rpuid);
	error = md_get_uint16le(mdp, &rqp->sr_rpmid);

	if (error == 0 &&
	    (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE))
		error = smb_rq_verify(rqp);

	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
	    rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid,
	    rqp->sr_errclass, rqp->sr_serror);
	return error ? error : rperror;
}
예제 #3
0
int
md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
{
	u_int32_t v;
	int error;

	error = md_get_uint32(mdp, &v);
	*x = le32toh(v);
	return error;
}
예제 #4
0
int
md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
{
	u_int32_t v;
	int error;

	error = md_get_uint32(mdp, &v);
	*x = betohl(v);
	return error;
}
예제 #5
0
int
md_get_uint32le(struct mdchain *mdp, uint32_t *x)
{
	uint32_t v;
	int error;

	error = md_get_uint32(mdp, &v);
	if (x != NULL)
		*x = le32toh(v);
	return error;
}
예제 #6
0
int
smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
	struct smb_cred *scred)
{
	struct smb_t2rq *t2p;
	struct mbchain *mbp;
	struct mdchain *mdp;
	u_int16_t bsize;
	u_int32_t units, bpu, funits;
	int error;

	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
	    scred, &t2p);
	if (error)
		return error;
	mbp = &t2p->t2_tparam;
	mb_init(mbp);
	mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
	t2p->t2_maxpcount = 4;
	t2p->t2_maxdcount = 4 * 4 + 2;
	error = smb_t2_request(t2p);
	if (error) {
		smb_t2_done(t2p);
		return error;
	}
	mdp = &t2p->t2_rdata;
	md_get_uint32(mdp, NULL);	/* fs id */
	md_get_uint32le(mdp, &bpu);
	md_get_uint32le(mdp, &units);
	md_get_uint32le(mdp, &funits);
	md_get_uint16le(mdp, &bsize);
	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
	sbp->f_blocks= units;		/* total data blocks in filesystem */
	sbp->f_bfree = funits;		/* free blocks in fs */
	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
	smb_t2_done(t2p);
	return 0;
}
예제 #7
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;
}
예제 #8
0
static int
smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
		    struct smb_cred *scred, short infolevel)
{
	struct smb_share *ssp = np->n_mount->sm_share;
	struct smb_vc *vcp = SSTOVC(ssp);
	struct smb_t2rq *t2p;
	int error, svtz, timesok = 1;
	struct mbchain *mbp;
	struct mdchain *mdp;
	u_int16_t date, time, wattr;
	int64_t lint;
	u_int32_t size, dattr;

	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
			     scred, &t2p);
	if (error)
		return error;
	mbp = &t2p->t2_tparam;
	mb_init(mbp);
	if (!infolevel) {
		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
			infolevel = SMB_QUERY_FILE_STANDARD;
		else
			infolevel = SMB_QUERY_FILE_BASIC_INFO;
	}
	mb_put_uint16le(mbp, infolevel);
	mb_put_uint32le(mbp, 0);
	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
	if (error) {
		smb_t2_done(t2p);
		return error;
	}
	t2p->t2_maxpcount = 2;
	t2p->t2_maxdcount = vcp->vc_txmax;
	error = smb_t2_request(t2p);
	if (error) {
		smb_t2_done(t2p);
		if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL)
			return error;
		return smbfs_smb_qpathinfo(np, fap, scred,
					   SMB_QUERY_FILE_STANDARD);
	}
	mdp = &t2p->t2_rdata;
	svtz = vcp->vc_sopt.sv_tz;
	switch (infolevel) {
	    case SMB_QUERY_FILE_STANDARD:
		timesok = 0;
		md_get_uint16le(mdp, NULL);
		md_get_uint16le(mdp, NULL);	/* creation time */
		md_get_uint16le(mdp, &date);
		md_get_uint16le(mdp, &time);	/* access time */
		if (date || time) {
			timesok++;
			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
		}
		md_get_uint16le(mdp, &date);
		md_get_uint16le(mdp, &time);	/* modify time */
		if (date || time) {
			timesok++;
			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
		}
		md_get_uint32le(mdp, &size);
		fap->fa_size = size;
		md_get_uint32(mdp, NULL);	/* allocation size */
		md_get_uint16le(mdp, &wattr);
		fap->fa_attr = wattr;
		break;
	    case SMB_QUERY_FILE_BASIC_INFO:
		timesok = 0;
		md_get_int64(mdp, NULL);	/* creation time */
		md_get_int64le(mdp, &lint);
		if (lint) {
			timesok++;
			smb_time_NT2local(lint, svtz, &fap->fa_atime);
		}
		md_get_int64le(mdp, &lint);
		if (lint) {
			timesok++;
			smb_time_NT2local(lint, svtz, &fap->fa_mtime);
		}
		md_get_int64le(mdp, &lint);
		if (lint) {
			timesok++;
			smb_time_NT2local(lint, svtz, &fap->fa_ctime);
		}
		md_get_uint32le(mdp, &dattr);
		fap->fa_attr = dattr;
		md_get_uint32(mdp, NULL);
		/* XXX could use ALL_INFO to get size */
		break;
	    default:
		SMBERROR("unexpected info level %d\n", infolevel);
		error = EINVAL;
	}
	smb_t2_done(t2p);
	/*
	 * if all times are zero (observed with FAT on NT4SP6)
	 * then fall back to older info level
	 */
	if (!timesok) {
		if (infolevel != SMB_QUERY_FILE_STANDARD)
			return smbfs_smb_qpathinfo(np, fap, scred,
						   SMB_QUERY_FILE_STANDARD);
		error = EINVAL;
	}
	return error;
}
예제 #9
0
파일: smbfs_smb.c 프로젝트: ryo/netbsd-src
int
smbfs_smb_statvfs(struct smb_share *ssp, struct statvfs *sbp,
	struct smb_cred *scred)
{
	unsigned long bsize;	/* Block (allocation unit) size */
	unsigned long bavail, bfree;

	/*
	 * The SMB request work with notion of sector size and
	 * allocation units. Allocation unit is what 'block'
	 * means in Unix context, sector size might be HW sector size.
	 */

	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) {
		struct smb_t2rq *t2p;
		struct mbchain *mbp;
		struct mdchain *mdp;
		u_int16_t secsz;
		u_int32_t units, bpu, funits;
		int error;

		error = smb_t2_alloc(SSTOCP(ssp),
		    SMB_TRANS2_QUERY_FS_INFORMATION, scred, &t2p);
		if (error)
			return error;
		mbp = &t2p->t2_tparam;
		mb_init(mbp);
		mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
		t2p->t2_maxpcount = 4;
		t2p->t2_maxdcount = 4 * 4 + 2;
		error = smb_t2_request(t2p);
		if (error) {
			smb_t2_done(t2p);
			return error;
		}
		mdp = &t2p->t2_rdata;
		md_get_uint32(mdp, NULL);	/* fs id */
		md_get_uint32le(mdp, &bpu);	/* Number of sectors per unit */
		md_get_uint32le(mdp, &units);	/* Total number of units */
		md_get_uint32le(mdp, &funits);	/* Number of available units */
		md_get_uint16le(mdp, &secsz);	/* Number of bytes per sector */
		smb_t2_done(t2p);

		bsize = bpu * secsz;
		bavail = units;
		bfree = funits;
	} else {
		struct smb_rq *rqp;
		struct mdchain *mdp;
		u_int16_t units, bpu, secsz, funits;
		int error;

		error = smb_rq_alloc(SSTOCP(ssp),
		    SMB_COM_QUERY_INFORMATION_DISK, scred, &rqp);
		if (error)
			return error;
		smb_rq_wstart(rqp);
		smb_rq_wend(rqp);
		smb_rq_bstart(rqp);
		smb_rq_bend(rqp);
		error = smb_rq_simple(rqp);
		if (error) {
			smb_rq_done(rqp);
			return error;
		}
		smb_rq_getreply(rqp, &mdp);
		md_get_uint16le(mdp, &units);	/* Total units per server */
		md_get_uint16le(mdp, &bpu);	/* Blocks per allocation unit */
		md_get_uint16le(mdp, &secsz);	/* Block size (in bytes) */
		md_get_uint16le(mdp, &funits);	/* Number of free units */
		smb_rq_done(rqp);

		bsize = bpu * secsz;
		bavail = units;
		bfree = funits;
	}

	sbp->f_bsize = bsize;		/* fundamental file system block size */
	sbp->f_frsize = bsize;		/* fundamental file system frag size */
	sbp->f_iosize = bsize;		/* optimal I/O size */
	sbp->f_blocks = bavail;		/* total data blocks in file system */
	sbp->f_bfree = bfree;		/* free blocks in fs */
	sbp->f_bresvd = 0;		/* reserved blocks in fs */
	sbp->f_bavail= bfree;		/* free blocks avail to non-superuser */
	sbp->f_files = 0xffff;		/* total file nodes in file system */
	sbp->f_ffree = 0xffff;		/* free file nodes to non-superuser */
	sbp->f_favail = 0xffff;		/* free file nodes in fs */
	sbp->f_fresvd = 0;		/* reserved file nodes in fs */
	return 0;
}