xref: /onnv-gate/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_lib.c (revision 12508:edb7861a1533)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * This file provides some common functionality for SMB Redirector
28  * module.
29  */
30 
31 #include <unistd.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <smbrdr.h>
35 
36 smb_log_hdl_t smbrdr_log_hdl;
37 
38 static DWORD smbrdr_handle_setup(smbrdr_handle_t *, unsigned char,
39     struct sdb_session *, struct sdb_logon *, struct sdb_netuse *);
40 static int smbrdr_hdr_setup(smbrdr_handle_t *);
41 static DWORD smbrdr_hdr_process(smbrdr_handle_t *, smb_hdr_t *);
42 static int smbrdr_sign(smb_sign_ctx_t *, smb_msgbuf_t *);
43 static int smbrdr_sign_chk(smb_sign_ctx_t *, smb_msgbuf_t *, unsigned char *);
44 
smbrdr_lock_transport()45 void smbrdr_lock_transport() { nb_lock(); }
smbrdr_unlock_transport()46 void smbrdr_unlock_transport() { nb_unlock(); }
47 
48 #pragma init(_smbrdr_init)
49 
50 void
_smbrdr_init(void)51 _smbrdr_init(void)
52 {
53 	smbrdr_log_hdl = smb_log_create(SMBRDR_LOG_MAXCNT, SMBRDR_LOG_NAME);
54 }
55 
56 /*
57  * smbrdr_request_init
58  *
59  * Setup a handle with given information and then
60  * setup a SMB header structure.
61  *
62  * Returns:
63  *
64  *	NT_STATUS_NO_MEMORY		no memory for creating request
65  *	NT_STATUS_INTERNAL_ERROR	header encode failed or crypto failed
66  *	NT_STATUS_SUCCESS		successful
67  */
68 DWORD
smbrdr_request_init(smbrdr_handle_t * srh,unsigned char cmd,struct sdb_session * session,struct sdb_logon * logon,struct sdb_netuse * netuse)69 smbrdr_request_init(smbrdr_handle_t *srh,
70 			unsigned char cmd,
71 			struct sdb_session *session,
72 			struct sdb_logon *logon,
73 			struct sdb_netuse *netuse)
74 {
75 	DWORD status;
76 
77 	status = smbrdr_handle_setup(srh, cmd, session, logon, netuse);
78 	if (status != NT_STATUS_SUCCESS)
79 		return (status);
80 
81 	if (smbrdr_hdr_setup(srh) < SMB_HEADER_LEN) {
82 		smbrdr_handle_free(srh);
83 		return (NT_STATUS_INTERNAL_ERROR);
84 	}
85 
86 	return (NT_STATUS_SUCCESS);
87 }
88 
89 /*
90  * smbrdr_send
91  *
92  * Send the SMB packet pointed by the given handle over
93  * network.
94  *
95  * Returns:
96  *
97  *	NT_STATUS_INTERNAL_ERROR		crypto framework failure
98  *	NT_STATUS_UNEXPECTED_NETWORK_ERROR	send failed
99  *	NT_STATUS_SUCCESS			successful
100  */
101 DWORD
smbrdr_send(smbrdr_handle_t * srh)102 smbrdr_send(smbrdr_handle_t *srh)
103 {
104 	int rc;
105 
106 	if (smbrdr_sign(&srh->srh_session->sign_ctx, &srh->srh_mbuf) !=
107 	    SMBAUTH_SUCCESS) {
108 		smb_log(smbrdr_log_hdl, LOG_ERR,
109 		    "smbrdr_send[%d]: signing failed", srh->srh_cmd);
110 		return (NT_STATUS_INTERNAL_ERROR);
111 	}
112 
113 	rc = nb_send(srh->srh_session->sock, srh->srh_buf,
114 	    smb_msgbuf_used(&srh->srh_mbuf));
115 
116 	if (rc < 0) {
117 		/*
118 		 * Make the sequence number of the next SMB request even
119 		 * to avoid DC from failing the next SMB request with
120 		 * ACCESS_DENIED.
121 		 */
122 		smb_mac_dec_seqnum(&srh->srh_session->sign_ctx);
123 		smb_log(smbrdr_log_hdl, LOG_ERR,
124 		    "smbrdr_send[%d]: send failed (%d)", srh->srh_cmd, rc);
125 		return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
126 	}
127 
128 	return (NT_STATUS_SUCCESS);
129 }
130 
131 /*
132  * smbrdr_rcv
133  *
134  * Receive a SMB response and decode the packet header.
135  *
136  * "Implementing CIFS" book, SMB requests always have an even sequence
137  * number and replies always have an odd.
138  *
139  * With the original code, if the SMB Redirector skip the counter increment
140  * in the event of any failure during SmbSessionSetupAndX, it causes the
141  * domain controller to fail the next SMB request(odd sequence number)
142  * with ACCESS_DENIED.
143  *
144  * Smbrdr module should use the same sequence number (i.e. ssc_seqnum of the
145  * SMB Sign context) for generating the MAC signature for all incoming
146  * responses per SmbTransact request. Otherwise, the validation will fail.
147  * It is now fixed by decrementing the sequence number prior to validating
148  * the subsequent responses for a single request.
149  *
150  * Returns:
151  *
152  *	status code returned by smbrdr_hdr_process()
153  *	NT_STATUS_UNEXPECTED_NETWORK_ERROR	receive failed
154  *	NT_STATUS_SUCCESS					successful
155  */
156 DWORD
smbrdr_rcv(smbrdr_handle_t * srh,int is_first_rsp)157 smbrdr_rcv(smbrdr_handle_t *srh, int is_first_rsp)
158 {
159 	smb_hdr_t smb_hdr;
160 	DWORD status;
161 	int rc;
162 	smb_sign_ctx_t *sign_ctx = &srh->srh_session->sign_ctx;
163 
164 	rc = nb_rcv(srh->srh_session->sock, srh->srh_buf, SMBRDR_REQ_BUFSZ, 0);
165 	if (rc < 0) {
166 		smb_mac_inc_seqnum(sign_ctx);
167 		smb_log(smbrdr_log_hdl, LOG_ERR,
168 		    "smbrdr_rcv[%d]: receive failed (%d)", srh->srh_cmd, rc);
169 		return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
170 	}
171 
172 	smb_msgbuf_init(&srh->srh_mbuf, srh->srh_buf, rc, srh->srh_mbflags);
173 
174 	status = smbrdr_hdr_process(srh, &smb_hdr);
175 	if (status != NT_STATUS_SUCCESS) {
176 		smb_mac_inc_seqnum(sign_ctx);
177 		smb_log(smbrdr_log_hdl, LOG_ERR,
178 		    "smbrdr_rcv[%d]: failed (%s)", srh->srh_cmd,
179 		    xlate_nt_status(status));
180 		return (status);
181 	}
182 
183 	if (!is_first_rsp)
184 		smb_mac_dec_seqnum(sign_ctx);
185 
186 	if (!smbrdr_sign_chk(sign_ctx,
187 	    &srh->srh_mbuf, smb_hdr.extra.extra.security_sig)) {
188 		smb_log(smbrdr_log_hdl, LOG_ERR,
189 		    "smbrdr_rcv[%d]: bad signature", srh->srh_cmd);
190 		return (NT_STATUS_INVALID_NETWORK_RESPONSE);
191 	}
192 
193 	return (NT_STATUS_SUCCESS);
194 }
195 
196 /*
197  * smbrdr_exchange
198  *
199  * Send the SMB packet pointed by the given handle over
200  * network. Receive the response and decode the packet header.
201  *
202  * From "Implementing CIFS" book, SMB requests always have an even sequence
203  * number and replies always have an odd.
204  *
205  * With the original code, if the SMB Redirector skips the counter increment
206  * in the event of any failure during SmbSessionSetupAndX, it causes the
207  * domain controller to fail the next SMB request(odd sequence number)
208  * with ACCESS_DENIED.
209  *
210  * Returns:
211  *
212  *	status code returned by smbrdr_hdr_process()
213  *	NT_STATUS_INTERNAL_ERROR		crypto framework failure
214  *	NT_STATUS_UNEXPECTED_NETWORK_ERROR	send/receive failed
215  *	NT_STATUS_SUCCESS			successful
216  */
217 DWORD
smbrdr_exchange(smbrdr_handle_t * srh,smb_hdr_t * smb_hdr,long timeout)218 smbrdr_exchange(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr, long timeout)
219 {
220 	smb_sign_ctx_t *sign_ctx;
221 	smb_msgbuf_t *mb;
222 	DWORD status;
223 	int rc;
224 
225 	smbrdr_lock_transport();
226 
227 	mb = &srh->srh_mbuf;
228 	sign_ctx = &srh->srh_session->sign_ctx;
229 
230 	if (smbrdr_sign(sign_ctx, mb) != SMBAUTH_SUCCESS) {
231 		smb_log(smbrdr_log_hdl, LOG_ERR,
232 		    "smbrdr_exchange[%d]: signing failed", srh->srh_cmd);
233 		smbrdr_unlock_transport();
234 		return (NT_STATUS_INTERNAL_ERROR);
235 	}
236 
237 	rc = nb_exchange(srh->srh_session->sock,
238 	    srh->srh_buf, smb_msgbuf_used(mb),
239 	    srh->srh_buf, SMBRDR_REQ_BUFSZ, timeout);
240 
241 	if (rc < 0) {
242 		smb_log(smbrdr_log_hdl, LOG_ERR,
243 		    "smbrdr_exchange[%d]: failed (%d)", srh->srh_cmd, rc);
244 
245 		if (srh->srh_cmd != SMB_COM_ECHO) {
246 			/*
247 			 * Since SMB echo is used to check the session
248 			 * status then don't destroy the session if it's
249 			 * SMB echo.
250 			 */
251 			srh->srh_session->state = SDB_SSTATE_STALE;
252 		}
253 		smb_mac_inc_seqnum(sign_ctx);
254 		smbrdr_unlock_transport();
255 		return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
256 	}
257 
258 	/* initialize for processing response */
259 	smb_msgbuf_init(mb, srh->srh_buf, rc, srh->srh_mbflags);
260 
261 	status = smbrdr_hdr_process(srh, smb_hdr);
262 	if (status != NT_STATUS_SUCCESS) {
263 		smb_log(smbrdr_log_hdl, LOG_ERR,
264 		    "smbrdr_exchange[%d]: failed (%s)", srh->srh_cmd,
265 		    xlate_nt_status(status));
266 		smb_mac_inc_seqnum(sign_ctx);
267 		smbrdr_unlock_transport();
268 		return (status);
269 	}
270 
271 	/* Signature validation */
272 	if (!smbrdr_sign_chk(sign_ctx, mb, smb_hdr->extra.extra.security_sig)) {
273 		smb_log(smbrdr_log_hdl, LOG_ERR,
274 		    "smbrdr_exchange[%d]: bad signature", srh->srh_cmd);
275 		smbrdr_unlock_transport();
276 		return (NT_STATUS_INVALID_NETWORK_RESPONSE);
277 	}
278 
279 	smbrdr_unlock_transport();
280 	return (NT_STATUS_SUCCESS);
281 }
282 
283 /*
284  * smbrdr_handle_free
285  *
286  * Frees the memories allocated for the given handle.
287  */
288 void
smbrdr_handle_free(smbrdr_handle_t * srh)289 smbrdr_handle_free(smbrdr_handle_t *srh)
290 {
291 	if (srh) {
292 		smb_msgbuf_term(&srh->srh_mbuf);
293 		free(srh->srh_buf);
294 	}
295 }
296 
297 
298 /*
299  * smbrdr_sign_init
300  *
301  * This function is called from SessionSetup and initialize the
302  * signing context for the session if the connected user isn't
303  * anonymous. This has to call before smbrdr_request_init()
304  * because it modifies smb_flags2.
305  *
306  * The following description is taken out from the "Implementing CIFS"
307  * book(pg. 304):
308  *
309  * "Once the MAC signing has been initialized within a session, all
310  * messages are numbered using the same counters and signed using
311  * the same Session Key.  This is true even if additional SESSION
312  * SETUP ANDX exchanges occur."
313  *
314  * The original SMB packet signing implementation calculates a MAC
315  * key each time the SMB Redirector sends the SmbSessionSetupAndx
316  * request for any non-anonymous/non-guest user which is not desired
317  * whenever there is a change in the user session key.
318  *
319  * If NTLMv2 authentication is used, the MAC key generated for each
320  * SessionSetup is unique. Since the domain controller expects the
321  * signature of all incoming requests are signed by the same MAC key
322  * (i.e. the one that generated for the first non-anonymous SessionSetup),
323  * access denied is returned for any subsequent SmbSessionSetupAndX
324  * request.
325  */
326 int
smbrdr_sign_init(struct sdb_session * session,struct sdb_logon * logon)327 smbrdr_sign_init(struct sdb_session *session, struct sdb_logon *logon)
328 {
329 	smb_sign_ctx_t *sign_ctx;
330 	int rc = 0;
331 
332 	sign_ctx = &session->sign_ctx;
333 
334 	if ((sign_ctx->ssc_flags & SMB_SCF_REQUIRED) &&
335 	    !(sign_ctx->ssc_flags & SMB_SCF_STARTED) &&
336 	    (logon->type != SDB_LOGON_ANONYMOUS)) {
337 		if (smb_mac_init(sign_ctx, &logon->auth) != SMBAUTH_SUCCESS)
338 			return (-1);
339 
340 		sign_ctx->ssc_flags |=
341 		    (SMB_SCF_STARTED | SMB_SCF_KEY_ISSET_THIS_LOGON);
342 		session->smb_flags2 |= SMB_FLAGS2_SMB_SECURITY_SIGNATURE;
343 		rc = 1;
344 	}
345 
346 	return (rc);
347 }
348 
349 /*
350  * smbrdr_sign_fini
351  *
352  * Invalidate the MAC key if the first non-anonymous/non-guest user logon
353  * fail.
354  */
355 void
smbrdr_sign_fini(struct sdb_session * session)356 smbrdr_sign_fini(struct sdb_session *session)
357 {
358 	smb_sign_ctx_t *sign_ctx = &session->sign_ctx;
359 
360 	if (sign_ctx->ssc_flags & SMB_SCF_KEY_ISSET_THIS_LOGON) {
361 		sign_ctx->ssc_flags &= ~SMB_SCF_STARTED;
362 		sign_ctx->ssc_flags &= ~SMB_SCF_KEY_ISSET_THIS_LOGON;
363 		sign_ctx->ssc_seqnum = 0;
364 	}
365 }
366 
367 /*
368  * smbrdr_sign_unset_key
369  *
370  * The SMB_SCF_KEY_ISSET_THIS_LOGON should be unset upon the successful
371  * SmbSessionSetupAndX request for the first non-anonymous/non-guest
372  * logon.
373  */
374 void
smbrdr_sign_unset_key(struct sdb_session * session)375 smbrdr_sign_unset_key(struct sdb_session *session)
376 {
377 	smb_sign_ctx_t *sign_ctx = &session->sign_ctx;
378 
379 	sign_ctx->ssc_flags &= ~SMB_SCF_KEY_ISSET_THIS_LOGON;
380 }
381 
382 /*
383  * smbrdr_handle_setup
384  *
385  * Allocates a buffer for sending/receiving a SMB request.
386  * Initialize a smb_msgbuf structure with the allocated buffer.
387  * Setup given handle (srh) with the specified information.
388  *
389  * Returns:
390  *
391  *	NT_STATUS_NO_MEMORY		not enough memory
392  *	NT_STATUS_SUCCESS		successful
393  */
394 static DWORD
smbrdr_handle_setup(smbrdr_handle_t * srh,unsigned char cmd,struct sdb_session * session,struct sdb_logon * logon,struct sdb_netuse * netuse)395 smbrdr_handle_setup(smbrdr_handle_t *srh,
396 			unsigned char cmd,
397 			struct sdb_session *session,
398 			struct sdb_logon *logon,
399 			struct sdb_netuse *netuse)
400 {
401 	srh->srh_buf = (unsigned char *)malloc(SMBRDR_REQ_BUFSZ);
402 	if (srh->srh_buf == NULL)
403 		return (NT_STATUS_NO_MEMORY);
404 
405 	bzero(srh->srh_buf, SMBRDR_REQ_BUFSZ);
406 
407 	srh->srh_mbflags = (session->remote_caps & CAP_UNICODE)
408 	    ? SMB_MSGBUF_UNICODE : 0;
409 
410 	smb_msgbuf_init(&srh->srh_mbuf, srh->srh_buf,
411 	    SMBRDR_REQ_BUFSZ, srh->srh_mbflags);
412 
413 	srh->srh_cmd = cmd;
414 	srh->srh_session = session;
415 	srh->srh_user = logon;
416 	srh->srh_tree = netuse;
417 
418 	return (NT_STATUS_SUCCESS);
419 }
420 
421 /*
422  * smbrdr_hdr_setup
423  *
424  * Build an SMB header based on the information in the given handle.
425  * The SMB header is described in section 3.2 of the CIFS spec.
426  * As this is a canned function, no error checking is performed here.
427  * The return value from smb_msgbuf_encode is simply returned to the caller.
428  */
429 static int
smbrdr_hdr_setup(smbrdr_handle_t * srh)430 smbrdr_hdr_setup(smbrdr_handle_t *srh)
431 {
432 	static unsigned short my_pid = 0;
433 
434 	if (!my_pid)
435 		my_pid = getpid();
436 
437 	return (smb_msgbuf_encode(&srh->srh_mbuf, "Mb4.bw12.wwww",
438 	    srh->srh_cmd,
439 	    srh->srh_session->smb_flags,
440 	    srh->srh_session->smb_flags2,
441 	    (srh->srh_tree) ? srh->srh_tree->tid : 0,
442 	    my_pid,
443 	    (srh->srh_user) ? srh->srh_user->uid : 0,
444 	    0 /* mid */));
445 }
446 
447 /*
448  * Canned SMB header decode.
449  */
450 static int
smb_decode_nt_hdr(smb_msgbuf_t * mb,smb_hdr_t * hdr)451 smb_decode_nt_hdr(smb_msgbuf_t *mb, smb_hdr_t *hdr)
452 {
453 	return (smb_msgbuf_decode(mb, SMB_HEADER_NT_FMT,
454 	    &hdr->command,
455 	    &hdr->status.ntstatus,
456 	    &hdr->flags,
457 	    &hdr->flags2,
458 	    &hdr->pid_high,
459 	    SMB_SIG_SIZE,
460 	    &hdr->extra.extra.security_sig,
461 	    &hdr->tid,
462 	    &hdr->pid,
463 	    &hdr->uid,
464 	    &hdr->mid));
465 }
466 
467 /*
468  * smbrdr_hdr_process
469  *
470  * Assuming 'srh->srh_mbuf' contains a response from a Windows client,
471  * decodes the 32 bytes SMB header.
472  *
473  * Buffer overflow typically means that the server has more data than
474  * it could fit in the response buffer.  The client can use subsequent
475  * SmbReadX requests to obtain the remaining data (KB 193839).
476  *
477  * Returns:
478  *
479  *  NT_STATUS_INVALID_NETWORK_RESPONSE	error decoding the header
480  *  NT_STATUS_REPLY_MESSAGE_MISMATCH	response doesn't match the request
481  *  NT_STATUS_SUCCESS			successful
482  *  smb_hdr->status.ntstatus		error returned by server
483  */
484 static DWORD
smbrdr_hdr_process(smbrdr_handle_t * srh,smb_hdr_t * smb_hdr)485 smbrdr_hdr_process(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr)
486 {
487 	int rc;
488 
489 	rc = smb_decode_nt_hdr(&srh->srh_mbuf, smb_hdr);
490 	if (rc < SMB_HEADER_LEN) {
491 		smb_log(smbrdr_log_hdl, LOG_DEBUG,
492 		    "smbrdr_hdr_process[%d]: invalid header (%d)",
493 		    srh->srh_cmd, rc);
494 		return (NT_STATUS_INVALID_NETWORK_RESPONSE);
495 	}
496 
497 	switch (NT_SC_VALUE(smb_hdr->status.ntstatus)) {
498 	case NT_STATUS_SUCCESS:
499 	case NT_STATUS_BUFFER_OVERFLOW:
500 		break;
501 
502 	default:
503 		smb_log(smbrdr_log_hdl, LOG_DEBUG,
504 		    "smbrdr_hdr_process[%d]: request failed (%s)",
505 		    srh->srh_cmd, xlate_nt_status(smb_hdr->status.ntstatus));
506 		return (smb_hdr->status.ntstatus);
507 	}
508 
509 	if (smb_hdr->command != srh->srh_cmd) {
510 		smb_log(smbrdr_log_hdl, LOG_DEBUG,
511 		    "smbrdr_hdr_process[%d]: reply mismatch (%d)",
512 		    srh->srh_cmd, smb_hdr->command);
513 		return (NT_STATUS_REPLY_MESSAGE_MISMATCH);
514 	}
515 
516 	return (NT_STATUS_SUCCESS);
517 }
518 
519 /*
520  * smbrdr_sign
521  *
522  * Signs the given outgoing packet according to the
523  * specified signing context.
524  *
525  * The client and server each maintain an integer counter
526  * which they initialize to zero. Both counters are
527  * incremented for every SMB message - that's once for a
528  * request and once for a reply. As a result, requests sent
529  * by SMB Redirector always have an even sequence number
530  * and replies from the Windows server always have an odd
531  * number.
532  *
533  * Based on the observed Windows 2003 behavior, any SMB
534  * request will fail with NT_STATUS_ACCESS_DENIED if its
535  * sequence number is not even.
536  *
537  * The function can fail if there is trouble with the cryptographic
538  * framework and if that happens SMBAUTH_FAILURE is returned.  In the
539  * normal case SMBAUTH_SUCCESS is returned.
540  */
541 static int
smbrdr_sign(smb_sign_ctx_t * sign_ctx,smb_msgbuf_t * mb)542 smbrdr_sign(smb_sign_ctx_t *sign_ctx, smb_msgbuf_t *mb)
543 {
544 	if (sign_ctx->ssc_flags & SMB_SCF_STARTED) {
545 		if (sign_ctx->ssc_seqnum % 2) {
546 			smb_log(smbrdr_log_hdl, LOG_DEBUG,
547 			    "smbrdr_sign: invalid sequence (%d)",
548 			    sign_ctx->ssc_seqnum);
549 		}
550 		if (smb_mac_sign(sign_ctx, smb_msgbuf_base(mb),
551 		    smb_msgbuf_used(mb)) != SMBAUTH_SUCCESS)
552 			return (SMBAUTH_FAILURE);
553 		sign_ctx->ssc_seqnum++;
554 	}
555 	return (SMBAUTH_SUCCESS);
556 }
557 
558 
559 /*
560  * smbrdr_sign_chk
561  *
562  * Validates SMB MAC signature in the in-coming message.
563  * Return 1 if the signature are match; otherwise, return 0;
564  *
565  * When packet signing is enabled, the sequence number kept in the
566  * sign_ctx structure will be incremented when a SMB request is
567  * sent and upon the receipt of the first SmbTransact response
568  * if SMB fragmentation occurs.
569  */
570 static int
smbrdr_sign_chk(smb_sign_ctx_t * sign_ctx,smb_msgbuf_t * mb,unsigned char * signature)571 smbrdr_sign_chk(smb_sign_ctx_t *sign_ctx, smb_msgbuf_t *mb,
572 		unsigned char *signature)
573 {
574 	int sign_ok = 1;
575 
576 	if (sign_ctx->ssc_flags & SMB_SCF_STARTED) {
577 		(void) memcpy(sign_ctx->ssc_sign, signature, SMB_SIG_SIZE);
578 		sign_ok = smb_mac_chk(sign_ctx, smb_msgbuf_base(mb),
579 		    smb_msgbuf_size(mb));
580 		sign_ctx->ssc_seqnum++;
581 	}
582 
583 	return (sign_ok);
584 }
585