xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_common_transact.c (revision 7f3ef643e446c82e27a9386991b140b128baf22c)
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  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 #include <smbsrv/smb_kproto.h>
28 #include <smbsrv/smb_fsops.h>
29 #include <smbsrv/smb_share.h>
30 #include <smbsrv/string.h>
31 #include <smbsrv/nmpipes.h>
32 #include <smbsrv/mailslot.h>
33 
34 /*
35  * count of bytes in server response packet
36  * except parameters and data. Note that setup
37  * word count is zero.
38  */
39 #define	RESP_HEADER_LEN		24
40 
41 /*
42  * We started by using common functions for transaction/transaction2
43  * and transaction_secondary/transaction2_secondary because they
44  * are respectively so similar. However, it turned out to be a bad
45  * idea because of quirky differences. Be sure if you modify one
46  * of these four functions to check and see if the modification should
47  * be applied to its peer.
48  */
49 
50 static int smb_trans_ready(smb_xa_t *);
51 static smb_sdrc_t smb_trans_dispatch(smb_request_t *, smb_xa_t *);
52 static smb_sdrc_t smb_trans2_dispatch(smb_request_t *, smb_xa_t *);
53 
54 smb_sdrc_t
55 smb_pre_transaction(smb_request_t *sr)
56 {
57 	DTRACE_SMB_1(op__Transaction__start, smb_request_t *, sr);
58 	return (SDRC_SUCCESS);
59 }
60 
61 void
62 smb_post_transaction(smb_request_t *sr)
63 {
64 	DTRACE_SMB_1(op__Transaction__done, smb_request_t *, sr);
65 }
66 
67 smb_sdrc_t
68 smb_com_transaction(smb_request_t *sr)
69 {
70 	int		rc;
71 	unsigned char	msrcnt, suwcnt;
72 	uint16_t	tpscnt, tdscnt, mprcnt, mdrcnt, flags;
73 	uint16_t	pscnt, psoff, dscnt, dsoff;
74 	uint32_t	timeo;
75 	struct smb_xa *xa;
76 	char *stn;
77 	int ready;
78 
79 	rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT,
80 	    &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &msrcnt, &flags,
81 	    &timeo, &pscnt, &psoff, &dscnt, &dsoff, &suwcnt);
82 
83 	if (rc != 0)
84 		return (SDRC_ERROR);
85 
86 	xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
87 	    msrcnt, suwcnt);
88 	if (xa == NULL) {
89 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
90 		return (SDRC_ERROR);
91 	}
92 
93 	/* Should be some alignment stuff here in SMB? */
94 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) {
95 		rc = smbsr_decode_data(sr, "%.U", sr, &stn);
96 	} else {
97 		rc = smbsr_decode_data(sr, "%s", sr,  &stn);
98 	}
99 	if (rc != 0) {
100 		smb_xa_rele(sr->session, xa);
101 		return (SDRC_ERROR);
102 	}
103 
104 	xa->xa_pipe_name = smb_mem_strdup(stn);
105 	xa->smb_flags  = flags;
106 	xa->smb_timeout = timeo;
107 	xa->req_disp_param = pscnt;
108 	xa->req_disp_data  = dscnt;
109 
110 	if (smb_mbc_copy(&xa->req_setup_mb, &sr->smb_vwv,
111 	    sr->smb_vwv.chain_offset, suwcnt * 2)) {
112 		smb_xa_rele(sr->session, xa);
113 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
114 		return (SDRC_ERROR);
115 	}
116 	if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
117 		smb_xa_rele(sr->session, xa);
118 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
119 		return (SDRC_ERROR);
120 	}
121 	if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
122 		smb_xa_rele(sr->session, xa);
123 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
124 		return (SDRC_ERROR);
125 	}
126 
127 	ready = smb_trans_ready(xa);
128 
129 	if (smb_xa_open(xa)) {
130 		smb_xa_rele(sr->session, xa);
131 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
132 		return (SDRC_ERROR);
133 	}
134 	sr->r_xa = xa;
135 
136 	if (!ready) {
137 		rc = smbsr_encode_empty_result(sr);
138 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
139 	}
140 
141 	if (!smb_xa_complete(xa)) {
142 		smb_xa_close(xa);
143 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
144 		return (SDRC_ERROR);
145 	}
146 
147 	return (smb_trans_dispatch(sr, xa));
148 }
149 
150 smb_sdrc_t
151 smb_pre_transaction_secondary(smb_request_t *sr)
152 {
153 	DTRACE_SMB_1(op__TransactionSecondary__start, smb_request_t *, sr);
154 	return (SDRC_SUCCESS);
155 }
156 
157 void
158 smb_post_transaction_secondary(smb_request_t *sr)
159 {
160 	DTRACE_SMB_1(op__TransactionSecondary__done, smb_request_t *, sr);
161 }
162 
163 smb_sdrc_t
164 smb_com_transaction_secondary(smb_request_t *sr)
165 {
166 	uint16_t tpscnt, tdscnt, pscnt, psdisp;
167 	uint16_t dscnt, dsoff, dsdisp, psoff;
168 	smb_xa_t *xa;
169 	int rc;
170 
171 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
172 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
173 		return (SDRC_ERROR);
174 	}
175 
176 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
177 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
178 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
179 			    ERRDOS, ERRnoaccess);
180 			return (SDRC_ERROR);
181 		}
182 	}
183 
184 	if (xa->smb_com != SMB_COM_TRANSACTION) {
185 		return (SDRC_DROP_VC);
186 	}
187 
188 	rc = smbsr_decode_vwv(sr, SMB_TRANSSHDR_ED_FMT, &tpscnt, &tdscnt,
189 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp);
190 
191 	if (rc != 0)
192 		return (SDRC_ERROR);
193 
194 	mutex_enter(&xa->xa_mutex);
195 	if (xa->smb_tpscnt > tpscnt)
196 		xa->smb_tpscnt = tpscnt;
197 	if (xa->smb_tdscnt > tdscnt)
198 		xa->smb_tdscnt = tdscnt;
199 	xa->req_disp_param = psdisp + pscnt;
200 	xa->req_disp_data  = dsdisp + dscnt;
201 
202 	/*
203 	 * The words psdisp, dsdisp, tell us what displacement
204 	 * into the entire trans parameter and data buffers
205 	 * where we should put the params & data that are
206 	 * delivered by this request.  [MS-CIFS] says all the
207 	 * parameters and data SHOULD be sent sequentially, so
208 	 * so we can normally reassemble by simply appending.
209 	 * However, the components MAY come out of order, so
210 	 * check and set the current offset.  This is rare,
211 	 * and we might like to know when this happens, so
212 	 * fire some static dtrace probes when it does.
213 	 */
214 	if (xa->req_param_mb.chain_offset != psdisp) {
215 		DTRACE_PROBE2(trans_param_disp,
216 		    smb_xa_t *, xa, uint16_t, psdisp);
217 		xa->req_param_mb.chain_offset = psdisp;
218 	}
219 	if (xa->req_data_mb.chain_offset != dsdisp) {
220 		DTRACE_PROBE2(trans_data_disp,
221 		    smb_xa_t *, xa, uint16_t, dsdisp);
222 		xa->req_data_mb.chain_offset = dsdisp;
223 	}
224 
225 	if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
226 		mutex_exit(&xa->xa_mutex);
227 		smb_xa_close(xa);
228 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
229 		return (SDRC_ERROR);
230 	}
231 	if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
232 		mutex_exit(&xa->xa_mutex);
233 		smb_xa_close(xa);
234 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
235 		return (SDRC_ERROR);
236 	}
237 	mutex_exit(&xa->xa_mutex);
238 
239 	if (!smb_trans_ready(xa))
240 		return (SDRC_NO_REPLY);
241 
242 	if (!smb_xa_complete(xa))
243 		return (SDRC_NO_REPLY);
244 
245 	return (smb_trans_dispatch(sr, xa));
246 }
247 
248 smb_sdrc_t
249 smb_pre_ioctl(smb_request_t *sr)
250 {
251 	DTRACE_SMB_1(op__Ioctl__start, smb_request_t *, sr);
252 	return (SDRC_SUCCESS);
253 }
254 
255 void
256 smb_post_ioctl(smb_request_t *sr)
257 {
258 	DTRACE_SMB_1(op__Ioctl__done, smb_request_t *, sr);
259 }
260 
261 smb_sdrc_t
262 smb_com_ioctl(smb_request_t *sr)
263 {
264 	uint16_t fid, category, function, tpscnt, tdscnt, mprcnt;
265 	uint16_t mdrcnt, pscnt, pdoff, dscnt, dsoff;
266 	uint32_t timeout;
267 	int rc;
268 
269 	rc = smbsr_decode_vwv(sr, "wwwwwwwl2.wwww", &fid, &category, &function,
270 	    &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &timeout, &pscnt,
271 	    &pdoff, &dscnt, &dsoff);
272 
273 	if (rc != 0)
274 		return (SDRC_ERROR);
275 
276 	return (SDRC_NOT_IMPLEMENTED);
277 }
278 
279 smb_sdrc_t
280 smb_pre_transaction2(smb_request_t *sr)
281 {
282 	DTRACE_SMB_1(op__Transaction2__start, smb_request_t *, sr);
283 	return (SDRC_SUCCESS);
284 }
285 
286 void
287 smb_post_transaction2(smb_request_t *sr)
288 {
289 	DTRACE_SMB_1(op__Transaction2__done, smb_request_t *, sr);
290 }
291 
292 smb_sdrc_t
293 smb_com_transaction2(struct smb_request *sr)
294 {
295 	unsigned char	msrcnt, suwcnt;
296 	uint16_t	tpscnt, tdscnt, mprcnt, mdrcnt, flags;
297 	uint16_t	pscnt, psoff, dscnt, dsoff;
298 	uint32_t	timeo;
299 	smb_xa_t *xa;
300 	int ready;
301 	int rc;
302 
303 	rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT, &tpscnt, &tdscnt,
304 	    &mprcnt, &mdrcnt, &msrcnt, &flags, &timeo, &pscnt, &psoff, &dscnt,
305 	    &dsoff, &suwcnt);
306 
307 	if (rc != 0)
308 		return (SDRC_ERROR);
309 
310 	xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
311 	    msrcnt, suwcnt);
312 	if (xa == 0) {
313 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
314 		return (SDRC_ERROR);
315 	}
316 
317 	xa->smb_flags  = flags;
318 	xa->smb_timeout = timeo;
319 	xa->req_disp_param = pscnt;
320 	xa->req_disp_data  = dscnt;
321 
322 	if (smb_mbc_copy(&xa->req_setup_mb, &sr->smb_vwv,
323 	    sr->smb_vwv.chain_offset, suwcnt*2)) {
324 		smb_xa_rele(sr->session, xa);
325 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
326 		return (SDRC_ERROR);
327 	}
328 	if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
329 		smb_xa_rele(sr->session, xa);
330 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
331 		return (SDRC_ERROR);
332 	}
333 	if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
334 		smb_xa_rele(sr->session, xa);
335 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
336 		return (SDRC_ERROR);
337 	}
338 
339 	ready = smb_trans_ready(xa);
340 
341 	if (smb_xa_open(xa)) {
342 		smb_xa_rele(sr->session, xa);
343 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
344 		return (SDRC_ERROR);
345 	}
346 	sr->r_xa = xa;
347 
348 	if (!ready) {
349 		rc = smbsr_encode_empty_result(sr);
350 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
351 	}
352 
353 	if (!smb_xa_complete(xa)) {
354 		smb_xa_close(xa);
355 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
356 		return (SDRC_ERROR);
357 	}
358 
359 	return (smb_trans2_dispatch(sr, xa));
360 }
361 
362 smb_sdrc_t
363 smb_pre_transaction2_secondary(smb_request_t *sr)
364 {
365 	DTRACE_SMB_1(op__Transaction2Secondary__start, smb_request_t *, sr);
366 	return (SDRC_SUCCESS);
367 }
368 
369 void
370 smb_post_transaction2_secondary(smb_request_t *sr)
371 {
372 	DTRACE_SMB_1(op__Transaction2Secondary__done, smb_request_t *, sr);
373 }
374 
375 smb_sdrc_t
376 smb_com_transaction2_secondary(smb_request_t *sr)
377 {
378 	uint16_t tpscnt, tdscnt, fid;
379 	uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
380 	smb_xa_t *xa;
381 	int rc;
382 
383 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
384 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
385 		return (SDRC_ERROR);
386 	}
387 
388 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
389 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
390 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
391 			    ERRDOS, ERRnoaccess);
392 			return (SDRC_ERROR);
393 		}
394 	}
395 
396 	if (xa->smb_com != SMB_COM_TRANSACTION2) {
397 		return (SDRC_DROP_VC);
398 	}
399 
400 	rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
401 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
402 
403 	if (rc != 0)
404 		return (SDRC_ERROR);
405 
406 	mutex_enter(&xa->xa_mutex);
407 	if (xa->smb_tpscnt > tpscnt)
408 		xa->smb_tpscnt = tpscnt;
409 	if (xa->smb_tdscnt > tdscnt)
410 		xa->smb_tdscnt = tdscnt;
411 	if (fid != 0xFFFF)
412 		xa->xa_smb_fid = fid;
413 	xa->req_disp_param = psdisp + pscnt;
414 	xa->req_disp_data  = dsdisp + dscnt;
415 
416 	/*
417 	 * See comment in smb_com_transaction_secondary
418 	 */
419 	if (xa->req_param_mb.chain_offset != psdisp) {
420 		DTRACE_PROBE2(trans_param_disp,
421 		    smb_xa_t *, xa, uint16_t, psdisp);
422 		xa->req_param_mb.chain_offset = psdisp;
423 	}
424 	if (xa->req_data_mb.chain_offset != dsdisp) {
425 		DTRACE_PROBE2(trans_data_disp,
426 		    smb_xa_t *, xa, uint16_t, dsdisp);
427 		xa->req_data_mb.chain_offset = dsdisp;
428 	}
429 
430 	if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
431 		mutex_exit(&xa->xa_mutex);
432 		smb_xa_close(xa);
433 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
434 		return (SDRC_ERROR);
435 	}
436 	if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
437 		mutex_exit(&xa->xa_mutex);
438 		smb_xa_close(xa);
439 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
440 		return (SDRC_ERROR);
441 	}
442 	mutex_exit(&xa->xa_mutex);
443 
444 	if (!smb_trans_ready(xa))
445 		return (SDRC_NO_REPLY);
446 
447 	if (!smb_xa_complete(xa))
448 		return (SDRC_NO_REPLY);
449 
450 	return (smb_trans2_dispatch(sr, xa));
451 }
452 
453 static smb_sdrc_t
454 smb_nt_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
455 {
456 	int rc;
457 	int total_bytes, n_setup, n_param, n_data;
458 	int param_off, param_pad, data_off, data_pad;
459 
460 	switch (xa->smb_func) {
461 	case NT_TRANSACT_CREATE:
462 		if ((rc = smb_pre_nt_transact_create(sr, xa)) == 0)
463 			rc = smb_nt_transact_create(sr, xa);
464 		smb_post_nt_transact_create(sr, xa);
465 		break;
466 	case NT_TRANSACT_NOTIFY_CHANGE:
467 		rc = smb_nt_transact_notify_change(sr, xa);
468 		break;
469 	case NT_TRANSACT_QUERY_SECURITY_DESC:
470 		rc = smb_nt_transact_query_security_info(sr, xa);
471 		break;
472 	case NT_TRANSACT_SET_SECURITY_DESC:
473 		rc = smb_nt_transact_set_security_info(sr, xa);
474 		break;
475 	case NT_TRANSACT_IOCTL:
476 		rc = smb_nt_transact_ioctl(sr, xa);
477 		break;
478 	case NT_TRANSACT_QUERY_QUOTA:
479 		rc = smb_nt_transact_query_quota(sr, xa);
480 		break;
481 	case NT_TRANSACT_SET_QUOTA:
482 		rc = smb_nt_transact_set_quota(sr, xa);
483 		break;
484 	case NT_TRANSACT_RENAME:
485 		rc = smb_nt_transact_rename(sr, xa);
486 		break;
487 
488 	default:
489 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
490 		return (SDRC_ERROR);
491 	}
492 
493 	switch (rc) {
494 	case SDRC_SUCCESS:
495 		break;
496 
497 	case SDRC_DROP_VC:
498 	case SDRC_NO_REPLY:
499 	case SDRC_ERROR:
500 	case SDRC_SR_KEPT:
501 		return (rc);
502 
503 	case SDRC_NOT_IMPLEMENTED:
504 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
505 		return (SDRC_ERROR);
506 
507 	default:
508 		break;
509 	}
510 
511 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
512 	n_param = MBC_LENGTH(&xa->rep_param_mb);
513 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
514 
515 	if (xa->smb_msrcnt < n_setup ||
516 	    xa->smb_mprcnt < n_param ||
517 	    xa->smb_mdrcnt < n_data) {
518 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
519 		return (SDRC_ERROR);
520 	}
521 
522 	/* neato, blast it over there */
523 
524 	n_setup = (n_setup + 1) / 2;		/* Conver to setup words */
525 	param_pad = 1;				/* must be one */
526 	param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
527 	data_pad = (4 - ((param_off + n_param) & 3)) % 4; /* Pad to 4 byte */
528 	data_off = param_off + n_param + data_pad; /* Param off from hdr */
529 	total_bytes = param_pad + n_param + data_pad + n_data;
530 
531 	rc = smbsr_encode_result(sr, 18+n_setup, total_bytes,
532 	    "b3.llllllllbCw#.C#.C",
533 	    18 + n_setup,		/* wct */
534 	    n_param,			/* Total Parameter Bytes */
535 	    n_data,			/* Total Data Bytes */
536 	    n_param,			/* Total Parameter Bytes this buffer */
537 	    param_off,			/* Param offset from header start */
538 	    0,				/* Param displacement */
539 	    n_data,			/* Total Data Bytes this buffer */
540 	    data_off,			/* Data offset from header start */
541 	    0,				/* Data displacement */
542 	    n_setup,			/* suwcnt */
543 	    &xa->rep_setup_mb,		/* setup[] */
544 	    total_bytes,		/* Total data bytes */
545 	    param_pad,
546 	    &xa->rep_param_mb,
547 	    data_pad,
548 	    &xa->rep_data_mb);
549 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
550 }
551 
552 smb_sdrc_t
553 smb_pre_nt_transact(smb_request_t *sr)
554 {
555 	DTRACE_SMB_1(op__NtTransact__start, smb_request_t *, sr);
556 	return (SDRC_SUCCESS);
557 }
558 
559 void
560 smb_post_nt_transact(smb_request_t *sr)
561 {
562 	DTRACE_SMB_1(op__NtTransact__done, smb_request_t *, sr);
563 }
564 
565 smb_sdrc_t
566 smb_com_nt_transact(struct smb_request *sr)
567 {
568 	uint16_t	Function;
569 	unsigned char	MaxSetupCount, SetupCount;
570 	uint32_t	TotalParameterCount, TotalDataCount;
571 	uint32_t	MaxParameterCount, MaxDataCount, pscnt;
572 	uint32_t	psoff, dscnt, dsoff;
573 	smb_xa_t *xa;
574 	int ready;
575 	int rc;
576 
577 	rc = smbsr_decode_vwv(sr, SMB_NT_TRANSHDR_ED_FMT, &MaxSetupCount,
578 	    &TotalParameterCount, &TotalDataCount, &MaxParameterCount,
579 	    &MaxDataCount, &pscnt, &psoff, &dscnt,
580 	    &dsoff, &SetupCount, &Function);
581 
582 	if (rc != 0)
583 		return (SDRC_ERROR);
584 
585 	xa = smb_xa_create(sr->session, sr, TotalParameterCount, TotalDataCount,
586 	    MaxParameterCount, MaxDataCount, MaxSetupCount, SetupCount);
587 	if (xa == 0) {
588 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
589 		return (SDRC_ERROR);
590 	}
591 
592 	xa->smb_flags  = 0;
593 	xa->smb_timeout = 0;
594 	xa->smb_func = Function;
595 	xa->req_disp_param = pscnt;
596 	xa->req_disp_data  = dscnt;
597 
598 	if (smb_mbc_copy(&xa->req_setup_mb, &sr->smb_vwv,
599 	    sr->smb_vwv.chain_offset, SetupCount * 2)) {
600 		smb_xa_rele(sr->session, xa);
601 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
602 		return (SDRC_ERROR);
603 	}
604 	if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
605 		smb_xa_rele(sr->session, xa);
606 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
607 		return (SDRC_ERROR);
608 	}
609 	if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
610 		smb_xa_rele(sr->session, xa);
611 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
612 		return (SDRC_ERROR);
613 	}
614 
615 	ready = smb_trans_ready(xa);
616 
617 	if (smb_xa_open(xa)) {
618 		smb_xa_rele(sr->session, xa);
619 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
620 		return (SDRC_ERROR);
621 	}
622 	sr->r_xa = xa;
623 
624 	if (!ready) {
625 		rc = smbsr_encode_empty_result(sr);
626 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
627 	}
628 
629 	if (!smb_xa_complete(xa)) {
630 		smb_xa_close(xa);
631 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
632 		return (SDRC_ERROR);
633 	}
634 
635 	return (smb_nt_trans_dispatch(sr, xa));
636 }
637 
638 smb_sdrc_t
639 smb_pre_nt_transact_secondary(smb_request_t *sr)
640 {
641 	DTRACE_SMB_1(op__NtTransactSecondary__start, smb_request_t *, sr);
642 	return (SDRC_SUCCESS);
643 }
644 
645 void
646 smb_post_nt_transact_secondary(smb_request_t *sr)
647 {
648 	DTRACE_SMB_1(op__NtTransactSecondary__done, smb_request_t *, sr);
649 }
650 
651 smb_sdrc_t
652 smb_com_nt_transact_secondary(struct smb_request *sr)
653 {
654 	uint16_t tpscnt, tdscnt, fid;
655 	uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
656 	smb_xa_t *xa;
657 	int rc;
658 
659 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
660 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
661 		return (SDRC_ERROR);
662 	}
663 
664 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
665 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
666 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
667 			    ERRDOS, ERRnoaccess);
668 			return (SDRC_ERROR);
669 		}
670 	}
671 
672 	if (xa->smb_com != SMB_COM_TRANSACTION2) {
673 		return (SDRC_DROP_VC);
674 	}
675 
676 	rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
677 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
678 
679 	if (rc != 0)
680 		return (SDRC_ERROR);
681 
682 	mutex_enter(&xa->xa_mutex);
683 	if (xa->smb_tpscnt > tpscnt)
684 		xa->smb_tpscnt = tpscnt;
685 	if (xa->smb_tdscnt > tdscnt)
686 		xa->smb_tdscnt = tdscnt;
687 	if (fid != 0xFFFF)
688 		xa->xa_smb_fid = fid;
689 	xa->req_disp_param = psdisp + pscnt;
690 	xa->req_disp_data  = dsdisp + dscnt;
691 
692 	/*
693 	 * See comment in smb_com_transaction_secondary
694 	 */
695 	if (xa->req_param_mb.chain_offset != psdisp) {
696 		DTRACE_PROBE2(trans_param_disp,
697 		    smb_xa_t *, xa, uint16_t, psdisp);
698 		xa->req_param_mb.chain_offset = psdisp;
699 	}
700 	if (xa->req_data_mb.chain_offset != dsdisp) {
701 		DTRACE_PROBE2(trans_data_disp,
702 		    smb_xa_t *, xa, uint16_t, dsdisp);
703 		xa->req_data_mb.chain_offset = dsdisp;
704 	}
705 
706 	if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
707 		mutex_exit(&xa->xa_mutex);
708 		smb_xa_close(xa);
709 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
710 		return (SDRC_ERROR);
711 	}
712 	if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
713 		mutex_exit(&xa->xa_mutex);
714 		smb_xa_close(xa);
715 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
716 		return (SDRC_ERROR);
717 	}
718 	mutex_exit(&xa->xa_mutex);
719 
720 	if (!smb_trans_ready(xa))
721 		return (SDRC_NO_REPLY);
722 
723 	if (!smb_xa_complete(xa))
724 		return (SDRC_NO_REPLY);
725 
726 	return (smb_nt_trans_dispatch(sr, xa));
727 }
728 
729 static int
730 smb_trans_ready(smb_xa_t *xa)
731 {
732 	int rc;
733 
734 	mutex_enter(&xa->xa_mutex);
735 	rc = xa->req_disp_data >= xa->smb_tdscnt &&
736 	    xa->req_disp_param >= xa->smb_tpscnt;
737 	mutex_exit(&xa->xa_mutex);
738 
739 	return (rc);
740 }
741 
742 static void
743 smb_encode_SHARE_INFO_1(struct mbuf_chain *output, struct mbuf_chain *text,
744     char *oem_name, uint16_t type, char *comment)
745 {
746 	(void) smb_mbc_encodef(output, "13c.wl", oem_name,
747 	    type, MBC_LENGTH(text));
748 
749 	(void) smb_mbc_encodef(text, "s", comment ? comment : "");
750 }
751 
752 static void
753 smb_encode_SHARE_INFO_2(struct mbuf_chain *output, struct mbuf_chain *text,
754 	smb_request_t *sr, char *oem_name, uint16_t type,
755 	char *comment, uint16_t access, char *path, char *password)
756 {
757 	unsigned char pword[9];
758 
759 	bzero(pword, sizeof (pword));
760 	(void) strncpy((char *)pword, password, sizeof (pword));
761 	smb_encode_SHARE_INFO_1(output, text, oem_name, type, comment);
762 	(void) smb_mbc_encodef(output, "wwwl9c.",
763 	    access,
764 	    sr->sr_cfg->skc_maxconnections,
765 	    smb_server_get_session_count(),
766 	    MBC_LENGTH(text),
767 	    pword);
768 	(void) smb_mbc_encodef(text, "s", path);
769 }
770 
771 int
772 smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
773 {
774 	/*
775 	 * Number of data bytes that will
776 	 * be sent in the current response
777 	 */
778 	uint16_t data_scnt;
779 
780 	/*
781 	 * Total number of data bytes that
782 	 * are sent till now. This is only
783 	 * used for calculating current data
784 	 * displacement
785 	 */
786 	uint16_t tot_data_scnt;
787 
788 	/*
789 	 * Number of parameter bytes should
790 	 * be sent for the current response.
791 	 * It is 8 for the 1st response and
792 	 * 0 for others
793 	 */
794 	uint16_t param_scnt;
795 
796 	/* number of setup and parameter bytes */
797 	uint16_t n_setup, n_param;
798 
799 	/* data and parameter displacement */
800 	uint16_t data_disp, param_disp;
801 
802 	/* parameter and data offset and pad */
803 	int param_off, param_pad, data_off, data_pad;
804 
805 	/*
806 	 * total bytes of parameters and data
807 	 * in the packet, plus the pad bytes.
808 	 */
809 	int tot_packet_bytes;
810 
811 	boolean_t first_resp;
812 
813 	char fmt[16];
814 	struct mbuf_chain reply;
815 
816 	uint16_t level;
817 	uint16_t pkt_bufsize;
818 	smb_enumshare_info_t esi;
819 	char *sent_buf;
820 
821 	ASSERT(sr->uid_user);
822 
823 	if (smb_mbc_decodef(&xa->req_param_mb, "ww", &level,
824 	    &esi.es_bufsize) != 0)
825 		return (SDRC_NOT_IMPLEMENTED);
826 
827 	if (level != 1) {
828 		/*
829 		 * Only level 1 is valid for NetShareEnum
830 		 * None of the error codes in the spec are meaningful
831 		 * here. This error code is returned by Windows.
832 		 */
833 		(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
834 		    ERROR_INVALID_LEVEL, 0, 0, 0);
835 		return (SDRC_SUCCESS);
836 	}
837 
838 	esi.es_buf = smb_srm_zalloc(sr, esi.es_bufsize);
839 	esi.es_posix_uid = crgetuid(sr->uid_user->u_cred);
840 	smb_kshare_enum(&esi);
841 
842 	/* client buffer size is not big enough to hold any shares */
843 	if (esi.es_nsent == 0) {
844 		(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
845 		    ERROR_MORE_DATA, 0, esi.es_nsent, esi.es_ntotal);
846 		return (SDRC_SUCCESS);
847 	}
848 
849 	/*
850 	 * Initialize the reply mbuf chain.  Note that we re-initialize
851 	 * this on each pass through the loop below.
852 	 */
853 	MBC_SETUP(&reply, smb_maxbufsize);
854 
855 	/*
856 	 * The rep_setup_mb is already initialized in smb_trans_dispatch().
857 	 * Calling MBC_INIT() will initialized the structure and so the
858 	 * pointer to the mbuf chains will be lost. Therefore, we need
859 	 * to free the resources before calling MBC_INIT() again.
860 	 */
861 	n_setup = 0;	/* Setup count for NetShareEnum SMB is 0 */
862 	MBC_FLUSH(&xa->rep_setup_mb);
863 
864 	n_param = 8;
865 	pkt_bufsize = sr->session->smb_msg_size -
866 	    (SMB_HEADER_ED_LEN + RESP_HEADER_LEN + n_param);
867 
868 	tot_data_scnt = 0;
869 	sent_buf = esi.es_buf;
870 	first_resp = B_TRUE;
871 
872 	while (tot_data_scnt < esi.es_datasize) {
873 		data_scnt = esi.es_datasize - tot_data_scnt;
874 		if (data_scnt > pkt_bufsize)
875 			data_scnt = pkt_bufsize;
876 		MBC_FLUSH(&xa->rep_data_mb);
877 
878 		(void) sprintf(fmt, "%dc", data_scnt);
879 		(void) smb_mbc_encodef(&xa->rep_data_mb, fmt, sent_buf);
880 
881 		sent_buf += data_scnt;
882 		tot_data_scnt += data_scnt;
883 
884 		/* Only the 1st response packet contains parameters */
885 		param_scnt = (first_resp) ? n_param : 0;
886 		param_pad = 1;				/* always one */
887 		param_off = SMB_HEADER_ED_LEN + RESP_HEADER_LEN;
888 		param_disp = (first_resp) ? 0 : n_param;
889 
890 		MBC_FLUSH(&xa->rep_param_mb);
891 
892 		if (first_resp) {
893 			first_resp = B_FALSE;
894 			(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
895 			    (esi.es_ntotal > esi.es_nsent)
896 			    ? ERROR_MORE_DATA : 0,
897 			    0, esi.es_nsent, esi.es_ntotal);
898 		}
899 
900 		data_pad = (param_off + n_param) & 1;	/* Pad to short */
901 
902 		/* data off from hdr start */
903 		data_off = param_off + param_scnt + data_pad;
904 		data_disp = tot_data_scnt - data_scnt;
905 		tot_packet_bytes = param_pad + param_scnt + data_pad +
906 		    data_scnt;
907 
908 		MBC_FLUSH(&reply);
909 		(void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT,
910 		    sr->first_smb_com,
911 		    sr->smb_rcls,
912 		    sr->smb_reh,
913 		    sr->smb_err,
914 		    sr->smb_flg | SMB_FLAGS_REPLY,
915 		    sr->smb_flg2,
916 		    sr->smb_pid_high,
917 		    sr->smb_sig,
918 		    sr->smb_tid,
919 		    sr->smb_pid,
920 		    sr->smb_uid,
921 		    sr->smb_mid);
922 
923 		(void) smb_mbc_encodef(&reply,
924 		    "bww2.wwwwwwb.Cw#.C#.C",
925 		    10 + n_setup,	/* wct */
926 		    n_param,		/* Total Parameter Bytes */
927 		    esi.es_datasize,	/* Total Data Bytes */
928 		    param_scnt,		/* Total Parameter Bytes this buffer */
929 		    param_off,		/* Param offset from header start */
930 		    param_disp,		/* Param displacement */
931 		    data_scnt,		/* Total Data Bytes this buffer */
932 		    data_off,		/* Data offset from header start */
933 		    data_disp,		/* Data displacement */
934 		    n_setup,		/* suwcnt */
935 		    &xa->rep_setup_mb, 	/* setup[] */
936 		    tot_packet_bytes,	/* Total data bytes */
937 		    param_pad,
938 		    &xa->rep_param_mb,
939 		    data_pad,
940 		    &xa->rep_data_mb);
941 
942 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
943 			smb_sign_reply(sr, &reply);
944 
945 		(void) smb_session_send(sr->session, 0, &reply);
946 
947 	}
948 
949 	m_freem(reply.chain);
950 
951 	return (SDRC_NO_REPLY);
952 }
953 
954 int
955 smb_trans_net_share_getinfo(smb_request_t *sr, struct smb_xa *xa)
956 {
957 	uint16_t		level, max_bytes, access;
958 	struct mbuf_chain	str_mb;
959 	char			*share;
960 	char			*password;
961 	smb_kshare_t		*si;
962 
963 	if (smb_mbc_decodef(&xa->req_param_mb, "%sww", sr,
964 	    &share, &level, &max_bytes) != 0)
965 		return (SDRC_NOT_IMPLEMENTED);
966 
967 	si = smb_kshare_lookup(share);
968 	if ((si == NULL) || (si->shr_oemname == NULL)) {
969 		(void) smb_mbc_encodef(&xa->rep_param_mb, "www",
970 		    NERR_NetNameNotFound, 0, 0);
971 		if (si)
972 			smb_kshare_release(si);
973 		return (SDRC_SUCCESS);
974 	}
975 
976 	access = SHARE_ACCESS_ALL;
977 	password = "";
978 
979 	MBC_INIT(&str_mb, max_bytes);
980 
981 	switch (level) {
982 	case 0 :
983 		(void) smb_mbc_encodef(&xa->rep_data_mb, "13c",
984 		    si->shr_oemname);
985 		break;
986 
987 	case 1 :
988 		smb_encode_SHARE_INFO_1(&xa->rep_data_mb, &str_mb,
989 		    si->shr_oemname, si->shr_type, si->shr_cmnt);
990 		break;
991 
992 	case 2 :
993 		smb_encode_SHARE_INFO_2(&xa->rep_data_mb, &str_mb, sr,
994 		    si->shr_oemname, si->shr_type, si->shr_cmnt, access,
995 		    si->shr_path, password);
996 		break;
997 
998 	default:
999 		smb_kshare_release(si);
1000 		(void) smb_mbc_encodef(&xa->rep_param_mb, "www",
1001 		    ERROR_INVALID_LEVEL, 0, 0);
1002 		m_freem(str_mb.chain);
1003 		return (SDRC_NOT_IMPLEMENTED);
1004 	}
1005 
1006 	smb_kshare_release(si);
1007 	(void) smb_mbc_encodef(&xa->rep_param_mb, "www", NERR_Success,
1008 	    -MBC_LENGTH(&xa->rep_data_mb),
1009 	    MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
1010 	(void) smb_mbc_encodef(&xa->rep_data_mb, "C", &str_mb);
1011 	m_freem(str_mb.chain);
1012 	return (SDRC_SUCCESS);
1013 }
1014 
1015 int
1016 smb_trans_net_workstation_getinfo(struct smb_request *sr, struct smb_xa *xa)
1017 {
1018 	uint16_t		level, max_bytes;
1019 	struct mbuf_chain	str_mb;
1020 	char *domain;
1021 	char *hostname;
1022 
1023 	if ((smb_mbc_decodef(&xa->req_param_mb, "ww",
1024 	    &level, &max_bytes) != 0) ||
1025 	    (level != 10)) {
1026 		(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
1027 		    NERR_BadTransactConfig, 0, 0, 0);
1028 		return (SDRC_SUCCESS);
1029 	}
1030 
1031 	domain = sr->sr_cfg->skc_nbdomain;
1032 	hostname = sr->sr_cfg->skc_hostname;
1033 
1034 	MBC_INIT(&str_mb, max_bytes);
1035 
1036 	(void) smb_mbc_encodef(&str_mb, "."); /* Prevent NULL pointers */
1037 
1038 	(void) smb_mbc_encodef(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1039 	(void) smb_mbc_encodef(&str_mb, "s", hostname);
1040 	(void) smb_mbc_encodef(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1041 	(void) smb_mbc_encodef(&str_mb, "s", "nobody");
1042 	(void) smb_mbc_encodef(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1043 	(void) smb_mbc_encodef(&str_mb, "s", domain);
1044 	(void) smb_mbc_encodef(&xa->rep_data_mb, "bbl",
1045 	    (uint8_t)sr->sr_cfg->skc_version.sv_major,
1046 	    (uint8_t)sr->sr_cfg->skc_version.sv_minor,
1047 	    MBC_LENGTH(&str_mb));
1048 	(void) smb_mbc_encodef(&str_mb, "s", domain);
1049 	(void) smb_mbc_encodef(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1050 	(void) smb_mbc_encodef(&str_mb, "s", domain);
1051 
1052 	(void) smb_mbc_encodef(&xa->rep_param_mb, "www", 0,
1053 	    -MBC_LENGTH(&xa->rep_data_mb),
1054 	    MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
1055 	(void) smb_mbc_encodef(&xa->rep_data_mb, "C", &str_mb);
1056 	m_freem(str_mb.chain);
1057 	return (SDRC_SUCCESS);
1058 }
1059 
1060 int
1061 smb_trans_net_user_getinfo(struct smb_request *sr, struct smb_xa *xa)
1062 {
1063 	uint16_t		level, max_bytes;
1064 	unsigned char		*user;
1065 	int rc;
1066 
1067 	rc = smb_mbc_decodef(&xa->req_param_mb, "%sww", sr,
1068 	    &user,
1069 	    &level,
1070 	    &max_bytes);
1071 
1072 	if (rc != 0)
1073 		return (SDRC_NOT_IMPLEMENTED);
1074 
1075 	(void) smb_mbc_encodef(&xa->rep_param_mb, "www",
1076 	    NERR_UserNotFound, 0, 0);
1077 	return (SDRC_SUCCESS);
1078 }
1079 
1080 smb_sdrc_t
1081 smb_trans_net_server_getinfo(struct smb_request *sr, struct smb_xa *xa)
1082 {
1083 	uint16_t		level, buf_size;
1084 	uint16_t		avail_data, max_data;
1085 	char			server_name[16];
1086 	struct mbuf_chain	str_mb;
1087 
1088 	if (smb_mbc_decodef(&xa->req_param_mb, "ww", &level, &buf_size) != 0)
1089 		return (SDRC_ERROR);
1090 
1091 	max_data = MBC_MAXBYTES(&xa->rep_data_mb);
1092 
1093 	MBC_INIT(&str_mb, buf_size);
1094 
1095 	bzero(server_name, sizeof (server_name));
1096 	(void) strncpy(server_name, sr->sr_cfg->skc_hostname,
1097 	    sizeof (server_name));
1098 
1099 	/* valid levels are 0 and 1 */
1100 	switch (level) {
1101 	case 0:
1102 		(void) smb_mbc_encodef(&xa->rep_data_mb, "16c", server_name);
1103 		break;
1104 
1105 	case 1:
1106 		(void) smb_mbc_encodef(&str_mb, "s",
1107 		    sr->sr_cfg->skc_system_comment);
1108 		(void) smb_mbc_encodef(&xa->rep_data_mb, "16cbbll", server_name,
1109 		    (uint8_t)sr->sr_cfg->skc_version.sv_major,
1110 		    (uint8_t)sr->sr_cfg->skc_version.sv_minor,
1111 		    MY_SERVER_TYPE, max_data - MBC_LENGTH(&str_mb));
1112 		break;
1113 
1114 	default:
1115 		(void) smb_mbc_encodef(&xa->rep_param_mb, "www",
1116 		    ERROR_INVALID_LEVEL, 0, 0);
1117 		m_freem(str_mb.chain);
1118 		return (SDRC_SUCCESS);
1119 	}
1120 
1121 	avail_data = MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb);
1122 	(void) smb_mbc_encodef(&xa->rep_param_mb, "www",
1123 	    NERR_Success, max_data - avail_data, avail_data);
1124 	(void) smb_mbc_encodef(&xa->rep_data_mb, "C", &str_mb);
1125 	m_freem(str_mb.chain);
1126 	return (SDRC_SUCCESS);
1127 }
1128 
1129 /*
1130  * 6.4 The NetServerEnum2 RAP Service
1131  *
1132  * The NetServerEnum2 RAP service lists all computers of the specified type
1133  * or types that are visible in the specified domains. It may also
1134  * enumerate domains.
1135  *
1136  * The following definition uses the notation and terminology defined in
1137  * the CIFS Remote Administration Protocol specification, which is required
1138  * in order to make it well-defined. The definition is:
1139  *
1140  *     uint16_t NetServerEnum2 (
1141  *         uint16_t  sLevel,
1142  *         RCVBUF          pbBuffer,
1143  *         RCVBUFLEN       cbBuffer,
1144  *         ENTCOUNT        pcEntriesRead,
1145  *         uint16_t  *pcTotalAvail,
1146  *         uint32_t   fServerType,
1147  *         char            *pszDomain,
1148  *     );
1149  *
1150  * where:
1151  *
1152  *    sLevel specifies the level of detail (0 or 1) requested.
1153  *
1154  *    pbBuffer points to the buffer to receive the returned data. If the
1155  *    function is successful, the buffer contains a sequence of
1156  *    server_info_x structures, where x is 0 or 1, depending on the
1157  *    level of detail requested.
1158  *
1159  *    cbBuffer specifies the size, in bytes, of the buffer pointed to by
1160  *    the pbBuffer parameter.
1161  *
1162  *    pcEntriesRead points to a 16 bit variable that receives a count of
1163  *    the number of servers enumerated in the buffer. This count is
1164  *    valid only if NetServerEnum2 returns the NERR_Success or
1165  *    ERROR_MORE_DATA values.
1166  *
1167  *    pcTotal Avail points to a 16 bit variable that receives a count of
1168  *    the total number of available entries. This count is valid only if
1169  *    NetServerEnum2 returns the NERR_Success or ERROR_MORE_DATA values.
1170  *
1171  *     fServerType specifies the type or types of computers to enumerate.
1172  *     Computers that match at least one of the specified types are
1173  *     returned in the buffer. Possible values are defined in the request
1174  *     parameters section.
1175  *
1176  *    pszDomain points to a null-terminated string that contains the
1177  *    name of the workgroup in which to enumerate computers of the
1178  *    specified type or types. If the pszDomain parameter is a null
1179  *    string or a null pointer, servers are enumerated for the current
1180  *    domain of the computer.
1181  *
1182  * 6.4.1 Transaction Request Parameters section
1183  *
1184  * The Transaction request parameters section in this instance contains:
1185  * . The 16 bit function number for NetServerEnum2 which is 104.
1186  * . The parameter descriptor string which is "WrLehDz".
1187  * . The data descriptor string for the (returned) data which is "B16" for
1188  *   level detail 0 or "B16BBDz" for level detail 1.
1189  * . The actual parameters as described by the parameter descriptor
1190  *   string.
1191  *
1192  * The parameters are:
1193  * . A 16 bit integer with a value of 0 or 1 (corresponding to the "W" in
1194  *   the parameter descriptor string. This represents the level of detail
1195  *   the server is expected to return
1196  * . A 16 bit integer that contains the size of the receive buffer.
1197  * . A 32 bit integer that represents the type of servers the function
1198  *   should enumerate. The possible values may be any of the following or
1199  *   a combination of the following:
1200  *
1201  * SV_TYPE_WORKSTATION        0x00000001 All workstations
1202  * SV_TYPE_SERVER             0x00000002 All servers
1203  * SV_TYPE_SQLSERVER          0x00000004 Any server running with SQL
1204  *                                       server
1205  * SV_TYPE_DOMAIN_CTRL        0x00000008 Primary domain controller
1206  * SV_TYPE_DOMAIN_BAKCTRL     0x00000010 Backup domain controller
1207  * SV_TYPE_TIME_SOURCE        0x00000020 Server running the timesource
1208  *                                       service
1209  * SV_TYPE_AFP                0x00000040 Apple File Protocol servers
1210  * SV_TYPE_NOVELL             0x00000080 Novell servers
1211  * SV_TYPE_DOMAIN_MEMBER      0x00000100 Domain Member
1212  * SV_TYPE_PRINTQ_SERVER      0x00000200 Server sharing print queue
1213  * SV_TYPE_DIALIN_SERVER      0x00000400 Server running dialin service.
1214  * SV_TYPE_XENIX_SERVER       0x00000800 Xenix server
1215  * SV_TYPE_NT                 0x00001000 NT server
1216  * SV_TYPE_WFW                0x00002000 Server running Windows for
1217  *                                       Workgroups
1218  * SV_TYPE_SERVER_NT          0x00008000 Windows NT non DC server
1219  * SV_TYPE_POTENTIAL_BROWSER  0x00010000 Server that can run the browser
1220  *                                       service
1221  * SV_TYPE_BACKUP_BROWSER     0x00020000 Backup browser server
1222  * SV_TYPE_MASTER_BROWSER     0x00040000 Master browser server
1223  * SV_TYPE_DOMAIN_MASTER      0x00080000 Domain Master Browser server
1224  * SV_TYPE_LOCAL_LIST_ONLY    0x40000000 Enumerate only entries marked
1225  *                                       "local"
1226  * SV_TYPE_DOMAIN_ENUM        0x80000000 Enumerate Domains. The pszDomain
1227  *                                       parameter must be NULL.
1228  *
1229  * . A null terminated ASCII string representing the pszDomain parameter
1230  *   described above
1231  *
1232  * 6.4.2 Transaction Request Data section
1233  *
1234  * There is no data or auxiliary data to send as part of the request.
1235  *
1236  * 6.4.3 Transaction Response Parameters section
1237  *
1238  * The transaction response parameters section consists of:
1239  * . A 16 bit word indicating the return status. The possible values are:
1240  *
1241  * Code                   Value  Description
1242  * NERR_Success           0      No errors encountered
1243  * ERROR_MORE_DATA        234    Additional data is available
1244  * NERR_ServerNotStarted  2114   The RAP service on the remote computer
1245  *                               is not running
1246  * NERR_BadTransactConfig 2141   The server is not configured for
1247  *                               transactions, IPC$ is not shared
1248  *
1249  * . A 16 bit "converter" word.
1250  * . A 16 bit number representing the number of entries returned.
1251  * . A 16 bit number representing the total number of available entries.
1252  *   If the supplied buffer is large enough, this will equal the number of
1253  *   entries returned.
1254  *
1255  * 6.4.4 Transaction Response Data section
1256  *
1257  * The return data section consists of a number of SERVER_INFO_1 structures.
1258  * The number of such structures present is determined by the third entry
1259  * (described above) in the return parameters section.
1260  *
1261  * At level detail 0, the Transaction response data section contains a
1262  * number of SERVER_INFO_0 data structure. The number of such structures is
1263  * equal to the 16 bit number returned by the server in the third parameter
1264  * in the Transaction response parameter section. The SERVER_INFO_0 data
1265  * structure is defined as:
1266  *
1267  *     struct SERVER_INFO_0 {
1268  *         char        sv0_name[16];
1269  *     };
1270  *
1271  *  where:
1272  *
1273  *    sv0_name is a null-terminated string that specifies the name of a
1274  *    computer or domain .
1275  *
1276  * At level detail 1, the Transaction response data section contains a
1277  * number of SERVER_INFO_1 data structure. The number of such structures is
1278  * equal to the 16 bit number returned by the server in the third parameter
1279  * in the Transaction response parameter section. The SERVER_INFO_1 data
1280  * structure is defined as:
1281  *
1282  *     struct SERVER_INFO_1 {
1283  *         char            sv1_name[16];
1284  *         char            sv1_version_major;
1285  *         char            sv1_version_minor;
1286  *         uint32_t   sv1_type;
1287  *         char        *sv1_comment_or_master_browser;
1288  *     };
1289  *
1290  *    sv1_name contains a null-terminated string that specifies the name
1291  *    of a computer, or a domain name if SV_TYPE_DOMAIN_ENUM is set in
1292  *    sv1_type.
1293  *
1294  *    sv1_version_major whatever was specified in the HostAnnouncement
1295  *    or DomainAnnouncement frame with which the entry was registered.
1296  *
1297  *    sv1_version_minor whatever was specified in the HostAnnouncement
1298  *    or DomainAnnouncement frame with which the entry was registered.
1299  *
1300  *    sv1_type specifies the type of software the computer is running.
1301  *    The member can be one or a combination of the values defined above
1302  *    in the Transaction request parameters section for fServerType.
1303  *
1304  *
1305  *    sv1_comment_or_master_browser points to a null-terminated string. If
1306  *    the sv1_type indicates that the entry is for a domain, this
1307  *    specifies the name of server running the domain master browser;
1308  *    otherwise, it specifies a comment describing the server. The comment
1309  *    can be a null string or the pointer may be a null pointer.
1310  *
1311  *    In case there are multiple SERVER_INFO_1 data structures to
1312  *    return, the server may put all these fixed length structures in
1313  *    the return buffer, leave some space and then put all the variable
1314  *    length data (the actual value of the sv1_comment strings) at the
1315  *    end of the buffer.
1316  *
1317  * There is no auxiliary data to receive.
1318  */
1319 
1320 int
1321 smb_trans_net_server_enum2(struct smb_request *sr, struct smb_xa *xa)
1322 {
1323 	uint16_t opcode, level, max_bytes;
1324 	uint32_t server_type;
1325 	unsigned char *domain;
1326 	struct mbuf_chain str_mb;
1327 	char *hostname, *s;
1328 	smb_kmod_cfg_t *si;
1329 
1330 	if (smb_mbc_decodef(&xa->req_param_mb,
1331 	    "%wsswwls", sr, &opcode, &s, &s,
1332 	    &level, &max_bytes, &server_type, &domain) != 0)
1333 		return (SDRC_NOT_IMPLEMENTED);
1334 
1335 	si = sr->sr_cfg;
1336 
1337 	if (smb_strcasecmp(si->skc_nbdomain, (char *)domain, 0) != 0) {
1338 		(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
1339 		return (SDRC_SUCCESS);
1340 	}
1341 
1342 	if ((server_type & MY_SERVER_TYPE) == 0) {
1343 		(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
1344 		return (SDRC_SUCCESS);
1345 	}
1346 
1347 	MBC_INIT(&str_mb, max_bytes);
1348 
1349 	hostname = si->skc_hostname;
1350 
1351 	(void) smb_mbc_encodef(&xa->rep_data_mb, "16c", hostname);
1352 	if (level == 1) {
1353 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbll",
1354 		    (uint8_t)sr->sr_cfg->skc_version.sv_major,
1355 		    (uint8_t)sr->sr_cfg->skc_version.sv_minor,
1356 		    MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
1357 		(void) smb_mbc_encodef(&str_mb, "s", si->skc_system_comment);
1358 	}
1359 
1360 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", 0,
1361 	    -MBC_LENGTH(&xa->rep_data_mb), 1, 1);
1362 	(void) smb_mbc_encodef(&xa->rep_data_mb, "m", str_mb.chain);
1363 	return (SDRC_SUCCESS);
1364 }
1365 
1366 static boolean_t
1367 is_supported_mailslot(const char *mailslot)
1368 {
1369 	static char *mailslots[] = {
1370 		PIPE_LANMAN,
1371 		MAILSLOT_LANMAN,
1372 		MAILSLOT_BROWSE,
1373 		MAILSLOT_MSBROWSE
1374 	};
1375 
1376 	int i;
1377 
1378 	for (i = 0; i < sizeof (mailslots)/sizeof (mailslots[0]); ++i)
1379 		if (smb_strcasecmp(mailslot, mailslots[i], 0) == 0)
1380 			return (B_TRUE);
1381 
1382 	return (B_FALSE);
1383 }
1384 
1385 /*
1386  * Currently, just return false if the pipe is \\PIPE\repl.
1387  * Otherwise, return true.
1388  */
1389 static boolean_t
1390 is_supported_pipe(const char *pname)
1391 {
1392 	if (smb_strcasecmp(pname, PIPE_REPL, 0) == 0)
1393 		return (B_FALSE);
1394 
1395 	return (B_TRUE);
1396 }
1397 
1398 static smb_sdrc_t
1399 smb_trans_dispatch(smb_request_t *sr, smb_xa_t *xa)
1400 {
1401 	int		rc, pos;
1402 	int		total_bytes, n_setup, n_param, n_data;
1403 	int		param_off, param_pad, data_off, data_pad;
1404 	uint16_t	opcode;
1405 	uint16_t	devstate;
1406 	char		*req_fmt;
1407 	char		*rep_fmt;
1408 	smb_vdb_t	vdb;
1409 
1410 	if (xa->smb_suwcnt > 0 && STYPE_ISIPC(sr->tid_tree->t_res_type)) {
1411 		rc = smb_mbc_decodef(&xa->req_setup_mb, "ww", &opcode,
1412 		    &sr->smb_fid);
1413 		if (rc != 0)
1414 			goto trans_err_not_supported;
1415 		switch (opcode) {
1416 		case TRANS_SET_NMPIPE_STATE:
1417 			if ((rc = smb_mbc_decodef(&xa->req_param_mb, "w",
1418 			    &devstate)) != 0)
1419 				goto trans_err_not_supported;
1420 
1421 			rc = SDRC_SUCCESS;
1422 			break;
1423 
1424 		case TRANS_TRANSACT_NMPIPE:
1425 			smbsr_lookup_file(sr);
1426 			if (sr->fid_ofile == NULL) {
1427 				smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
1428 				    ERRDOS, ERRbadfid);
1429 				return (SDRC_ERROR);
1430 			}
1431 
1432 			rc = smb_mbc_decodef(&xa->req_data_mb, "#B",
1433 			    xa->smb_tdscnt, &vdb);
1434 			if (rc != 0)
1435 				goto trans_err_not_supported;
1436 
1437 			rc = smb_opipe_transact(sr, &vdb.vdb_uio);
1438 			break;
1439 
1440 		case TRANS_WAIT_NMPIPE:
1441 			if (!is_supported_pipe(xa->xa_pipe_name)) {
1442 				smbsr_error(sr, 0, ERRDOS, ERRbadfile);
1443 				return (SDRC_ERROR);
1444 			}
1445 			rc = SDRC_SUCCESS;
1446 			break;
1447 
1448 		default:
1449 			goto trans_err_not_supported;
1450 		}
1451 	} else {
1452 		if (!is_supported_mailslot(xa->xa_pipe_name))
1453 			goto trans_err_not_supported;
1454 
1455 		if ((rc = smb_mbc_decodef(&xa->req_param_mb, "%wss", sr,
1456 		    &opcode, &req_fmt, &rep_fmt)) != 0)
1457 			goto trans_err_not_supported;
1458 
1459 		switch (opcode) {
1460 		case API_WshareEnum:
1461 			rc = smb_trans_net_share_enum(sr, xa);
1462 			break;
1463 
1464 		case API_WshareGetInfo:
1465 			rc = smb_trans_net_share_getinfo(sr, xa);
1466 			break;
1467 
1468 		case API_WserverGetInfo:
1469 			rc = smb_trans_net_server_getinfo(sr, xa);
1470 			break;
1471 
1472 		case API_WUserGetInfo:
1473 			rc = smb_trans_net_user_getinfo(sr, xa);
1474 			break;
1475 
1476 		case API_WWkstaGetInfo:
1477 			rc = smb_trans_net_workstation_getinfo(sr, xa);
1478 			break;
1479 
1480 		case API_NetServerEnum2:
1481 			rc = smb_trans_net_server_enum2(sr, xa);
1482 			break;
1483 
1484 		default:
1485 			goto trans_err_not_supported;
1486 		}
1487 	}
1488 
1489 	switch (rc) {
1490 	case SDRC_SUCCESS:
1491 		break;
1492 
1493 	case SDRC_DROP_VC:
1494 	case SDRC_NO_REPLY:
1495 	case SDRC_ERROR:
1496 		return (rc);
1497 
1498 	case SDRC_NOT_IMPLEMENTED:
1499 		goto trans_err_not_supported;
1500 
1501 	default:
1502 		break;
1503 	}
1504 
1505 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
1506 	n_param = MBC_LENGTH(&xa->rep_param_mb);
1507 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
1508 
1509 	if (xa->smb_msrcnt < n_setup ||
1510 	    xa->smb_mprcnt < n_param ||
1511 	    xa->smb_mdrcnt < n_data) {
1512 		goto trans_err_too_small;
1513 	}
1514 
1515 	/* neato, blast it over there */
1516 
1517 	n_setup = (n_setup + 1) / 2;		/* Convert to setup words */
1518 	param_pad = 1;				/* always one */
1519 	param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
1520 	data_pad = (param_off + n_param) & 1;	/* Pad to short */
1521 	/* Param off from hdr start */
1522 	data_off = param_off + n_param + data_pad;
1523 	total_bytes = param_pad + n_param + data_pad + n_data;
1524 
1525 	rc = smbsr_encode_result(sr, 10+n_setup, total_bytes,
1526 	    "bww2.wwwwwwb.Cw#.C#.C",
1527 	    10 + n_setup,		/* wct */
1528 	    n_param,			/* Total Parameter Bytes */
1529 	    n_data,			/* Total Data Bytes */
1530 	    n_param,			/* Total Parameter Bytes this buffer */
1531 	    param_off,			/* Param offset from header start */
1532 	    0,				/* Param displacement */
1533 	    n_data,			/* Total Data Bytes this buffer */
1534 	    data_off,			/* Data offset from header start */
1535 	    0,				/* Data displacement */
1536 	    n_setup,			/* suwcnt */
1537 	    &xa->rep_setup_mb, /* setup[] */
1538 	    total_bytes,		/* Total data bytes */
1539 	    param_pad,
1540 	    &xa->rep_param_mb,
1541 	    data_pad,
1542 	    &xa->rep_data_mb);
1543 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1544 
1545 trans_err_too_small:
1546 	rc = NERR_BufTooSmall;
1547 	goto trans_err;
1548 
1549 trans_err_not_supported:
1550 	rc = ERROR_NOT_SUPPORTED;
1551 	goto trans_err;
1552 
1553 trans_err:
1554 	pos = MBC_LENGTH(&sr->reply) + 23;
1555 	rc = smbsr_encode_result(sr, 10, 4, "bww2.wwwwwwb.www",
1556 	    10,		/* wct */
1557 	    4, 0,	/* tpscnt tdscnt */
1558 	    4, pos, 0,	/* pscnt psoff psdisp */
1559 	    0, 0, 0,	/* dscnt dsoff dsdisp */
1560 	    0,		/* suwcnt */
1561 	    4,		/* bcc */
1562 	    rc,
1563 	    0);		/* converter word? */
1564 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1565 }
1566 
1567 static smb_sdrc_t
1568 smb_trans2_dispatch(smb_request_t *sr, smb_xa_t *xa)
1569 {
1570 	int		rc, pos;
1571 	int		total_bytes, n_setup, n_param, n_data;
1572 	int		param_off, param_pad, data_off, data_pad;
1573 	uint16_t	opcode;
1574 	uint16_t  nt_unknown_secret = 0x0100;
1575 	char *fmt;
1576 
1577 	n_data = xa->smb_mdrcnt;
1578 
1579 	if (smb_mbc_decodef(&xa->req_setup_mb, "w", &opcode) != 0)
1580 		goto trans_err_not_supported;
1581 
1582 	/*
1583 	 * Save this for /proc to read later.
1584 	 */
1585 	xa->smb_func = opcode;
1586 
1587 	/* for now, only respond to the */
1588 	switch (opcode) {
1589 	case TRANS2_OPEN2:
1590 		rc = smb_com_trans2_open2(sr, xa);
1591 		break;
1592 
1593 	case TRANS2_CREATE_DIRECTORY:
1594 		rc = smb_com_trans2_create_directory(sr, xa);
1595 		break;
1596 
1597 	case TRANS2_FIND_FIRST2:
1598 		/*
1599 		 * Should have enough room to send the response
1600 		 * data back to client.
1601 		 */
1602 		if (n_data == 0) {
1603 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1604 			    ERRDOS, ERROR_BAD_LENGTH);
1605 			return (SDRC_ERROR);
1606 		}
1607 		rc = smb_com_trans2_find_first2(sr, xa);
1608 		break;
1609 
1610 	case TRANS2_FIND_NEXT2:
1611 		/*
1612 		 * Should have enough room to send the response
1613 		 * data back to client.
1614 		 */
1615 		if (n_data == 0) {
1616 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1617 			    ERRDOS, ERROR_BAD_LENGTH);
1618 			return (SDRC_ERROR);
1619 		}
1620 		rc = smb_com_trans2_find_next2(sr, xa);
1621 		break;
1622 
1623 	case TRANS2_QUERY_FS_INFORMATION:
1624 		/*
1625 		 * Should have enough room to send the response
1626 		 * data back to client.
1627 		 */
1628 		if (n_data == 0) {
1629 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1630 			    ERRDOS, ERROR_BAD_LENGTH);
1631 			return (SDRC_ERROR);
1632 		}
1633 		rc = smb_com_trans2_query_fs_information(sr, xa);
1634 		break;
1635 
1636 	case TRANS2_SET_FS_INFORMATION:
1637 		rc = smb_com_trans2_set_fs_information(sr, xa);
1638 		break;
1639 
1640 	case TRANS2_QUERY_PATH_INFORMATION:
1641 		/*
1642 		 * Should have enough room to send the response
1643 		 * data back to client.
1644 		 */
1645 		if (n_data == 0) {
1646 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1647 			    ERRDOS, ERROR_BAD_LENGTH);
1648 			return (SDRC_ERROR);
1649 		}
1650 		rc = smb_com_trans2_query_path_information(sr, xa);
1651 		break;
1652 
1653 	case TRANS2_QUERY_FILE_INFORMATION:
1654 		/*
1655 		 * Should have enough room to send the response
1656 		 * data back to client.
1657 		 */
1658 		if (n_data == 0) {
1659 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1660 			    ERRDOS, ERROR_BAD_LENGTH);
1661 			return (SDRC_ERROR);
1662 		}
1663 		rc = smb_com_trans2_query_file_information(sr, xa);
1664 		break;
1665 
1666 	case TRANS2_SET_PATH_INFORMATION:
1667 		rc = smb_com_trans2_set_path_information(sr, xa);
1668 		break;
1669 
1670 	case TRANS2_SET_FILE_INFORMATION:
1671 		rc = smb_com_trans2_set_file_information(sr, xa);
1672 		break;
1673 
1674 	case TRANS2_GET_DFS_REFERRAL:
1675 		rc = smb_com_trans2_get_dfs_referral(sr, xa);
1676 		break;
1677 
1678 	default:
1679 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
1680 		goto trans_err_not_supported;
1681 	}
1682 
1683 	switch (rc) {
1684 	case SDRC_SUCCESS:
1685 		break;
1686 
1687 	case SDRC_DROP_VC:
1688 	case SDRC_NO_REPLY:
1689 	case SDRC_ERROR:
1690 		return (rc);
1691 
1692 	case SDRC_NOT_IMPLEMENTED:
1693 		goto trans_err_not_supported;
1694 
1695 	default:
1696 		break;
1697 	}
1698 
1699 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
1700 	n_param = MBC_LENGTH(&xa->rep_param_mb);
1701 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
1702 
1703 	if (xa->smb_msrcnt < n_setup ||
1704 	    xa->smb_mprcnt < n_param ||
1705 	    xa->smb_mdrcnt < n_data) {
1706 		goto trans_err_too_small;
1707 	}
1708 
1709 	/* neato, blast it over there */
1710 
1711 	n_setup = (n_setup + 1) / 2;		/* Conver to setup words */
1712 	param_pad = 1;				/* must be one */
1713 	param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
1714 
1715 	/*
1716 	 * Including the nt_unknown_secret value persuades netmon to
1717 	 * display the correct data format for QueryPathInfo and
1718 	 * QueryFileInfo.
1719 	 */
1720 	if (opcode == TRANS2_QUERY_FILE_INFORMATION ||
1721 	    opcode == TRANS2_QUERY_PATH_INFORMATION) {
1722 		data_pad = sizeof (uint16_t);
1723 		data_off = param_off + n_param + data_pad;
1724 		fmt = "bww2.wwwwwwb.Cw#.CwC";
1725 		nt_unknown_secret = 0x0100;
1726 	}
1727 	else
1728 	{
1729 		data_pad = (param_off + n_param) & 1; /* Pad to short */
1730 		/* Param off from hdr start */
1731 		data_off = param_off + n_param + data_pad;
1732 		fmt = "bww2.wwwwwwb.Cw#.C#.C";
1733 		/*LINTED E_ASSIGN_NARROW_CONV*/
1734 		nt_unknown_secret = data_pad;
1735 	}
1736 
1737 	total_bytes = param_pad + n_param + data_pad + n_data;
1738 
1739 	rc = smbsr_encode_result(sr, 10+n_setup, total_bytes,
1740 	    fmt,
1741 	    10 + n_setup,		/* wct */
1742 	    n_param,			/* Total Parameter Bytes */
1743 	    n_data /* + data_pad */,	/* Total Data Bytes */
1744 	    n_param,			/* Total Parameter Bytes this buffer */
1745 	    param_off,			/* Param offset from header start */
1746 	    0,				/* Param displacement */
1747 	    n_data /* + data_pad */,	/* Total Data Bytes this buffer */
1748 	    data_off,			/* Data offset from header start */
1749 	    0,				/* Data displacement */
1750 	    n_setup,			/* suwcnt */
1751 	    &xa->rep_setup_mb,		/* setup[] */
1752 	    total_bytes,		/* Total data bytes */
1753 	    param_pad,
1754 	    &xa->rep_param_mb,
1755 	    nt_unknown_secret,
1756 	    &xa->rep_data_mb);
1757 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1758 
1759 trans_err_too_small:
1760 	rc = NERR_BufTooSmall;
1761 	goto trans_err;
1762 
1763 trans_err_not_supported:
1764 	rc = ERROR_NOT_SUPPORTED;
1765 	goto trans_err;
1766 
1767 trans_err:
1768 	pos = MBC_LENGTH(&sr->reply) + 23;
1769 	rc = smbsr_encode_result(sr, 10, 4, "bww2.wwwwwwb.www",
1770 	    10,		/* wct */
1771 	    4, 0,	/* tpscnt tdscnt */
1772 	    4, pos, 0,	/* pscnt psoff psdisp */
1773 	    0, 0, 0,	/* dscnt dsoff dsdisp */
1774 	    0,		/* suwcnt */
1775 	    4,		/* bcc */
1776 	    rc,
1777 	    0);		/* converter word? */
1778 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1779 }
1780 
1781 static uint32_t smb_xa_max_setup_count = 200;
1782 static uint32_t smb_xa_max_param_count = 32 * 1024;
1783 static uint32_t smb_xa_max_data_count  = 64 * 1024;
1784 
1785 smb_xa_t *
1786 smb_xa_create(
1787     smb_session_t	*session,
1788     smb_request_t	*sr,
1789     uint32_t		total_parameter_count,
1790     uint32_t		total_data_count,
1791     uint32_t		max_parameter_count,
1792     uint32_t		max_data_count,
1793     uint32_t		max_setup_count,
1794     uint32_t		setup_word_count)
1795 {
1796 	smb_xa_t	*xa, *nxa;
1797 	smb_llist_t	*xlist;
1798 
1799 	/*
1800 	 * Sanity check what the client says it will send.
1801 	 * Caller handles NULL return as ERRnoroom.
1802 	 */
1803 	if (setup_word_count > smb_xa_max_setup_count)
1804 		return (NULL);
1805 	if (total_parameter_count > smb_xa_max_param_count)
1806 		return (NULL);
1807 	if (total_data_count > smb_xa_max_data_count)
1808 		return (NULL);
1809 
1810 	/*
1811 	 * Limit what the client asks us to allocate for
1812 	 * returned setup, params, data.
1813 	 */
1814 	if (max_setup_count > smb_xa_max_setup_count)
1815 		max_setup_count = smb_xa_max_setup_count;
1816 	if (max_parameter_count > smb_xa_max_param_count)
1817 		max_parameter_count = smb_xa_max_param_count;
1818 	if (max_data_count > smb_xa_max_data_count)
1819 		max_data_count = smb_xa_max_data_count;
1820 
1821 	xa = kmem_zalloc(sizeof (smb_xa_t), KM_SLEEP);
1822 	xa->xa_refcnt = 1;
1823 	xa->smb_com = sr->smb_com;
1824 	xa->smb_flg = sr->smb_flg;
1825 	xa->smb_flg2 = sr->smb_flg2;
1826 	xa->smb_tid = sr->smb_tid;
1827 	xa->smb_pid = sr->smb_pid;
1828 	xa->smb_uid = sr->smb_uid;
1829 	xa->xa_smb_mid = sr->smb_mid;
1830 	xa->xa_smb_fid = 0xFFFF;
1831 	xa->reply_seqnum = sr->reply_seqnum;
1832 	xa->smb_tpscnt = total_parameter_count;
1833 	xa->smb_tdscnt = total_data_count;
1834 	xa->smb_mprcnt = max_parameter_count;
1835 	xa->smb_mdrcnt = max_data_count;
1836 	xa->smb_msrcnt = max_setup_count;
1837 	xa->smb_suwcnt = setup_word_count;
1838 	xa->xa_session = session;
1839 	xa->xa_magic = SMB_XA_MAGIC;
1840 
1841 	/* request parts */
1842 	xa->req_setup_mb.max_bytes = setup_word_count * 2;
1843 	xa->req_param_mb.max_bytes = total_parameter_count;
1844 	xa->req_data_mb.max_bytes  = total_data_count;
1845 
1846 	/* reply parts */
1847 	xa->rep_setup_mb.max_bytes = max_setup_count * 2;
1848 	xa->rep_param_mb.max_bytes = max_parameter_count;
1849 	xa->rep_data_mb.max_bytes =  max_data_count;
1850 
1851 	/*
1852 	 * The new xa structure is checked against the current list to see
1853 	 * if it exists already.
1854 	 */
1855 	xlist = &session->s_xa_list;
1856 	smb_llist_enter(xlist, RW_WRITER);
1857 	nxa = smb_llist_head(xlist);
1858 	while (nxa) {
1859 		ASSERT(nxa->xa_magic == SMB_XA_MAGIC);
1860 		if (nxa->xa_smb_mid == xa->xa_smb_mid &&
1861 		    nxa->smb_pid == xa->smb_pid &&
1862 		    !SMB_XA_CLOSED(nxa) &&
1863 		    !(nxa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
1864 			smb_llist_exit(xlist);
1865 			kmem_free(xa, sizeof (smb_xa_t));
1866 			return (NULL);
1867 		}
1868 		nxa = smb_llist_next(xlist, nxa);
1869 	}
1870 	smb_llist_insert_tail(xlist, xa);
1871 	smb_llist_exit(xlist);
1872 	return (xa);
1873 }
1874 
1875 void
1876 smb_xa_delete(smb_xa_t *xa)
1877 {
1878 	ASSERT(xa->xa_refcnt == 0);
1879 	ASSERT(SMB_XA_CLOSED(xa));
1880 
1881 	if (xa->xa_pipe_name)
1882 		smb_mem_free(xa->xa_pipe_name);
1883 
1884 	/* request parts */
1885 	if (xa->req_setup_mb.chain != NULL)
1886 		m_freem(xa->req_setup_mb.chain);
1887 	if (xa->req_param_mb.chain != NULL)
1888 		m_freem(xa->req_param_mb.chain);
1889 	if (xa->req_data_mb.chain != NULL)
1890 		m_freem(xa->req_data_mb.chain);
1891 
1892 	/* reply parts */
1893 	if (xa->rep_setup_mb.chain != NULL)
1894 		m_freem(xa->rep_setup_mb.chain);
1895 	if (xa->rep_param_mb.chain != NULL)
1896 		m_freem(xa->rep_param_mb.chain);
1897 	if (xa->rep_data_mb.chain != NULL)
1898 		m_freem(xa->rep_data_mb.chain);
1899 
1900 	xa->xa_magic = (uint32_t)~SMB_XA_MAGIC;
1901 	kmem_free(xa, sizeof (smb_xa_t));
1902 }
1903 
1904 smb_xa_t *
1905 smb_xa_hold(smb_xa_t *xa)
1906 {
1907 	mutex_enter(&xa->xa_mutex);
1908 	xa->xa_refcnt++;
1909 	ASSERT(xa->xa_refcnt);
1910 	mutex_exit(&xa->xa_mutex);
1911 	return (xa);
1912 }
1913 
1914 void
1915 smb_xa_rele(smb_session_t *session, smb_xa_t *xa)
1916 {
1917 	mutex_enter(&xa->xa_mutex);
1918 	ASSERT(xa->xa_refcnt);
1919 	xa->xa_refcnt--;
1920 	if (SMB_XA_CLOSED(xa) && (xa->xa_refcnt == 0)) {
1921 		mutex_exit(&xa->xa_mutex);
1922 		smb_llist_enter(&session->s_xa_list, RW_WRITER);
1923 		smb_llist_remove(&session->s_xa_list, xa);
1924 		smb_llist_exit(&session->s_xa_list);
1925 		smb_xa_delete(xa);
1926 		return;
1927 	}
1928 	mutex_exit(&xa->xa_mutex);
1929 }
1930 
1931 int
1932 smb_xa_open(smb_xa_t *xa)
1933 {
1934 	int rc;
1935 
1936 	mutex_enter(&xa->xa_mutex);
1937 
1938 	ASSERT((xa->xa_flags & SMB_XA_FLAG_OPEN) == 0);
1939 
1940 	if ((xa->xa_flags & SMB_XA_FLAG_CLOSE) == 0) {
1941 		xa->xa_flags |= SMB_XA_FLAG_OPEN;
1942 		rc = 0;
1943 	} else {
1944 		rc = ERROR_INVALID_HANDLE;
1945 	}
1946 
1947 	mutex_exit(&xa->xa_mutex);
1948 
1949 	return (rc);
1950 }
1951 
1952 void
1953 smb_xa_close(smb_xa_t *xa)
1954 {
1955 	mutex_enter(&xa->xa_mutex);
1956 	xa->xa_flags |= SMB_XA_FLAG_CLOSE;
1957 	xa->xa_flags &= ~SMB_XA_FLAG_OPEN;
1958 
1959 	if (xa->xa_refcnt == 0) {
1960 		mutex_exit(&xa->xa_mutex);
1961 		smb_llist_enter(&xa->xa_session->s_xa_list, RW_WRITER);
1962 		smb_llist_remove(&xa->xa_session->s_xa_list, xa);
1963 		smb_llist_exit(&xa->xa_session->s_xa_list);
1964 		smb_xa_delete(xa);
1965 		return;
1966 	}
1967 
1968 	mutex_exit(&xa->xa_mutex);
1969 }
1970 
1971 int
1972 smb_xa_complete(smb_xa_t *xa)
1973 {
1974 	int rc;
1975 
1976 	mutex_enter(&xa->xa_mutex);
1977 	if (xa->xa_flags & (SMB_XA_FLAG_COMPLETE | SMB_XA_FLAG_CLOSE)) {
1978 		rc = 0; /* error ("not complete") */
1979 	} else {
1980 		rc = 1; /* Yes, "complete" */
1981 		xa->xa_flags |= SMB_XA_FLAG_COMPLETE;
1982 
1983 		/*
1984 		 * During trans & trans-secondary processing,
1985 		 * we copied the request data into these.
1986 		 * Now we want to parse them, so we need to
1987 		 * move the "finger" back to the beginning.
1988 		 */
1989 		xa->req_setup_mb.chain_offset = 0;
1990 		xa->req_param_mb.chain_offset = 0;
1991 		xa->req_data_mb.chain_offset  = 0;
1992 	}
1993 
1994 	mutex_exit(&xa->xa_mutex);
1995 	return (rc);
1996 }
1997 
1998 smb_xa_t *
1999 smb_xa_find(
2000     smb_session_t	*session,
2001     uint16_t		pid,
2002     uint16_t		mid)
2003 {
2004 	smb_xa_t	*xa;
2005 	smb_llist_t	*xlist;
2006 
2007 	xlist = &session->s_xa_list;
2008 	smb_llist_enter(xlist, RW_READER);
2009 	xa = smb_llist_head(xlist);
2010 	while (xa) {
2011 		mutex_enter(&xa->xa_mutex);
2012 		if (xa->xa_smb_mid == mid &&
2013 		    xa->smb_pid == pid &&
2014 		    !SMB_XA_CLOSED(xa) &&
2015 		    !(xa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
2016 			xa->xa_refcnt++;
2017 			ASSERT(xa->xa_refcnt);
2018 			mutex_exit(&xa->xa_mutex);
2019 			break;
2020 		}
2021 		mutex_exit(&xa->xa_mutex);
2022 		xa = smb_llist_next(xlist, xa);
2023 	}
2024 	smb_llist_exit(xlist);
2025 	return (xa);
2026 }
2027