Example #1
0
/*
 * smbrdr_handle_setup
 *
 * Allocates a buffer for sending/receiving a SMB request.
 * Initialize a smb_msgbuf structure with the allocated buffer.
 * Setup given handle (srh) with the specified information.
 *
 * Returns:
 *
 *	NT_STATUS_NO_MEMORY		not enough memory
 *	NT_STATUS_SUCCESS		successful
 */
static DWORD
smbrdr_handle_setup(smbrdr_handle_t *srh,
			unsigned char cmd,
			struct sdb_session *session,
			struct sdb_logon *logon,
			struct sdb_netuse *netuse)
{
	srh->srh_buf = (unsigned char *)malloc(SMBRDR_REQ_BUFSZ);
	if (srh->srh_buf == NULL)
		return (NT_STATUS_NO_MEMORY);

	bzero(srh->srh_buf, SMBRDR_REQ_BUFSZ);

	srh->srh_mbflags = (session->remote_caps & CAP_UNICODE)
	    ? SMB_MSGBUF_UNICODE : 0;

	smb_msgbuf_init(&srh->srh_mbuf, srh->srh_buf,
	    SMBRDR_REQ_BUFSZ, srh->srh_mbflags);

	srh->srh_cmd = cmd;
	srh->srh_session = session;
	srh->srh_user = logon;
	srh->srh_tree = netuse;

	return (NT_STATUS_SUCCESS);
}
Example #2
0
/*
 * smbrdr_rcv
 *
 * Receive a SMB response and decode the packet header.
 *
 * "Implementing CIFS" book, SMB requests always have an even sequence
 * number and replies always have an odd.
 *
 * With the original code, if the SMB Redirector skip the counter increment
 * in the event of any failure during SmbSessionSetupAndX, it causes the
 * domain controller to fail the next SMB request(odd sequence number)
 * with ACCESS_DENIED.
 *
 * Smbrdr module should use the same sequence number (i.e. ssc_seqnum of the
 * SMB Sign context) for generating the MAC signature for all incoming
 * responses per SmbTransact request. Otherwise, the validation will fail.
 * It is now fixed by decrementing the sequence number prior to validating
 * the subsequent responses for a single request.
 *
 * Returns:
 *
 *	status code returned by smbrdr_hdr_process()
 *	NT_STATUS_UNEXPECTED_NETWORK_ERROR	receive failed
 *	NT_STATUS_SUCCESS					successful
 */
DWORD
smbrdr_rcv(smbrdr_handle_t *srh, int is_first_rsp)
{
	smb_hdr_t smb_hdr;
	DWORD status;
	int rc;
	smb_sign_ctx_t *sign_ctx = &srh->srh_session->sign_ctx;

	rc = nb_rcv(srh->srh_session->sock, srh->srh_buf, SMBRDR_REQ_BUFSZ, 0);
	if (rc < 0) {
		smb_mac_inc_seqnum(sign_ctx);
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_rcv[%d]: receive failed (%d)", srh->srh_cmd, rc);
		return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
	}

	smb_msgbuf_init(&srh->srh_mbuf, srh->srh_buf, rc, srh->srh_mbflags);

	status = smbrdr_hdr_process(srh, &smb_hdr);
	if (status != NT_STATUS_SUCCESS) {
		smb_mac_inc_seqnum(sign_ctx);
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_rcv[%d]: failed (%s)", srh->srh_cmd,
		    xlate_nt_status(status));
		return (status);
	}

	if (!is_first_rsp)
		smb_mac_dec_seqnum(sign_ctx);

	if (!smbrdr_sign_chk(sign_ctx,
	    &srh->srh_mbuf, smb_hdr.extra.extra.security_sig)) {
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_rcv[%d]: bad signature", srh->srh_cmd);
		return (NT_STATUS_INVALID_NETWORK_RESPONSE);
	}

	return (NT_STATUS_SUCCESS);
}
Example #3
0
/*
 * smbrdr_exchange
 *
 * Send the SMB packet pointed by the given handle over
 * network. Receive the response and decode the packet header.
 *
 * From "Implementing CIFS" book, SMB requests always have an even sequence
 * number and replies always have an odd.
 *
 * With the original code, if the SMB Redirector skips the counter increment
 * in the event of any failure during SmbSessionSetupAndX, it causes the
 * domain controller to fail the next SMB request(odd sequence number)
 * with ACCESS_DENIED.
 *
 * Returns:
 *
 *	status code returned by smbrdr_hdr_process()
 *	NT_STATUS_INTERNAL_ERROR		crypto framework failure
 *	NT_STATUS_UNEXPECTED_NETWORK_ERROR	send/receive failed
 *	NT_STATUS_SUCCESS			successful
 */
DWORD
smbrdr_exchange(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr, long timeout)
{
	smb_sign_ctx_t *sign_ctx;
	smb_msgbuf_t *mb;
	DWORD status;
	int rc;

	smbrdr_lock_transport();

	mb = &srh->srh_mbuf;
	sign_ctx = &srh->srh_session->sign_ctx;

	if (smbrdr_sign(sign_ctx, mb) != SMBAUTH_SUCCESS) {
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_exchange[%d]: signing failed", srh->srh_cmd);
		smbrdr_unlock_transport();
		return (NT_STATUS_INTERNAL_ERROR);
	}

	rc = nb_exchange(srh->srh_session->sock,
	    srh->srh_buf, smb_msgbuf_used(mb),
	    srh->srh_buf, SMBRDR_REQ_BUFSZ, timeout);

	if (rc < 0) {
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_exchange[%d]: failed (%d)", srh->srh_cmd, rc);

		if (srh->srh_cmd != SMB_COM_ECHO) {
			/*
			 * Since SMB echo is used to check the session
			 * status then don't destroy the session if it's
			 * SMB echo.
			 */
			srh->srh_session->state = SDB_SSTATE_STALE;
		}
		smb_mac_inc_seqnum(sign_ctx);
		smbrdr_unlock_transport();
		return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
	}

	/* initialize for processing response */
	smb_msgbuf_init(mb, srh->srh_buf, rc, srh->srh_mbflags);

	status = smbrdr_hdr_process(srh, smb_hdr);
	if (status != NT_STATUS_SUCCESS) {
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_exchange[%d]: failed (%s)", srh->srh_cmd,
		    xlate_nt_status(status));
		smb_mac_inc_seqnum(sign_ctx);
		smbrdr_unlock_transport();
		return (status);
	}

	/* Signature validation */
	if (!smbrdr_sign_chk(sign_ctx, mb, smb_hdr->extra.extra.security_sig)) {
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_exchange[%d]: bad signature", srh->srh_cmd);
		smbrdr_unlock_transport();
		return (NT_STATUS_INVALID_NETWORK_RESPONSE);
	}

	smbrdr_unlock_transport();
	return (NT_STATUS_SUCCESS);
}
Example #4
0
/*
 * smb_trans2_mbc_encode
 *
 * This function encodes the mbc for one directory entry.
 *
 * The function returns -1 when the max data requested by client
 * is reached. If the entry is valid and successful encoded, 0
 * will be returned; otherwise, 1 will be returned.
 *
 * We always null terminate the filename. The space for the null
 * is included in the maxdata calculation and is therefore included
 * in the next_entry_offset. namelen is the unterminated length of
 * the filename. For levels except STANDARD and EA_SIZE, if the
 * filename is ascii the name length returned to the client should
 * include the null terminator. Otherwise the length returned to
 * the client should not include the terminator.
 *
 * Returns: 0 - data successfully encoded
 *          1 - client request's maxdata limit reached
 *	   -1 - error
 */
static int
smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
    smb_fileinfo_t *fileinfo, smb_find_args_t *args)
{
	int		namelen, shortlen;
	uint32_t	next_entry_offset;
	uint32_t	dsize32, asize32;
	uint32_t	mb_flags = 0;
	uint32_t	resume_key;
	char		buf83[26];
	smb_msgbuf_t	mb;

	namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
	if (namelen == -1)
		return (-1);

	/*
	 * If ascii the filename length returned to the client should
	 * include the null terminator for levels except STANDARD and
	 * EASIZE.
	 */
	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
		if ((args->fa_infolev != SMB_INFO_STANDARD) &&
		    (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
			namelen += 1;
	}

	next_entry_offset = args->fa_maxdata + namelen;

	if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
		return (1);

	mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
	dsize32 = (fileinfo->fi_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_size;
	asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;

	resume_key = fileinfo->fi_cookie;
	if (smbd_use_resume_keys == 0)
		resume_key = 0;

	/*
	 * This switch handles all the "information levels" (formats)
	 * that we support.  Note that all formats have the file name
	 * placed after some fixed-size data, and the code to write
	 * the file name is factored out at the end of this switch.
	 */
	switch (args->fa_infolev) {
	case SMB_INFO_STANDARD:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    resume_key);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    namelen);
		break;

	case SMB_INFO_QUERY_EA_SIZE:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    resume_key);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    0L,		/* EA Size */
		    namelen);
		break;

	case SMB_FIND_FILE_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen);
		break;

	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll", sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L);
		break;

	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.q", sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    fileinfo->fi_nodeid);
		break;

	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c",
		    sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_ascii_or_unicode_strlen(sr,
		    fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb,
		    "%llTTTTqqlllb.24c2.q",
		    sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83,
		    fileinfo->fi_nodeid);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_NAMES_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lll", sr,
		    next_entry_offset,
		    resume_key,
		    namelen);
		break;

	default:
		/* invalid info. level */
		return (-1);
	}

	/*
	 * At this point we have written all the fixed-size data
	 * for the specified info. level, and we're about to put
	 * the file name string in the message.  We may later
	 * need the offset in the trans2 data where this string
	 * is placed, so save the message position now.  Note:
	 * We also need to account for the alignment padding
	 * that may precede the unicode string.
	 */
	args->fa_lno = xa->rep_data_mb.chain_offset;
	if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 &&
	    (args->fa_lno & 1) != 0)
		args->fa_lno++;

	(void) smb_mbc_encodef(&xa->rep_data_mb, "%u", sr,
	    fileinfo->fi_name);

	return (0);
}
Example #5
0
smb_sdrc_t
smb_com_negotiate(smb_request_t *sr)
{
	smb_session_t 		*session = sr->session;
	smb_arg_negotiate_t	*negprot = sr->sr_negprot;
	uint16_t		secmode;
	uint32_t		sesskey;
	char			*nbdomain;
	uint8_t			*wcbuf;
	int			wclen;
	smb_msgbuf_t		mb;
	int			rc;

	if (session->s_state != SMB_SESSION_STATE_ESTABLISHED) {
		/* The protocol has already been negotiated. */
		smbsr_error(sr, 0, ERRSRV, ERRerror);
		return (SDRC_ERROR);
	}

	/*
	 * Special case for negotiating SMB2 from SMB1.  The client
	 * includes the  "SMB 2..." dialects in the SMB1 negotiate,
	 * and if SMB2 is enabled, we choose one of those and then
	 * send an SMB2 reply to that SMB1 request.  Yes, it's very
	 * strange, but this SMB1 request can have an SMB2 reply!
	 * To accomplish this, we let the SMB2 code send the reply
	 * and return the special code SDRC_NO_REPLY to the SMB1
	 * dispatch logic so it will NOT send an SMB1 reply.
	 * (Or possibly send an SMB1 error reply.)
	 */
	if (negprot->ni_dialect >= DIALECT_SMB2002) {
		rc = smb1_negotiate_smb2(sr);
		ASSERT(rc == SDRC_NO_REPLY ||
		    rc == SDRC_DROP_VC || rc == SDRC_ERROR);
		return (rc);
	}

	session->secmode = NEGOTIATE_ENCRYPT_PASSWORDS |
	    NEGOTIATE_USER_SECURITY;
	secmode = session->secmode;
	sesskey = session->sesskey;

	negprot->ni_servertime.tv_sec = gethrestime_sec();
	negprot->ni_servertime.tv_nsec = 0;
	negprot->ni_tzcorrection = sr->sr_gmtoff / 60;
	negprot->ni_maxmpxcount = sr->sr_cfg->skc_maxworkers;
	negprot->ni_keylen = SMB_CHALLENGE_SZ;
	bcopy(&session->challenge_key, negprot->ni_key, SMB_CHALLENGE_SZ);
	nbdomain = sr->sr_cfg->skc_nbdomain;

	/*
	 * UNICODE support is required for long share names,
	 * long file names and streams.  Note: CAP_RAW_MODE
	 * is not supported because it does nothing to help
	 * modern clients and causes nasty complications.
	 */
	negprot->ni_capabilities = CAP_LARGE_FILES
	    | CAP_UNICODE
	    | CAP_NT_SMBS
	    | CAP_STATUS32
	    | CAP_NT_FIND
	    | CAP_LEVEL_II_OPLOCKS
	    | CAP_LOCK_AND_READ
	    | CAP_RPC_REMOTE_APIS
	    | CAP_LARGE_READX
	    | CAP_LARGE_WRITEX
	    | CAP_DFS;

	if (smb_cap_passthru)
		negprot->ni_capabilities |= CAP_INFOLEVEL_PASSTHRU;
	else
		cmn_err(CE_NOTE, "smbsrv: cap passthru is %s",
		    (negprot->ni_capabilities & CAP_INFOLEVEL_PASSTHRU) ?
		    "enabled" : "disabled");

	switch (negprot->ni_dialect) {
	case PC_NETWORK_PROGRAM_1_0:	/* core */
		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
		    SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf,
		    sizeof (smb_dos_tcp_rcvbuf), CRED());
		rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
		    negprot->ni_index, 0);
		break;

	case Windows_for_Workgroups_3_1a:
	case PCLAN1_0:
	case MICROSOFT_NETWORKS_1_03:
	case MICROSOFT_NETWORKS_3_0:
	case LANMAN1_0:
	case LM1_2X002:
	case DOS_LM1_2X002:
		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
		    SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf,
		    sizeof (smb_dos_tcp_rcvbuf), CRED());
		sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
		rc = smbsr_encode_result(sr, 13, VAR_BCC,
		    "bwwwwwwlYww2.w#c",
		    13,				/* wct */
		    negprot->ni_index,		/* dialect index */
		    secmode,			/* security mode */
		    SMB_DOS_MAXBUF,		/* max buffer size */
		    1,				/* max MPX */
		    1,				/* max VCs */
		    0,				/* read/write raw */
		    sesskey,			/* session key */
		    negprot->ni_servertime.tv_sec, /* server date/time */
		    negprot->ni_tzcorrection,
		    (uint16_t)negprot->ni_keylen, /* encryption key length */
						/* reserved field handled 2. */
		    VAR_BCC,
		    (int)negprot->ni_keylen,
		    negprot->ni_key);		/* encryption key */
		break;

	case DOS_LANMAN2_1:
	case LANMAN2_1:
		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
		    SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf,
		    sizeof (smb_dos_tcp_rcvbuf), CRED());
		sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
		rc = smbsr_encode_result(sr, 13, VAR_BCC,
		    "bwwwwwwlYww2.w#cs",
		    13,				/* wct */
		    negprot->ni_index,		/* dialect index */
		    secmode,			/* security mode */
		    SMB_DOS_MAXBUF,		/* max buffer size */
		    1,				/* max MPX */
		    1,				/* max VCs */
		    0,				/* read/write raw */
		    sesskey,			/* session key */
		    negprot->ni_servertime.tv_sec, /* server date/time */
		    negprot->ni_tzcorrection,
		    (uint16_t)negprot->ni_keylen, /* encryption key length */
						/* reserved field handled 2. */
		    VAR_BCC,
		    (int)negprot->ni_keylen,
		    negprot->ni_key,		/* encryption key */
		    nbdomain);
		break;

	case NT_LM_0_12:
		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
		    SO_RCVBUF, (const void *)&smb_nt_tcp_rcvbuf,
		    sizeof (smb_nt_tcp_rcvbuf), CRED());

		/*
		 * Allow SMB signatures if using encrypted passwords
		 */
		if ((secmode & NEGOTIATE_ENCRYPT_PASSWORDS) &&
		    sr->sr_cfg->skc_signing_enable) {
			secmode |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
			if (sr->sr_cfg->skc_signing_required)
				secmode |=
				    NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;

			session->secmode = secmode;
		}

		/*
		 * Does the client want Extended Security?
		 * (and if we have it enabled)
		 * If so, handle as if a different dialect.
		 */
		if ((sr->smb_flg2 & SMB_FLAGS2_EXT_SEC) && smb_cap_ext_sec)
			goto NT_LM_0_12_ext_sec;
		sr->smb_flg2 &= ~SMB_FLAGS2_EXT_SEC;

		/*
		 * nbdomain is not expected to be aligned.
		 * Use temporary buffer to avoid alignment padding
		 */
		wclen = smb_wcequiv_strlen(nbdomain) + sizeof (smb_wchar_t);
		wcbuf = smb_srm_zalloc(sr, wclen);
		smb_msgbuf_init(&mb, wcbuf, wclen, SMB_MSGBUF_UNICODE);
		if (smb_msgbuf_encode(&mb, "U", nbdomain) < 0) {
			smb_msgbuf_term(&mb);
			smbsr_error(sr, 0, ERRSRV, ERRerror);
			return (SDRC_ERROR);
		}

		rc = smbsr_encode_result(sr, 17, VAR_BCC,
		    "bwbwwllllTwbw#c#c",
		    17,				/* wct */
		    negprot->ni_index,		/* dialect index */
		    secmode,			/* security mode */
		    negprot->ni_maxmpxcount,	/* max MPX */
		    1,				/* max VCs */
		    (DWORD)smb_maxbufsize,	/* max buffer size */
		    0xFFFF,			/* max raw size */
		    sesskey,			/* session key */
		    negprot->ni_capabilities,
		    &negprot->ni_servertime,	/* system time */
		    negprot->ni_tzcorrection,
		    negprot->ni_keylen,		/* encryption key length */
		    VAR_BCC,
		    (int)negprot->ni_keylen,
		    negprot->ni_key,		/* encryption key */
		    wclen,
		    wcbuf);			/* nbdomain (unicode) */

		smb_msgbuf_term(&mb);
		break;

NT_LM_0_12_ext_sec:
		/*
		 * This is the "Extended Security" variant of
		 * dialect NT_LM_0_12.
		 */
		negprot->ni_capabilities |= CAP_EXTENDED_SECURITY;

		rc = smbsr_encode_result(sr, 17, VAR_BCC,
		    "bwbwwllllTwbw#c#c",
		    17,				/* wct */
		    negprot->ni_index,		/* dialect index */
		    secmode,			/* security mode */
		    negprot->ni_maxmpxcount,	/* max MPX */
		    1,				/* max VCs */
		    (DWORD)smb_maxbufsize,	/* max buffer size */
		    0xFFFF,			/* max raw size */
		    sesskey,			/* session key */
		    negprot->ni_capabilities,
		    &negprot->ni_servertime,	/* system time */
		    negprot->ni_tzcorrection,
		    0,		/* encryption key length (MBZ) */
		    VAR_BCC,
		    UUID_LEN,
		    sr->sr_cfg->skc_machine_uuid,
		    sr->sr_cfg->skc_negtok_len,
		    sr->sr_cfg->skc_negtok);
		break;


	default:
		rc = smbsr_encode_result(sr, 1, 0, "bww", 1, -1, 0);
		break;
	}

	if (rc != 0)
		return (SDRC_ERROR);

	/*
	 * Save the agreed dialect. Note that the state is also
	 * used to detect and reject attempts to re-negotiate.
	 */
	session->dialect = negprot->ni_dialect;
	session->s_state = SMB_SESSION_STATE_NEGOTIATED;

	/* Allow normal SMB1 requests now. */
	session->newrq_func = smb1sr_newrq;

	return (SDRC_SUCCESS);
}
Example #6
0
/*
 * This function builds a response for a NetShareEnum RAP request.
 * List of shares is scanned twice. In the first round the total number
 * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
 * and also the number of shares that fit in the given buffer are calculated.
 * In the second round the shares data are encoded in the buffer.
 *
 * The data associated with each share has two parts, a fixed size part and
 * a variable size part which is share's comment. The outline of the response
 * buffer is so that fixed part for all the shares will appear first and follows
 * with the comments for all those shares and that's why the data cannot be
 * encoded in one round without unnecessarily complicating the code.
 */
void
smb_kshare_enum(smb_server_t *sv, smb_enumshare_info_t *esi)
{
	smb_avl_t *share_avl;
	smb_avl_cursor_t cursor;
	smb_kshare_t *shr;
	int remained;
	uint16_t infolen = 0;
	uint16_t cmntlen = 0;
	uint16_t sharelen;
	uint16_t clen;
	uint32_t cmnt_offs;
	smb_msgbuf_t info_mb;
	smb_msgbuf_t cmnt_mb;
	boolean_t autohome_added = B_FALSE;

	if (!smb_export_isready(sv)) {
		esi->es_ntotal = esi->es_nsent = 0;
		esi->es_datasize = 0;
		return;
	}

	esi->es_ntotal = esi->es_nsent = 0;
	remained = esi->es_bufsize;
	share_avl = &sv->sv_export.e_share_avl;

	/* Do the necessary calculations in the first round */
	smb_avl_iterinit(share_avl, &cursor);

	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
		if (shr->shr_oemname == NULL) {
			smb_avl_release(share_avl, shr);
			continue;
		}

		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
			if (esi->es_posix_uid == shr->shr_uid) {
				autohome_added = B_TRUE;
			} else {
				smb_avl_release(share_avl, shr);
				continue;
			}
		}

		esi->es_ntotal++;

		if (remained <= 0) {
			smb_avl_release(share_avl, shr);
			continue;
		}

		clen = strlen(shr->shr_cmnt) + 1;
		sharelen = SHARE_INFO_1_SIZE + clen;

		if (sharelen <= remained) {
			infolen += SHARE_INFO_1_SIZE;
			cmntlen += clen;
		}

		remained -= sharelen;
		smb_avl_release(share_avl, shr);
	}

	esi->es_datasize = infolen + cmntlen;

	smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
	smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
	cmnt_offs = infolen;

	/* Encode the data in the second round */
	smb_avl_iterinit(share_avl, &cursor);
	autohome_added = B_FALSE;

	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
		if (shr->shr_oemname == NULL) {
			smb_avl_release(share_avl, shr);
			continue;
		}

		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
			if (esi->es_posix_uid == shr->shr_uid) {
				autohome_added = B_TRUE;
			} else {
				smb_avl_release(share_avl, shr);
				continue;
			}
		}

		if (smb_msgbuf_encode(&info_mb, "13c.wl",
		    shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) {
			smb_avl_release(share_avl, shr);
			break;
		}

		if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) {
			smb_avl_release(share_avl, shr);
			break;
		}

		cmnt_offs += strlen(shr->shr_cmnt) + 1;
		esi->es_nsent++;

		smb_avl_release(share_avl, shr);
	}

	smb_msgbuf_term(&info_mb);
	smb_msgbuf_term(&cmnt_mb);
}
/*
 * smb_trans2_mbc_encode
 *
 * This function encodes the mbc for one directory entry.
 *
 * The function returns -1 when the max data requested by client
 * is reached. If the entry is valid and successful encoded, 0
 * will be returned; otherwise, 1 will be returned.
 *
 * We always null terminate the filename. The space for the null
 * is included in the maxdata calculation and is therefore included
 * in the next_entry_offset. namelen is the unterminated length of
 * the filename. For levels except STANDARD and EA_SIZE, if the
 * filename is ascii the name length returned to the client should
 * include the null terminator. Otherwise the length returned to
 * the client should not include the terminator.
 *
 * Returns: 0 - data successfully encoded
 *          1 - client request's maxdata limit reached
 *	   -1 - error
 */
static int
smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
    smb_fileinfo_t *fileinfo, smb_find_args_t *args)
{
	int		namelen, shortlen, buflen;
	uint32_t	next_entry_offset;
	uint32_t	dsize32, asize32;
	uint32_t	mb_flags = 0;
	char		buf83[26];
	char		*tmpbuf;
	smb_msgbuf_t	mb;

	namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
	if (namelen == -1)
		return (-1);

	next_entry_offset = args->fa_maxdata + namelen;

	if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
		return (1);

	/*
	 * If ascii the filename length returned to the client should
	 * include the null terminator for levels except STANDARD and
	 * EASIZE.
	 */
	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
		if ((args->fa_infolev != SMB_INFO_STANDARD) &&
		    (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
			namelen += 1;
	}

	mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
	dsize32 = (fileinfo->fi_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_size;
	asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;

	switch (args->fa_infolev) {
	case SMB_INFO_STANDARD:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    fileinfo->fi_cookie);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    namelen,
		    fileinfo->fi_name);
		break;

	case SMB_INFO_QUERY_EA_SIZE:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    fileinfo->fi_cookie);

		/*
		 * Unicode filename should NOT be aligned. Encode ('u')
		 * into a temporary buffer, then encode buffer as a
		 * byte stream ('#c').
		 * Regardless of whether unicode or ascii, a single
		 * termination byte is used.
		 */
		buflen = namelen + sizeof (smb_wchar_t);
		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) {
			smb_msgbuf_term(&mb);
			kmem_free(tmpbuf, buflen);
			return (-1);
		}
		tmpbuf[namelen] = '\0';

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    0L,		/* EA Size */
		    namelen,
		    namelen + 1,
		    tmpbuf);

		smb_msgbuf_term(&mb);
		kmem_free(tmpbuf, buflen);
		break;

	case SMB_FIND_FILE_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    fileinfo->fi_name);
		break;

	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    fileinfo->fi_name);
		break;

	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    fileinfo->fi_nodeid,
		    fileinfo->fi_name);
		break;

	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
		    sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83,
		    fileinfo->fi_name);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_ascii_or_unicode_strlen(sr,
		    fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb,
		    "%llTTTTqqlllb.24c2.qu",
		    sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83,
		    fileinfo->fi_nodeid,
		    fileinfo->fi_name);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_NAMES_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    namelen,
		    fileinfo->fi_name);
		break;
	}

	return (0);
}