Пример #1
0
int
smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
{
	int error;

	if (limit == 0)
		limit = 1000000;
	else if (limit > 1)
		limit *= 4;	/* imperical */
	ctx->f_scred = scred;
	for (;;) {
		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
			error = smbfs_findnextLM1(ctx, limit);
		} else
			error = smbfs_findnextLM2(ctx, limit);
		if (error)
			return error;
		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
			if ((ctx->f_nmlen == 2 &&
			     *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
			    (ctx->f_nmlen == 4 &&
			     *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
				continue;
		} else
			if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
			    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
			     ctx->f_name[1] == '.'))
				continue;
		break;
	}
	smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
			    ctx->f_dnp->n_mount->sm_caseopt);
	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
	return 0;
}
Пример #2
0
int
smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
	const char *name, int nmlen)
{
	int caseopt = SMB_CS_NONE;
	int error;

	if (SMB_UNICODE_STRINGS(vcp)) {
		error = mb_put_padbyte(mbp);
		if (error)
			return error;
	}
	if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
		caseopt |= SMB_CS_UPPER;
	if (dnp != NULL) {
		error = smb_put_dmem(mbp, vcp, dnp->n_rpath, dnp->n_rplen, 
		    caseopt);
		if (error)
			return error;
		if (name) {
			/* Put the separator */
			if (SMB_UNICODE_STRINGS(vcp))
				error = mb_put_uint16le(mbp, '\\');
			else
				error = mb_put_uint8(mbp, '\\');
			if (error)
				return error;
			/* Put the name */
			error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt);
			if (error)
				return error;
		}
	}
	/* Put NULL terminator. */
	if (SMB_UNICODE_STRINGS(vcp))
		error = mb_put_uint16le(mbp, 0);
	else
		error = mb_put_uint8(mbp, 0);
	return error;
}
Пример #3
0
int
smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
	int caseopt)
{
	int error;

	error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
	if (error)
		return error;
	if (SMB_UNICODE_STRINGS(vcp))
		return mb_put_uint16le(mbp, 0);
	return mb_put_uint8(mbp, 0);
}
Пример #4
0
/*
 * Set DOS file attributes. mtime should be NULL for dialects above lm10
 */
int
smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
	struct smb_cred *scred)
{
	struct smb_rq *rqp;
	struct smb_share *ssp = np->n_mount->sm_share;
	struct mbchain *mbp;
	u_long time;
	int error, svtz;

	rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK);
	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
	if (error) {
		free(rqp, M_SMBFSDATA);
		return error;
	}
	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
	smb_rq_getrequest(rqp, &mbp);
	smb_rq_wstart(rqp);
	mb_put_uint16le(mbp, attr);
	if (mtime) {
		smb_time_local2server(mtime, svtz, &time);
	} else
		time = 0;
	mb_put_uint32le(mbp, time);		/* mtime */
	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
	smb_rq_wend(rqp);
	smb_rq_bstart(rqp);
	mb_put_uint8(mbp, SMB_DT_ASCII);
	do {
		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
		if (error)
			break;
		mb_put_uint8(mbp, SMB_DT_ASCII);
		if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
			mb_put_padbyte(mbp);
			mb_put_uint8(mbp, 0);	/* 1st byte of NULL Unicode char */
		}
		mb_put_uint8(mbp, 0);
		smb_rq_bend(rqp);
		error = smb_rq_simple(rqp);
		if (error) {
			SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
			break;
		}
	} while(0);
	smb_rq_done(rqp);
	free(rqp, M_SMBFSDATA);
	return error;
}
Пример #5
0
static int
smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
{
	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
		ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
	} else
		ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
	    SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
	ctx->f_attrmask = attr;
	ctx->f_wildcard = wildcard;
	ctx->f_wclen = wclen;
	return 0;
}
Пример #6
0
int
smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
	size_t size, int caseopt)
{
	struct iconv_drv *dp = vcp->vc_toserver;

	if (size == 0)
		return 0;
	if (dp == NULL) {
		return mb_put_mem(mbp, src, size, MB_MSYSTEM);
	}
	mbp->mb_copy = smb_copy_iconv;
	mbp->mb_udata = dp;
	if (SMB_UNICODE_STRINGS(vcp))
		mb_put_padbyte(mbp);
	return mb_put_mem(mbp, src, size, MB_MCUSTOM);
}
Пример #7
0
int
smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int *nmlen, int caseopt)
{
	int copt = (caseopt == SMB_CS_LOWER ? KICONV_FROM_LOWER : 
		    (caseopt == SMB_CS_UPPER ? KICONV_FROM_UPPER : 0));
	int error = 0;
	size_t ilen = *nmlen;
	size_t olen;
	char *ibuf = name;
	char outbuf[SMB_MAXFNAMELEN];
	char *obuf = outbuf;

	if (vcp->vc_tolocal) {
		olen = sizeof(outbuf);
		bzero(outbuf, sizeof(outbuf));

		/*
		error = iconv_conv_case
			(vcp->vc_tolocal, NULL, NULL, &obuf, &olen, copt);
		if (error) return error;
		*/

		error = iconv_conv_case
			(vcp->vc_tolocal, (const char **)&ibuf, &ilen, &obuf, &olen, copt);
		if (error && SMB_UNICODE_STRINGS(vcp)) {
			/*
			 * If using unicode, leaving a file name as it was when
			 * convert fails will cause a problem because the file name
			 * will contain NULL.
			 * Here, put '?' and give converted file name.
			 */
			*obuf = '?';
			olen--;
			error = 0;
		}
		if (!error) {
			*nmlen = sizeof(outbuf) - olen;
			memcpy(name, outbuf, *nmlen);
		}
	}
	return error;
}
Пример #8
0
static int
smbfs_smb_search(struct smbfs_fctx *ctx)
{
	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
	struct smb_rq *rqp;
	struct mbchain *mbp;
	struct mdchain *mdp;
	u_int8_t wc, bt;
	u_int16_t ec, dlen, bc;
	int maxent, error, iseof = 0;

	maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
	if (ctx->f_rq) {
		smb_rq_done(ctx->f_rq);
		ctx->f_rq = NULL;
	}
	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
	if (error)
		return error;
	ctx->f_rq = rqp;
	smb_rq_getrequest(rqp, &mbp);
	smb_rq_wstart(rqp);
	mb_put_uint16le(mbp, maxent);	/* max entries to return */
	mb_put_uint16le(mbp, ctx->f_attrmask);
	smb_rq_wend(rqp);
	smb_rq_bstart(rqp);
	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
		if (error)
			return error;
		mb_put_uint8(mbp, SMB_DT_VARIABLE);
		mb_put_uint16le(mbp, 0);	/* context length */
		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
	} else {
		if (SMB_UNICODE_STRINGS(vcp)) {
			mb_put_padbyte(mbp);
			mb_put_uint8(mbp, 0);
		}
		mb_put_uint8(mbp, 0);	/* file name length */
		mb_put_uint8(mbp, SMB_DT_VARIABLE);
		mb_put_uint16le(mbp, SMB_SKEYLEN);
		mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
	}
	smb_rq_bend(rqp);
	error = smb_rq_simple(rqp);
	if (error) {
		if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
			error = 0;
			iseof = 1;
			ctx->f_flags |= SMBFS_RDD_EOF;
		} else
			return error;
	}
	smb_rq_getreply(rqp, &mdp);
	md_get_uint8(mdp, &wc);
	if (wc != 1) 
		return iseof ? ENOENT : EBADRPC;
	md_get_uint16le(mdp, &ec);
	if (ec == 0)
		return ENOENT;
	ctx->f_ecnt = ec;
	md_get_uint16le(mdp, &bc);
	if (bc < 3)
		return EBADRPC;
	bc -= 3;
	md_get_uint8(mdp, &bt);
	if (bt != SMB_DT_VARIABLE)
		return EBADRPC;
	md_get_uint16le(mdp, &dlen);
	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
		return EBADRPC;
	return 0;
}
Пример #9
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;
}
Пример #10
0
int
smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
{
	struct smb_rq *rqp;
	struct mbchain *mbp;
	const smb_unichar *unipp;
	smb_uniptr ntencpass = NULL;
	char *up, *pbuf, *encpass;
	const char *pp;
	int error, plen, uniplen, ulen, upper;

	KASSERT(scred->scr_l == vcp->vc_iod->iod_l);

	upper = 0;

again:

	vcp->vc_smbuid = SMB_UID_UNKNOWN;

	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
	if (error)
		return error;
	pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
	encpass = malloc(24, M_SMBTEMP, M_WAITOK);
	if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
		/*
		 * We try w/o uppercasing first so Samba mixed case
		 * passwords work.  If that fails we come back and try
		 * uppercasing to satisfy OS/2 and Windows for Workgroups.
		 */
		if (upper) {
			iconv_convstr(vcp->vc_toupper, pbuf,
			    smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN + 1);
		} else {
			strlcpy(pbuf, smb_vc_getpass(vcp),
			    SMB_MAXPASSWORDLEN + 1);
		}
		if (!SMB_UNICODE_STRINGS(vcp))
			iconv_convstr(vcp->vc_toserver, pbuf, pbuf,
			    SMB_MAXPASSWORDLEN + 1);

		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
			uniplen = plen = 24;
			smb_encrypt(pbuf, vcp->vc_ch, encpass);
			ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
			if (SMB_UNICODE_STRINGS(vcp)) {
				strlcpy(pbuf, smb_vc_getpass(vcp),
				    SMB_MAXPASSWORDLEN + 1);
			} else
				iconv_convstr(vcp->vc_toserver, pbuf,
				    smb_vc_getpass(vcp),
				    SMB_MAXPASSWORDLEN + 1);
			smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
			pp = encpass;
			unipp = ntencpass;
		} else {
			plen = strlen(pbuf) + 1;
			pp = pbuf;
			uniplen = plen * 2;
			ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
			smb_strtouni(ntencpass, smb_vc_getpass(vcp));
			plen--;

			/*
			 * The uniplen is zeroed because Samba cannot deal
			 * with this 2nd cleartext password.  This Samba
			 * "bug" is actually a workaround for problems in
			 * Microsoft clients.
			 */
			uniplen = 0/*-= 2*/;
			unipp = ntencpass;
		}
	} else {
		/*
		 * In the share security mode password will be used
		 * only in the tree authentication
		 */
		 pp = "";
		 plen = 1;
		 unipp = &smb_unieol;
		 uniplen = 0;
	}
	smb_rq_wstart(rqp);
	mbp = &rqp->sr_rq;
	up = vcp->vc_username;
	ulen = strlen(up) + 1;
	/*
	 * If userid is null we are attempting anonymous browse login
	 * so passwords must be zero length.
	 */
	if (ulen == 1)
		plen = uniplen = 0;
	mb_put_uint8(mbp, 0xff);
	mb_put_uint8(mbp, 0);
	mb_put_uint16le(mbp, 0);
	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
	mb_put_uint16le(mbp, vcp->vc_number);
	mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
	mb_put_uint16le(mbp, plen);
	if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
		mb_put_uint32le(mbp, 0);
		smb_rq_wend(rqp);
		smb_rq_bstart(rqp);
		mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
		smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
	} else {
		mb_put_uint16le(mbp, uniplen);
		mb_put_uint32le(mbp, 0);		/* reserved */
		mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ?
				     SMB_CAP_UNICODE : 0);
		smb_rq_wend(rqp);
		smb_rq_bstart(rqp);
		mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
		mb_put_mem(mbp, (const void *)unipp, uniplen, MB_MSYSTEM);
		smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);		/* AccountName */
		smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE);	/* PrimaryDomain */
		smb_put_dstring(mbp, vcp, "NetBSD", SMB_CS_NONE);	/* Client's OS */
		smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE);		/* Client name */
	}
	smb_rq_bend(rqp);
	if (ntencpass)
		free(ntencpass, M_SMBTEMP);
	error = smb_rq_simple(rqp);
	SMBSDEBUG(("%d\n", error));
	if (error) {
		if (error == EACCES)
			error = EAUTH;
		goto bad;
	}
	vcp->vc_smbuid = rqp->sr_rpuid;
bad:
	free(encpass, M_SMBTEMP);
	free(pbuf, M_SMBTEMP);
	smb_rq_done(rqp);
	if (error && !upper && vcp->vc_sopt.sv_sm & SMB_SM_USER) {
		upper = 1;
		goto again;
	}
	return error;
}
Пример #11
0
/*
 * Called from user land so we always have a reference on the share.
 */
int 
smb_usr_check_dir(struct smb_share *share, struct smb_vc *vcp,
                  struct smb2ioc_check_dir *check_dir_ioc,
                  vfs_context_t context)
{
	int error;
    char *local_pathp = NULL;
    uint32_t local_path_len = check_dir_ioc->ioc_path_len;
    uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE;
    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
    /* Tell create, the namep is a path to an item */
    uint64_t create_flags = SMB2_CREATE_NAME_IS_PATH;
    struct smbfattr *fap = NULL;
	size_t network_path_len = PATH_MAX + 1;
	char *network_pathp = NULL;
    
    /* Assume no error */
    check_dir_ioc->ioc_ret_ntstatus = 0;
        
    /* 
     * Compound Create/Close call should be sufficient. 
     * If item exists, verify it is a dir.
     */
    
	/* Take the 32 bit world pointers and convert them to user_addr_t. */
	if (!vfs_context_is64bit(context)) {
		check_dir_ioc->ioc_kern_path = CAST_USER_ADDR_T(check_dir_ioc->ioc_path);
	}
	
    if (!(check_dir_ioc->ioc_kern_path)) {
        error = EINVAL;
        goto bad;
    }

    /* local_path_len includes the null byte, ioc_kern_path is a c-style string */
	if (check_dir_ioc->ioc_kern_path && local_path_len) {
		local_pathp = smb_memdupin(check_dir_ioc->ioc_kern_path,
                                   local_path_len);
	}

    if (local_pathp == NULL) {
        SMBERROR("smb_memdupin failed\n");
        error = ENOMEM;
        goto bad;
    }

    /*
     * Need to convert from local path to a network path 
     */
	SMB_MALLOC(network_pathp, char *, network_path_len, M_TEMP, M_WAITOK | M_ZERO);
	if (network_pathp == NULL) {
		error = ENOMEM;
		goto bad;		
	}

	error = smb_convert_path_to_network(local_pathp, local_path_len,
                                        network_pathp, &network_path_len,
										'\\', SMB_UTF_SFM_CONVERSIONS,
                                        SMB_UNICODE_STRINGS(vcp));
	if (error) {
		SMBERROR("smb_convert_path_to_network failed : %d\n", error);
		goto bad;
	}
    
    /* 
     * Set up for Compound Create/Close call 
     */
    SMB_MALLOC(fap,
               struct smbfattr *, 
               sizeof(struct smbfattr), 
               M_SMBTEMP, 
               M_WAITOK | M_ZERO);
    if (fap == NULL) {
        SMBERROR("SMB_MALLOC failed\n");
        error = ENOMEM;
        goto bad;
    }

    /* Send a Create/Close */
    error = smb2fs_smb_cmpd_create(share, NULL,
                                   network_pathp, network_path_len,
                                   NULL, 0,
                                   desired_access, VDIR,
                                   share_access, FILE_OPEN,
                                   create_flags, &check_dir_ioc->ioc_ret_ntstatus,
                                   NULL, fap,
                                   NULL, context);
	if (error) {
		goto bad;
	}
    
    /* found something, verify its a dir */
    if (!(fap->fa_attr & SMB_EFA_DIRECTORY)) {
        error = ENOTDIR;
        check_dir_ioc->ioc_ret_ntstatus = STATUS_NOT_A_DIRECTORY;
    }

bad:    
    if (local_pathp) {
        SMB_FREE(local_pathp, M_SMBSTR);
    }
    
    if (network_pathp) {
        SMB_FREE(network_pathp, M_SMBSTR);
    }

    if (fap) {
        SMB_FREE(fap, M_SMBTEMP);
    }

	return error;
}
Пример #12
0
int
smb_usr_get_dfs_referral(struct smb_share *share, struct smb_vc *vcp,
                         struct smb2ioc_get_dfs_referral *get_dfs_refer_ioc,
                         vfs_context_t context)
{
	int error;
 	struct smb2_ioctl_rq *ioctlp = NULL;
 	struct smb2_get_dfs_referral dfs_referral;
    char *local_pathp = NULL;
    uint32_t local_path_len = get_dfs_refer_ioc->ioc_file_name_len;
	size_t network_path_len = PATH_MAX + 1;
	char *network_pathp = NULL;
    
    SMB_MALLOC(ioctlp,
               struct smb2_ioctl_rq *, 
               sizeof(struct smb2_ioctl_rq), 
               M_SMBTEMP, 
               M_WAITOK | M_ZERO);
    if (ioctlp == NULL) {
		SMBERROR("SMB_MALLOC failed\n");
        error = ENOMEM;
        goto bad;
    }

again:
	/* Take the 32 bit world pointers and convert them to user_addr_t. */
    bzero(&dfs_referral, sizeof(dfs_referral));

    dfs_referral.file_namep = NULL;
    dfs_referral.max_referral_level = get_dfs_refer_ioc->ioc_max_referral_level;
    
	if (!vfs_context_is64bit (context)) {
		get_dfs_refer_ioc->ioc_kern_file_name = CAST_USER_ADDR_T(get_dfs_refer_ioc->ioc_file_name);
	}
	
    if (!(get_dfs_refer_ioc->ioc_kern_file_name)) {
        error = EINVAL;
        goto bad;
    }

	/* ioc_file_name_len includes the null byte, ioc_kern_file_name is a c-style string */
	if (get_dfs_refer_ioc->ioc_kern_file_name && get_dfs_refer_ioc->ioc_file_name_len) {
		local_pathp = smb_memdupin(get_dfs_refer_ioc->ioc_kern_file_name,
                                   local_path_len);
	}

    if (local_pathp == NULL) {
        SMBERROR("smb_memdupin failed\n");
        error = ENOMEM;
        goto bad;
    }

    /*
     * Need to convert from local path to a network path 
     */
	SMB_MALLOC(network_pathp, char *, network_path_len, M_TEMP, M_WAITOK | M_ZERO);
	if (network_pathp == NULL) {
		error = ENOMEM;
		goto bad;		
	}
    
	error = smb_convert_path_to_network(local_pathp, local_path_len,
                                        network_pathp, &network_path_len,
										'\\', SMB_UTF_SFM_CONVERSIONS,
                                        SMB_UNICODE_STRINGS(vcp));
	if (error) {
		SMBERROR("smb_convert_path_to_network failed : %d\n", error);
		goto bad;
	}

    dfs_referral.file_namep = network_pathp;
    dfs_referral.file_name_len = (uint32_t) network_path_len;
    
    /* Take 32 bit world pointers and convert them to user_addr_t. */
    if (get_dfs_refer_ioc->ioc_rcv_output_len > 0) {
        if (vfs_context_is64bit(context)) {
            ioctlp->rcv_output_uio = uio_create(1, 0, UIO_USERSPACE64, UIO_READ);
        }
        else {
            get_dfs_refer_ioc->ioc_kern_rcv_output = CAST_USER_ADDR_T(get_dfs_refer_ioc->ioc_rcv_output);
            ioctlp->rcv_output_uio = uio_create(1, 0, UIO_USERSPACE32, UIO_READ);
        }
        
        if (ioctlp->rcv_output_uio) {
            uio_addiov(ioctlp->rcv_output_uio,
                       get_dfs_refer_ioc->ioc_kern_rcv_output, 
                       get_dfs_refer_ioc->ioc_rcv_output_len);
        } 
        else {
            error = ENOMEM;
            SMBERROR("uio_create failed\n");
            goto bad;
        }
    }

    ioctlp->share = share;
    ioctlp->ctl_code = FSCTL_DFS_GET_REFERRALS;
    ioctlp->fid = -1;
    
	ioctlp->snd_input_buffer = (uint8_t *) &dfs_referral;
	ioctlp->snd_input_len = sizeof(struct smb2_get_dfs_referral);
	ioctlp->snd_output_len = 0;
    
	ioctlp->rcv_input_len = 0;
    
    /* Handle servers that dislike large output buffer lengths */
    if (vcp->vc_misc_flags & SMBV_63K_IOCTL) {
        ioctlp->rcv_output_len = kSMB_63K;
    }
    else {
        ioctlp->rcv_output_len = get_dfs_refer_ioc->ioc_rcv_output_len;
    }

    /* Now do the real work */
	error = smb2_smb_ioctl(share, ioctlp, NULL, context);
    
    if ((error) &&
        (ioctlp->ret_ntstatus == STATUS_INVALID_PARAMETER) &&
        !(vcp->vc_misc_flags & SMBV_63K_IOCTL)) {
        /*
         * <14281932> Could this be a server that can not handle
         * larger than 65535 bytes in an IOCTL? 
         */
        SMBWARNING("SMB 2/3 server cant handle large OutputBufferLength in DFS Referral. Reducing to 63Kb.\n");
        vcp->vc_misc_flags |= SMBV_63K_IOCTL;
        
        ioctlp->ret_ntstatus = 0;
        
        if (ioctlp->snd_input_uio != NULL) {
            uio_free(ioctlp->snd_input_uio);
            ioctlp->snd_input_uio = NULL;
        }
        if (ioctlp->snd_output_uio != NULL) {
            uio_free(ioctlp->snd_output_uio);
            ioctlp->snd_output_uio = NULL;
        }
        if (ioctlp->rcv_input_uio != NULL) {
            uio_free(ioctlp->rcv_input_uio);
            ioctlp->rcv_input_uio = NULL;
        }
        if (ioctlp->rcv_output_uio != NULL) {
            uio_free(ioctlp->rcv_output_uio);
            ioctlp->rcv_output_uio = NULL;
        }

        goto again;
    }    
    
    /* always return the ntstatus error */
    get_dfs_refer_ioc->ioc_ret_ntstatus = ioctlp->ret_ntstatus;
	if (error) {
		goto bad;
	}
    
    /* Fill in actual bytes returned */
    get_dfs_refer_ioc->ioc_ret_output_len = ioctlp->ret_output_len;
    
bad:    
    if (ioctlp != NULL) {
        if (ioctlp->snd_input_uio != NULL) {
            uio_free(ioctlp->snd_input_uio);
        }
        if (ioctlp->snd_output_uio != NULL) {
            uio_free(ioctlp->snd_output_uio);
        }
        if (ioctlp->rcv_input_uio != NULL) {
            uio_free(ioctlp->rcv_input_uio);
        }
        if (ioctlp->rcv_output_uio != NULL) {
            uio_free(ioctlp->rcv_output_uio);
        }
        SMB_FREE(ioctlp, M_SMBTEMP);
    }
    
    if (local_pathp) {
        SMB_FREE(local_pathp, M_SMBSTR);
    }
    
    if (network_pathp) {
        SMB_FREE(network_pathp, M_SMBSTR);
    }

    return error;
}
Пример #13
0
/*
 * Perform a full round of TRANS2 request
 */
static int
smb_t2_request_int(struct smb_t2rq *t2p)
{
	struct smb_vc *vcp = t2p->t2_vc;
	struct smb_cred *scred = t2p->t2_cred;
	struct mbchain *mbp;
	struct mdchain *mdp, mbparam, mbdata;
	mblk_t *m;
	struct smb_rq *rqp;
	int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
	int error, doff, poff, txdcount, txpcount, nmlen, nmsize;

	m = t2p->t2_tparam.mb_top;
	if (m) {
		md_initm(&mbparam, m);	/* do not free it! */
		totpcount = m_fixhdr(m);
		if (totpcount > 0xffff)		/* maxvalue for ushort_t */
			return (EINVAL);
	} else
		totpcount = 0;
	m = t2p->t2_tdata.mb_top;
	if (m) {
		md_initm(&mbdata, m);	/* do not free it! */
		totdcount =  m_fixhdr(m);
		if (totdcount > 0xffff)
			return (EINVAL);
	} else
		totdcount = 0;
	leftdcount = totdcount;
	leftpcount = totpcount;
	txmax = vcp->vc_txmax;
	error = smb_rq_alloc(t2p->t2_source, t2p->t_name ?
	    SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
	if (error)
		return (error);
	rqp->sr_timo = smb_timo_default;
	rqp->sr_flags |= SMBR_MULTIPACKET;
	t2p->t2_rq = rqp;
	mbp = &rqp->sr_rq;
	smb_rq_wstart(rqp);
	mb_put_uint16le(mbp, totpcount);
	mb_put_uint16le(mbp, totdcount);
	mb_put_uint16le(mbp, t2p->t2_maxpcount);
	mb_put_uint16le(mbp, t2p->t2_maxdcount);
	mb_put_uint8(mbp, t2p->t2_maxscount);
	mb_put_uint8(mbp, 0);			/* reserved */
	mb_put_uint16le(mbp, 0);			/* flags */
	mb_put_uint32le(mbp, 0);			/* Timeout */
	mb_put_uint16le(mbp, 0);			/* reserved 2 */
	len = mb_fixhdr(mbp);

	/*
	 * Now we know the size of the trans overhead stuff:
	 * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + nmsize),
	 * where nmsize is the OTW size of the name, including
	 * the unicode null terminator and any alignment.
	 * Use this to decide which parts (and how much)
	 * can go into this request: params, data
	 */
	nmlen = t2p->t_name ? t2p->t_name_len : 0;
	nmsize = nmlen + 1; /* null term. */
	if (SMB_UNICODE_STRINGS(vcp)) {
		nmsize *= 2;
		/* we know put_dmem will need to align */
		nmsize += 1;
	}
	len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmsize);
	if (len + leftpcount > txmax) {
		txpcount = min(leftpcount, txmax - len);
		poff = len;
		txdcount = 0;
		doff = 0;
	} else {
		txpcount = leftpcount;
		poff = txpcount ? len : 0;
		/*
		 * Other client traffic seems to "ALIGN2" here.  The extra
		 * 2 byte pad we use has no observed downside and may be
		 * required for some old servers(?)
		 */
		len = ALIGN4(len + txpcount);
		txdcount = min(leftdcount, txmax - len);
		doff = txdcount ? len : 0;
	}
	leftpcount -= txpcount;
	leftdcount -= txdcount;
	mb_put_uint16le(mbp, txpcount);
	mb_put_uint16le(mbp, poff);
	mb_put_uint16le(mbp, txdcount);
	mb_put_uint16le(mbp, doff);
	mb_put_uint8(mbp, t2p->t2_setupcount);
	mb_put_uint8(mbp, 0);
	for (i = 0; i < t2p->t2_setupcount; i++) {
		mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
	}
	smb_rq_wend(rqp);
	smb_rq_bstart(rqp);
	if (t2p->t_name) {
		/* Put the string and terminating null. */
		smb_put_dmem(mbp, vcp, t2p->t_name, nmlen + 1,
		    SMB_CS_NONE, NULL);
	} else {
		/* nmsize accounts for padding, char size. */
		mb_put_mem(mbp, NULL, nmsize, MB_MZERO);
	}
	len = mb_fixhdr(mbp);
	if (txpcount) {
		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
		error = md_get_mbuf(&mbparam, txpcount, &m);
		SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
		if (error)
			goto freerq;
		mb_put_mbuf(mbp, m);
	}
	len = mb_fixhdr(mbp);
	if (txdcount) {
		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
		error = md_get_mbuf(&mbdata, txdcount, &m);
		if (error)
			goto freerq;
		mb_put_mbuf(mbp, m);
	}
	smb_rq_bend(rqp);	/* incredible, but thats it... */
	error = smb_rq_enqueue(rqp);
	if (error)
		goto freerq;
	if (leftpcount || leftdcount) {
		error = smb_rq_reply(rqp);
		if (error)
			goto bad;
		/*
		 * this is an interim response, ignore it.
		 */
		SMBRQ_LOCK(rqp);
		md_next_record(&rqp->sr_rp);
		SMBRQ_UNLOCK(rqp);
	}
	while (leftpcount || leftdcount) {
		error = smb_rq_new(rqp, t2p->t_name ?
		    SMB_COM_TRANSACTION_SECONDARY :
		    SMB_COM_TRANSACTION2_SECONDARY);
		if (error)
			goto bad;
		mbp = &rqp->sr_rq;
		smb_rq_wstart(rqp);
		mb_put_uint16le(mbp, totpcount);
		mb_put_uint16le(mbp, totdcount);
		len = mb_fixhdr(mbp);
		/*
		 * now we have known packet size as
		 * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
		 * and need to decide which parts should go into request
		 */
		len = ALIGN4(len + 6 * 2 + 2);
		if (t2p->t_name == NULL)
			len += 2;
		if (len + leftpcount > txmax) {
			txpcount = min(leftpcount, txmax - len);
			poff = len;
			txdcount = 0;
			doff = 0;
		} else {
			txpcount = leftpcount;
			poff = txpcount ? len : 0;
			len = ALIGN4(len + txpcount);
			txdcount = min(leftdcount, txmax - len);
			doff = txdcount ? len : 0;
		}
		mb_put_uint16le(mbp, txpcount);
		mb_put_uint16le(mbp, poff);
		mb_put_uint16le(mbp, totpcount - leftpcount);
		mb_put_uint16le(mbp, txdcount);
		mb_put_uint16le(mbp, doff);
		mb_put_uint16le(mbp, totdcount - leftdcount);
		leftpcount -= txpcount;
		leftdcount -= txdcount;
		if (t2p->t_name == NULL)
			mb_put_uint16le(mbp, t2p->t2_fid);
		smb_rq_wend(rqp);
		smb_rq_bstart(rqp);
		mb_put_uint8(mbp, 0);	/* name */
		len = mb_fixhdr(mbp);
		if (txpcount) {
			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
			error = md_get_mbuf(&mbparam, txpcount, &m);
			if (error)
				goto bad;
			mb_put_mbuf(mbp, m);
		}
		len = mb_fixhdr(mbp);
		if (txdcount) {
			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
			error = md_get_mbuf(&mbdata, txdcount, &m);
			if (error)
				goto bad;
			mb_put_mbuf(mbp, m);
		}
		smb_rq_bend(rqp);
		error = smb_iod_multirq(rqp);
		if (error)
			goto bad;
	}	/* while left params or data */
	error = smb_t2_reply(t2p);
	if (error && !(t2p->t2_flags & SMBT2_MOREDATA))
		goto bad;
	mdp = &t2p->t2_rdata;
	if (mdp->md_top) {
		m_fixhdr(mdp->md_top);
		md_initm(mdp, mdp->md_top);
	}
	mdp = &t2p->t2_rparam;
	if (mdp->md_top) {
		m_fixhdr(mdp->md_top);
		md_initm(mdp, mdp->md_top);
	}
bad:
	smb_iod_removerq(rqp);
freerq:
	if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) {
		if (rqp->sr_flags & SMBR_RESTART)
			t2p->t2_flags |= SMBT2_RESTART;
		md_done(&t2p->t2_rparam);
		md_done(&t2p->t2_rdata);
	}
	smb_rq_done(rqp);
	return (error);
}