Beispiel #1
0
/*
 * smbrdr_hdr_process
 *
 * Assuming 'srh->srh_mbuf' contains a response from a Windows client,
 * decodes the 32 bytes SMB header.
 *
 * Buffer overflow typically means that the server has more data than
 * it could fit in the response buffer.  The client can use subsequent
 * SmbReadX requests to obtain the remaining data (KB 193839).
 *
 * Returns:
 *
 *  NT_STATUS_INVALID_NETWORK_RESPONSE	error decoding the header
 *  NT_STATUS_REPLY_MESSAGE_MISMATCH	response doesn't match the request
 *  NT_STATUS_SUCCESS			successful
 *  smb_hdr->status.ntstatus		error returned by server
 */
static DWORD
smbrdr_hdr_process(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr)
{
	int rc;

	rc = smb_decode_nt_hdr(&srh->srh_mbuf, smb_hdr);
	if (rc < SMB_HEADER_LEN) {
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_hdr_process[%d]: invalid header (%d)",
		    srh->srh_cmd, rc);
		return (NT_STATUS_INVALID_NETWORK_RESPONSE);
	}

	switch (NT_SC_VALUE(smb_hdr->status.ntstatus)) {
	case NT_STATUS_SUCCESS:
	case NT_STATUS_BUFFER_OVERFLOW:
		break;

	default:
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_hdr_process[%d]: request failed (%s)",
		    srh->srh_cmd, xlate_nt_status(smb_hdr->status.ntstatus));
		return (smb_hdr->status.ntstatus);
	}

	if (smb_hdr->command != srh->srh_cmd) {
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_hdr_process[%d]: reply mismatch (%d)",
		    srh->srh_cmd, smb_hdr->command);
		return (NT_STATUS_REPLY_MESSAGE_MISMATCH);
	}

	return (NT_STATUS_SUCCESS);
}
Beispiel #2
0
/*
 * smbrdr_send
 *
 * Send the SMB packet pointed by the given handle over
 * network.
 *
 * Returns:
 *
 *	NT_STATUS_INTERNAL_ERROR		crypto framework failure
 *	NT_STATUS_UNEXPECTED_NETWORK_ERROR	send failed
 *	NT_STATUS_SUCCESS			successful
 */
DWORD
smbrdr_send(smbrdr_handle_t *srh)
{
	int rc;

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

	rc = nb_send(srh->srh_session->sock, srh->srh_buf,
	    smb_msgbuf_used(&srh->srh_mbuf));

	if (rc < 0) {
		/*
		 * Make the sequence number of the next SMB request even
		 * to avoid DC from failing the next SMB request with
		 * ACCESS_DENIED.
		 */
		smb_mac_dec_seqnum(&srh->srh_session->sign_ctx);
		smb_log(smbrdr_log_hdl, LOG_ERR,
		    "smbrdr_send[%d]: send failed (%d)", srh->srh_cmd, rc);
		return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
	}

	return (NT_STATUS_SUCCESS);
}
Beispiel #3
0
/*ARGSUSED*/
static void *
smbd_share_printers(void *arg)
{
	cups_dest_t	*dests;
	cups_dest_t	*dest;
	smb_cups_ops_t	*cups;
	smb_share_t	si;
	uint32_t	nerr;
	int		num_dests;
	int		i;

	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
		return (NULL);

	if ((cups = smbd_cups_ops()) == NULL)
		return (NULL);

	if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
		smb_log(smbd.s_loghd, LOG_DEBUG,
		    "smbd_share_printers unable to load %s", SMB_SHARE_PRINT);
		return (NULL);
	}

	num_dests = cups->cupsGetDests(&dests);

	for (i = num_dests, dest = dests; i > 0; i--, dest++) {
		if (dest->instance != NULL)
			continue;

		(void) strlcpy(si.shr_name, dest->name, MAXPATHLEN);
		smbd_print_share_comment(&si, dest);
		si.shr_type = STYPE_PRINTQ;

		nerr = smb_shr_add(&si);
		if (nerr == NERR_Success || nerr == NERR_DuplicateShare)
			smb_log(smbd.s_loghd, LOG_DEBUG,
			    "shared printer: %s", si.shr_name);
		else
			smb_log(smbd.s_loghd, LOG_DEBUG,
			    "smbd_share_printers: unable to add share %s: %u",
			    si.shr_name, nerr);
	}

	cups->cupsFreeDests(num_dests, dests);
	return (NULL);
}
Beispiel #4
0
/*
 * Wait until the service is online.  Provided for threads that
 * should wait until the service has been fully initialized before
 * they start performing operations.
 */
void
smbd_online_wait(const char *text)
{
	while (!smbd_online())
		(void) sleep(SMBD_ONLINE_WAIT_INTERVAL);

	if (text != NULL) {
		smb_log(smbd.s_loghd, LOG_DEBUG, "%s: online", text);
		(void) fprintf(stderr, "%s: online\n", text);
	}
}
Beispiel #5
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);
}
Beispiel #6
0
/*
 * smbrdr_sign
 *
 * Signs the given outgoing packet according to the
 * specified signing context.
 *
 * The client and server each maintain an integer counter
 * which they initialize to zero. Both counters are
 * incremented for every SMB message - that's once for a
 * request and once for a reply. As a result, requests sent
 * by SMB Redirector always have an even sequence number
 * and replies from the Windows server always have an odd
 * number.
 *
 * Based on the observed Windows 2003 behavior, any SMB
 * request will fail with NT_STATUS_ACCESS_DENIED if its
 * sequence number is not even.
 *
 * The function can fail if there is trouble with the cryptographic
 * framework and if that happens SMBAUTH_FAILURE is returned.  In the
 * normal case SMBAUTH_SUCCESS is returned.
 */
static int
smbrdr_sign(smb_sign_ctx_t *sign_ctx, smb_msgbuf_t *mb)
{
	if (sign_ctx->ssc_flags & SMB_SCF_STARTED) {
		if (sign_ctx->ssc_seqnum % 2) {
			smb_log(smbrdr_log_hdl, LOG_DEBUG,
			    "smbrdr_sign: invalid sequence (%d)",
			    sign_ctx->ssc_seqnum);
		}
		if (smb_mac_sign(sign_ctx, smb_msgbuf_base(mb),
		    smb_msgbuf_used(mb)) != SMBAUTH_SUCCESS)
			return (SMBAUTH_FAILURE);
		sign_ctx->ssc_seqnum++;
	}
	return (SMBAUTH_SUCCESS);
}
Beispiel #7
0
/*
 * Start the spool thread.
 * Returns 0 on success, an error number if thread creation fails.
 */
void
smbd_spool_start(void)
{
	pthread_attr_t	attr;
	int		rc;

	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
		return;

	(void) pthread_attr_init(&attr);
	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	rc = pthread_create(&smbd.s_spool_tid, &attr, smbd_spool_monitor, NULL);
	(void) pthread_attr_destroy(&attr);

	if (rc != 0)
		smb_log(smbd.s_loghd, LOG_NOTICE,
		    "failed to start print monitor: %s", strerror(errno));
}
Beispiel #8
0
void
smbd_load_printers(void)
{
	pthread_t	tid;
	pthread_attr_t	attr;
	int		rc;

	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
		return;

	(void) pthread_attr_init(&attr);
	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	rc = pthread_create(&tid, &attr, smbd_share_printers, &tid);
	(void) pthread_attr_destroy(&attr);

	if (rc != 0)
		smb_log(smbd.s_loghd, LOG_NOTICE,
		    "unable to load printer shares: %s", strerror(errno));
}
/*
 * smbrdr_transact
 *
 * Send a SMB_COM_TRANSACTION request.
 */
int
smbrdr_transact(int fid, char *out_buf, int out_len, char *in_buf, int in_len)
{
	struct sdb_session *session;
	struct sdb_netuse *netuse;
	struct sdb_ofile *ofile;
	struct sdb_logon *logon;
	smb_transact_rsp_t rsp;
	smbrdr_handle_t srh;
	smb_msgbuf_t *mb;
	DWORD status;
	int rc;
	unsigned short rcv_dcnt;
	int cur_inlen;
	int first_rsp;

	if ((ofile = smbrdr_ofile_get(fid)) == 0)
		return (-1);

	netuse = ofile->netuse;
	session = netuse->session;
	logon = &session->logon;

	status = smbrdr_request_init(&srh, SMB_COM_TRANSACTION,
	    session, logon, netuse);

	if (status != NT_STATUS_SUCCESS) {
		smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_transact: %s",
		    xlate_nt_status(status));
		smbrdr_ofile_put(ofile);
		return (-1);
	}

	mb = &srh.srh_mbuf;

	rc = prep_smb_transact(mb, ofile->fid, out_buf, out_len, in_len,
	    session->remote_caps & CAP_UNICODE);
	if (rc < 0) {
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_transact: prep failed");
		smbrdr_handle_free(&srh);
		smbrdr_ofile_put(ofile);
		return (rc);
	}

	smbrdr_lock_transport();

	status = smbrdr_send(&srh);
	if (status != NT_STATUS_SUCCESS) {
		smbrdr_unlock_transport();
		smbrdr_handle_free(&srh);
		smbrdr_ofile_put(ofile);
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_transact: send failed");
		return (-1);
	}

	rcv_dcnt = 0;
	cur_inlen = in_len;
	first_rsp = 1;

	do {
		if (smbrdr_rcv(&srh, first_rsp) != NT_STATUS_SUCCESS) {
			smb_log(smbrdr_log_hdl, LOG_DEBUG,
			    "smbrdr_transact: nb_rcv failed");
			rc = -1;
			break;
		}

		rc = decode_smb_transact(mb, in_buf, cur_inlen, &rsp);
		if (rc < 0 || rsp.TotalDataCount > in_len) {
			smb_log(smbrdr_log_hdl, LOG_DEBUG,
			    "smbrdr_transact: decode failed");
			rc = -1;
			break;
		}

		rcv_dcnt += rsp.DataCount;
		cur_inlen -= rsp.DataCount;
		first_rsp = 0;

	} while (rcv_dcnt < rsp.TotalDataCount);

	smbrdr_unlock_transport();
	smbrdr_handle_free(&srh);
	smbrdr_ofile_put(ofile);

	return ((rc < 0) ? rc : rcv_dcnt);
}
Beispiel #10
0
int
smbd_cups_init(void)
{
	(void) mutex_lock(&smbd_cups_mutex);

	if (smb_cups.cups_hdl != NULL) {
		(void) mutex_unlock(&smbd_cups_mutex);
		return (0);
	}

	if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) {
		(void) mutex_unlock(&smbd_cups_mutex);
		smb_log(smbd.s_loghd, LOG_DEBUG,
		    "smbd_cups_init: cannot open libcups");
		return (ENOENT);
	}

	smb_cups.cupsLangDefault =
	    (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault");
	smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *))
	    dlsym(smb_cups.cups_hdl, "cupsLangEncoding");
	smb_cups.cupsDoFileRequest =
	    (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *))
	    dlsym(smb_cups.cups_hdl, "cupsDoFileRequest");
	smb_cups.cupsLastError = (ipp_status_t (*)())
	    dlsym(smb_cups.cups_hdl, "cupsLastError");
	smb_cups.cupsLangFree = (void (*)(cups_lang_t *))
	    dlsym(smb_cups.cups_hdl, "cupsLangFree");
	smb_cups.cupsGetDests = (int (*)(cups_dest_t **))
	    dlsym(smb_cups.cups_hdl, "cupsGetDests");
	smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *))
	    dlsym(smb_cups.cups_hdl, "cupsFreeDests");

	smb_cups.httpClose = (void (*)(http_t *))
	    dlsym(smb_cups.cups_hdl, "httpClose");
	smb_cups.httpConnect = (http_t *(*)(const char *, int))
	    dlsym(smb_cups.cups_hdl, "httpConnect");

	smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew");
	smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete");
	smb_cups.ippErrorString = (char *(*)())
	    dlsym(smb_cups.cups_hdl, "ippErrorString");
	smb_cups.ippAddString = (ipp_attribute_t *(*)())
	    dlsym(smb_cups.cups_hdl, "ippAddString");

	if (smb_cups.cupsLangDefault == NULL ||
	    smb_cups.cupsLangEncoding == NULL ||
	    smb_cups.cupsDoFileRequest == NULL ||
	    smb_cups.cupsLastError == NULL ||
	    smb_cups.cupsLangFree == NULL ||
	    smb_cups.cupsGetDests == NULL ||
	    smb_cups.cupsFreeDests == NULL ||
	    smb_cups.ippNew == NULL ||
	    smb_cups.httpClose == NULL ||
	    smb_cups.httpConnect == NULL ||
	    smb_cups.ippDelete == NULL ||
	    smb_cups.ippErrorString == NULL ||
	    smb_cups.ippAddString == NULL) {
		(void) dlclose(smb_cups.cups_hdl);
		smb_cups.cups_hdl = NULL;
		(void) mutex_unlock(&smbd_cups_mutex);
		smb_log(smbd.s_loghd, LOG_DEBUG,
		    "smbd_cups_init: cannot load libcups");
		return (ENOENT);
	}

	(void) mutex_unlock(&smbd_cups_mutex);
	return (0);
}
Beispiel #11
0
/*
 * All versions of windows use this function to spool files to a printer
 * via the cups interface
 */
static void
smbd_spool_copyfile(smb_inaddr_t *ipaddr, char *username, char *path,
    char *doc_name)
{
	smb_cups_ops_t	*cups;
	http_t		*http = NULL;		/* HTTP connection to server */
	ipp_t		*request = NULL;	/* IPP Request */
	ipp_t		*response = NULL;	/* IPP Response */
	cups_lang_t	*language = NULL;	/* Default language */
	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
	char		new_jobname[SMBD_PJOBLEN];
	smbd_printjob_t	pjob;
	char 		clientname[INET6_ADDRSTRLEN];
	struct stat 	sbuf;
	int		rc = 1;

	if (stat(path, &sbuf)) {
		smb_log(smbd.s_loghd, LOG_INFO, "smbd_spool_copyfile: %s: %s",
		    path, strerror(errno));
		return;
	}

	/*
	 * Remove zero size files and return; these were inadvertantly
	 * created by XP or 2000.
	 */
	if (sbuf.st_size == 0) {
		if (remove(path) != 0)
			smb_log(smbd.s_loghd, LOG_INFO,
			    "smbd_spool_copyfile: cannot remove %s: %s",
			    path, strerror(errno));
		return;
	}

	if ((cups = smbd_cups_ops()) == NULL)
		return;

	if ((http = cups->httpConnect("localhost", 631)) == NULL) {
		smb_log(smbd.s_loghd, LOG_INFO,
		    "smbd_spool_copyfile: cupsd not running");
		return;
	}

	if ((request = cups->ippNew()) == NULL) {
		smb_log(smbd.s_loghd, LOG_INFO,
		    "smbd_spool_copyfile: ipp not running");
		return;
	}

	request->request.op.operation_id = IPP_PRINT_JOB;
	request->request.op.request_id = 1;
	language = cups->cupsLangDefault();

	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
	    "attributes-charset", NULL, cups->cupsLangEncoding(language));

	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
	    "attributes-natural-language", NULL, language->language);

	(void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s",
	    SMBD_PRINTER);
	pjob.pj_pid = pthread_self();
	pjob.pj_sysjob = 10;
	(void) strlcpy(pjob.pj_filename, path, SMBD_PJOBLEN);
	pjob.pj_start_time = time(NULL);
	pjob.pj_status = 2;
	pjob.pj_size = sbuf.st_blocks * 512;
	pjob.pj_page_count = 1;
	pjob.pj_isspooled = B_TRUE;
	pjob.pj_jobnum = smbd_cups_jobnum;

	(void) strlcpy(pjob.pj_jobname, doc_name, SMBD_PJOBLEN);
	(void) strlcpy(pjob.pj_username, username, SMBD_PJOBLEN);
	(void) strlcpy(pjob.pj_queuename, SMBD_CUPS_SPOOL_DIR, SMBD_PJOBLEN);

	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
	    "printer-uri", NULL, uri);

	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
	    "requesting-user-name", NULL, pjob.pj_username);

	if (smb_inet_ntop(ipaddr, clientname,
	    SMB_IPSTRLEN(ipaddr->a_family)) == NULL) {
		smb_log(smbd.s_loghd, LOG_INFO,
		    "smbd_spool_copyfile: %s: unknown client", clientname);
		goto out;
	}

	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
	    "job-originating-host-name", NULL, clientname);

	(void) snprintf(new_jobname, SMBD_PJOBLEN, "%s%d",
	    SMBD_FN_PREFIX, pjob.pj_jobnum);
	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
	    "job-name", NULL, new_jobname);

	(void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SMBD_PRINTER);

	response = cups->cupsDoFileRequest(http, request, uri,
	    pjob.pj_filename);
	if (response != NULL) {
		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
			smb_log(smbd.s_loghd, LOG_ERR,
			    "smbd_spool_copyfile: printer %s: %s",
			    SMBD_PRINTER,
			    cups->ippErrorString(cups->cupsLastError()));
		} else {
			atomic_inc_32(&smbd_cups_jobnum);
			rc = 0;
		}
	} else {
		smb_log(smbd.s_loghd, LOG_ERR,
		    "smbd_spool_copyfile: unable to print to %s",
		    cups->ippErrorString(cups->cupsLastError()));
	}

	if (rc == 0)
		(void) unlink(pjob.pj_filename);

out:
	if (response)
		cups->ippDelete(response);

	if (language)
		cups->cupsLangFree(language);

	if (http)
		cups->httpClose(http);
}
Beispiel #12
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);
}