xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_common_transact.c (revision d321a33cdd896e6b211d113a33698dd76e89b861)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <smbsrv/smb_incl.h>
30 #include <smbsrv/smb_fsops.h>
31 #include <smbsrv/oem.h>
32 #include <smbsrv/nmpipes.h>
33 #include <smbsrv/mailslot.h>
34 #include <smbsrv/lmerr.h>
35 #include <smbsrv/nterror.h>
36 
37 extern int smb_maxbufsize;
38 
39 #define	MAX_SHARE_NAME_LEN	13
40 #define	SHARE_INFO_1_SIZE	(MAX_SHARE_NAME_LEN + sizeof (char) + \
41     sizeof (short) + sizeof (uint32_t))
42 
43 /*
44  * count of bytes in server response packet
45  * except parameters and data. Note that setup
46  * word count is zero.
47  */
48 #define	RESP_HEADER_LEN		24
49 
50 /*
51  * NB. I started by using common functions for transaction/transaction2
52  * and transaction_secondary/transaction2_secondary because they
53  * are respectively so similar. However, it turned out to be a bad
54  * idea because of quirky differences. Be sure if you modify one
55  * of these four functions to check and see if the modification should
56  * be applied to its peer.
57  */
58 
59 int smb_trans_ready(struct smb_xa *xa);
60 int smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa);
61 int smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa);
62 int smb_trans2_find(struct smb_request *sr, struct smb_xa *xa, int opcode);
63 int smb_trans2_query_fs_info(struct smb_request *sr, struct smb_xa *xa);
64 
65 
66 int smb_nt_transact_query_quota(struct smb_request *sr, struct smb_xa *xa);
67 
68 int
69 smb_com_transaction(struct smb_request *sr)
70 {
71 	int		rc;
72 	unsigned char	msrcnt, suwcnt;
73 	uint16_t	tpscnt, tdscnt, mprcnt, mdrcnt, flags;
74 	uint16_t	pscnt, psoff, dscnt, dsoff;
75 	uint32_t	timeo;
76 	struct smb_xa *xa;
77 	char *stn;
78 	int ready;
79 
80 	rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT,
81 	    &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &msrcnt, &flags,
82 	    &timeo, &pscnt, &psoff, &dscnt, &dsoff, &suwcnt);
83 
84 	if (rc != 0) {
85 		smbsr_decode_error(sr);
86 		/* NOTREACHED */
87 	}
88 
89 	xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
90 	    msrcnt, suwcnt);
91 	if (xa == NULL) {
92 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
93 		/* NOTREACHED */
94 	}
95 
96 	/* Should be some alignment stuff here in SMB? */
97 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) {
98 		rc = smbsr_decode_data(sr, "%.U", sr, &stn);
99 	} else {
100 		rc = smbsr_decode_data(sr, "%s", sr,  &stn);
101 	}
102 	if (rc != 0) {
103 		smb_xa_rele(sr->session, xa);
104 		smbsr_decode_error(sr);
105 		/* NOTREACHED */
106 	}
107 	xa->xa_smb_trans_name = MEM_STRDUP("smb", stn);
108 
109 	xa->smb_flags  = flags;
110 	xa->smb_timeout = timeo;
111 	xa->req_disp_param = pscnt;
112 	xa->req_disp_data  = dscnt;
113 
114 	if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
115 	    sr->smb_vwv.chain_offset, suwcnt * 2)) {
116 		smb_xa_rele(sr->session, xa);
117 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
118 		/* NOTREACHED */
119 	}
120 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
121 		smb_xa_rele(sr->session, xa);
122 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
123 		/* NOTREACHED */
124 	}
125 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
126 		smb_xa_rele(sr->session, xa);
127 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
128 		/* NOTREACHED */
129 	}
130 
131 	ready = smb_trans_ready(xa);
132 
133 	if (smb_xa_open(xa)) {
134 		smb_xa_rele(sr->session, xa);
135 		smbsr_error(sr, 0, ERRDOS, ERRsrverror);
136 		/* NOTREACHED */
137 	}
138 	sr->r_xa = xa;
139 
140 	if (!ready) {
141 		smbsr_encode_empty_result(sr);
142 		return (SDRC_NORMAL_REPLY);
143 	}
144 
145 	if (!smb_xa_complete(xa)) {
146 		smb_xa_close(xa);
147 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
148 		/* NOTREACHED */
149 	}
150 
151 	return (smb_trans_dispatch(sr, xa));
152 }
153 
154 
155 int
156 smb_com_transaction_secondary(struct smb_request *sr)
157 {
158 	uint16_t tpscnt, tdscnt, pscnt, psdisp;
159 	uint16_t dscnt, dsoff, dsdisp, psoff;
160 	smb_xa_t *xa;
161 	int rc;
162 
163 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
164 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
165 		/* NOTREACHED */
166 	}
167 
168 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
169 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
170 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
171 			    ERRDOS, ERRnoaccess);
172 			/* NOTREACHED */
173 		}
174 	}
175 
176 	if (xa->smb_com != SMB_COM_TRANSACTION) {
177 		return (SDRC_DROP_VC);
178 	}
179 
180 	rc = smbsr_decode_vwv(sr, SMB_TRANSSHDR_ED_FMT, &tpscnt, &tdscnt,
181 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp);
182 
183 	if (rc != 0) {
184 		smbsr_decode_error(sr);
185 		/* NOTREACHED */
186 	}
187 
188 	mutex_enter(&xa->xa_mutex);
189 	xa->smb_tpscnt = tpscnt;	/* might have shrunk */
190 	xa->smb_tdscnt = tdscnt;	/* might have shrunk */
191 	xa->req_disp_param = psdisp+pscnt;
192 	xa->req_disp_data  = dsdisp+dscnt;
193 
194 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
195 		mutex_exit(&xa->xa_mutex);
196 		smb_xa_close(xa);
197 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
198 		/* NOTREACHED */
199 	}
200 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
201 		mutex_exit(&xa->xa_mutex);
202 		smb_xa_close(xa);
203 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
204 		/* NOTREACHED */
205 	}
206 	mutex_exit(&xa->xa_mutex);
207 
208 	if (!smb_trans_ready(xa))
209 		return (SDRC_NO_REPLY);
210 
211 	if (!smb_xa_complete(xa))
212 		return (SDRC_NO_REPLY);
213 
214 	return (smb_trans_dispatch(sr, xa));
215 }
216 
217 
218 int
219 smb_com_ioctl(struct smb_request *sr)
220 {
221 	uint16_t fid, category, function, tpscnt, tdscnt, mprcnt;
222 	uint16_t mdrcnt, pscnt, pdoff, dscnt, dsoff;
223 	uint32_t timeout;
224 	int rc;
225 
226 	rc = smbsr_decode_vwv(sr, "wwwwwwwl2.wwww", &fid, &category, &function,
227 	    &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &timeout, &pscnt,
228 	    &pdoff, &dscnt, &dsoff);
229 
230 	if (rc != 0) {
231 		smbsr_decode_error(sr);
232 		/* NOTREACHED */
233 	}
234 
235 	return (SDRC_UNIMPLEMENTED);
236 }
237 
238 
239 int /*ARGSUSED*/
240 smb_com_ioctl_secondary(struct smb_request *sr)
241 {
242 	return (SDRC_UNIMPLEMENTED);
243 }
244 
245 
246 int
247 smb_com_transaction2(struct smb_request *sr)
248 {
249 	unsigned char	msrcnt, suwcnt;
250 	uint16_t	tpscnt, tdscnt, mprcnt, mdrcnt, flags;
251 	uint16_t	pscnt, psoff, dscnt, dsoff;
252 	uint32_t	timeo;
253 	smb_xa_t *xa;
254 	int ready;
255 	int rc;
256 
257 	rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT, &tpscnt, &tdscnt,
258 	    &mprcnt, &mdrcnt, &msrcnt, &flags, &timeo, &pscnt, &psoff, &dscnt,
259 	    &dsoff, &suwcnt);
260 
261 	if (rc != 0) {
262 		smbsr_decode_error(sr);
263 		/* NOTREACHED */
264 	}
265 
266 	xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
267 	    msrcnt, suwcnt);
268 	if (xa == 0) {
269 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
270 		/* NOTREACHED */
271 	}
272 
273 	xa->smb_flags  = flags;
274 	xa->smb_timeout = timeo;
275 	xa->req_disp_param = pscnt;
276 	xa->req_disp_data  = dscnt;
277 
278 	if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
279 	    sr->smb_vwv.chain_offset, suwcnt*2)) {
280 		smb_xa_rele(sr->session, xa);
281 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
282 		/* NOTREACHED */
283 	}
284 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
285 		smb_xa_rele(sr->session, xa);
286 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
287 		/* NOTREACHED */
288 	}
289 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
290 		smb_xa_rele(sr->session, xa);
291 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
292 		/* NOTREACHED */
293 	}
294 
295 	ready = smb_trans_ready(xa);
296 
297 	if (smb_xa_open(xa)) {
298 		smb_xa_rele(sr->session, xa);
299 		smbsr_error(sr, 0, ERRDOS, ERRsrverror);
300 		/* NOTREACHED */
301 	}
302 	sr->r_xa = xa;
303 
304 	if (!ready) {
305 		smbsr_encode_empty_result(sr);
306 		return (SDRC_NORMAL_REPLY);
307 	}
308 
309 	if (!smb_xa_complete(xa)) {
310 		smb_xa_close(xa);
311 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
312 		/* NOTREACHED */
313 	}
314 
315 	return (smb_trans2_dispatch(sr, xa));
316 }
317 
318 
319 int
320 smb_com_transaction2_secondary(struct smb_request *sr)
321 {
322 	uint16_t tpscnt, tdscnt, fid;
323 	uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
324 	smb_xa_t *xa;
325 	int rc;
326 
327 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
328 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
329 		/* NOTREACHED */
330 	}
331 
332 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
333 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
334 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
335 			    ERRDOS, ERRnoaccess);
336 			/* NOTREACHED */
337 		}
338 	}
339 
340 	if (xa->smb_com != SMB_COM_TRANSACTION2) {
341 		return (SDRC_DROP_VC);
342 	}
343 
344 	rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
345 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
346 
347 	if (rc != 0) {
348 		smbsr_decode_error(sr);
349 		/* NOTREACHED */
350 	}
351 
352 	mutex_enter(&xa->xa_mutex);
353 	xa->smb_tpscnt = tpscnt;	/* might have shrunk */
354 	xa->smb_tdscnt = tdscnt;	/* might have shrunk */
355 	xa->xa_smb_fid = fid;		/* overwrite rules? */
356 	xa->req_disp_param = psdisp + pscnt;
357 	xa->req_disp_data  = dsdisp + dscnt;
358 
359 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
360 		mutex_exit(&xa->xa_mutex);
361 		smb_xa_close(xa);
362 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
363 		/* NOTREACHED */
364 	}
365 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
366 		mutex_exit(&xa->xa_mutex);
367 		smb_xa_close(xa);
368 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
369 		/* NOTREACHED */
370 	}
371 	mutex_exit(&xa->xa_mutex);
372 
373 	if (!smb_trans_ready(xa))
374 		return (SDRC_NO_REPLY);
375 
376 	if (!smb_xa_complete(xa))
377 		return (SDRC_NO_REPLY);
378 
379 	return (smb_trans2_dispatch(sr, xa));
380 }
381 
382 static int
383 smb_nt_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
384 {
385 	int rc;
386 	int total_bytes, n_setup, n_param, n_data;
387 	int param_off, param_pad, data_off, data_pad;
388 
389 	n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
390 	n_setup++;
391 	n_setup = n_setup & ~0x0001;
392 	n_param = (xa->smb_mprcnt < smb_maxbufsize)
393 	    ? xa->smb_mprcnt : smb_maxbufsize;
394 	n_param++;
395 	n_param = n_param & ~0x0001;
396 	rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
397 	n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
398 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
399 	MBC_INIT(&xa->rep_param_mb, n_param);
400 	MBC_INIT(&xa->rep_data_mb, n_data);
401 
402 	switch (xa->smb_func) {
403 	case NT_TRANSACT_CREATE:
404 		rc = smb_nt_transact_create(sr, xa);
405 		break;
406 	case NT_TRANSACT_NOTIFY_CHANGE:
407 		rc = smb_nt_transact_notify_change(sr, xa);
408 		break;
409 	case NT_TRANSACT_QUERY_SECURITY_DESC:
410 		rc = smb_nt_transact_query_security_info(sr, xa);
411 		break;
412 	case NT_TRANSACT_SET_SECURITY_DESC:
413 		rc = smb_nt_transact_set_security_info(sr, xa);
414 		break;
415 	case NT_TRANSACT_IOCTL:
416 		rc = smb_nt_transact_ioctl(sr, xa);
417 		break;
418 
419 	case NT_TRANSACT_QUERY_QUOTA:
420 		(void) smb_nt_transact_query_quota(sr, xa);
421 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
422 		/* NOTREACHED */
423 
424 	case NT_TRANSACT_SET_QUOTA:
425 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
426 		/* NOTREACHED */
427 
428 	default:
429 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
430 		/* NOTREACHED */
431 	}
432 
433 	switch (rc) {
434 	case SDRC_NORMAL_REPLY:
435 		break;
436 
437 	case SDRC_DROP_VC:
438 	case SDRC_NO_REPLY:
439 	case SDRC_ERROR_REPLY:
440 		return (rc);
441 
442 	case SDRC_UNIMPLEMENTED:
443 	case SDRC_UNSUPPORTED:
444 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
445 		/* NOTREACHED */
446 
447 	default:
448 		break;
449 	}
450 
451 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
452 	n_param = MBC_LENGTH(&xa->rep_param_mb);
453 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
454 
455 	if (xa->smb_msrcnt < n_setup ||
456 	    xa->smb_mprcnt < n_param ||
457 	    xa->smb_mdrcnt < n_data) {
458 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
459 		/* NOTREACHED */
460 	}
461 
462 	/* neato, blast it over there */
463 
464 	n_setup = (n_setup + 1) / 2;		/* Conver to setup words */
465 	param_pad = 1;				/* must be one */
466 	param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
467 	data_pad = (4 - ((param_off + n_param) & 3)) % 4; /* Pad to 4 byte */
468 	data_off = param_off + n_param + data_pad; /* Param off from hdr */
469 	total_bytes = param_pad + n_param + data_pad + n_data;
470 
471 	smbsr_encode_result(sr, 18+n_setup, total_bytes,
472 	    "b 3. llllllllb C w #. C #. C",
473 	    18 + n_setup,		/* wct */
474 	    n_param,			/* Total Parameter Bytes */
475 	    n_data,			/* Total Data Bytes */
476 	    n_param,			/* Total Parameter Bytes this buffer */
477 	    param_off,			/* Param offset from header start */
478 	    0,				/* Param displacement */
479 	    n_data,			/* Total Data Bytes this buffer */
480 	    data_off,			/* Data offset from header start */
481 	    0,				/* Data displacement */
482 	    n_setup,			/* suwcnt */
483 	    &xa->rep_setup_mb,		/* setup[] */
484 	    total_bytes,		/* Total data bytes */
485 	    param_pad,
486 	    &xa->rep_param_mb,
487 	    data_pad,
488 	    &xa->rep_data_mb);
489 	return (SDRC_NORMAL_REPLY);
490 }
491 
492 
493 /*
494  * smb_nt_transact_query_quota
495  *
496  * Stub to help debunk this function. There are 16 parameter bytes. The
497  * first parameter is definitely the fid. The second looks like a flags
498  * field. Then there are 12 bytes (probably 3 dwords) - all zero.
499  */
500 int
501 smb_nt_transact_query_quota(struct smb_request *sr, struct smb_xa *xa)
502 {
503 	uint16_t fid;
504 	uint16_t flags;
505 	int rc;
506 
507 	rc = smb_decode_mbc(&xa->req_param_mb, "%ww", sr, &fid, &flags);
508 	if (rc != 0) {
509 		smbsr_decode_error(sr);
510 		/* NOTREACHED */
511 	}
512 
513 	return (SDRC_NORMAL_REPLY);
514 }
515 
516 
517 int
518 smb_com_nt_transact(struct smb_request *sr)
519 {
520 	uint16_t	Function;
521 	unsigned char	MaxSetupCount, SetupCount;
522 	uint32_t	TotalParameterCount, TotalDataCount;
523 	uint32_t	MaxParameterCount, MaxDataCount, pscnt;
524 	uint32_t	psoff, dscnt, dsoff;
525 	smb_xa_t *xa;
526 	int ready;
527 	int rc;
528 
529 	rc = smbsr_decode_vwv(sr, SMB_NT_TRANSHDR_ED_FMT, &MaxSetupCount,
530 	    &TotalParameterCount, &TotalDataCount, &MaxParameterCount,
531 	    &MaxDataCount, &pscnt, &psoff, &dscnt,
532 	    &dsoff, &SetupCount, &Function);
533 
534 	if (rc != 0) {
535 		smbsr_decode_error(sr);
536 		/* NOTREACHED */
537 	}
538 
539 	xa = smb_xa_create(sr->session, sr, TotalParameterCount, TotalDataCount,
540 	    MaxParameterCount, MaxDataCount, MaxSetupCount, SetupCount);
541 	if (xa == 0) {
542 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
543 		/* NOTREACHED */
544 	}
545 
546 	xa->smb_flags  = 0;
547 	xa->smb_timeout = 0;
548 	xa->smb_func = Function;
549 	xa->req_disp_param = pscnt;
550 	xa->req_disp_data  = dscnt;
551 
552 	if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
553 	    sr->smb_vwv.chain_offset, SetupCount * 2)) {
554 		smb_xa_rele(sr->session, xa);
555 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
556 		/* NOTREACHED */
557 	}
558 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
559 		smb_xa_rele(sr->session, xa);
560 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
561 		/* NOTREACHED */
562 	}
563 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
564 		smb_xa_rele(sr->session, xa);
565 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
566 		/* NOTREACHED */
567 	}
568 
569 	ready = smb_trans_ready(xa);
570 
571 	if (smb_xa_open(xa)) {
572 		smb_xa_rele(sr->session, xa);
573 		smbsr_error(sr, 0, ERRDOS, ERRsrverror);
574 		/* NOTREACHED */
575 	}
576 	sr->r_xa = xa;
577 
578 	if (!ready) {
579 		smbsr_encode_empty_result(sr);
580 		return (SDRC_NORMAL_REPLY);
581 	}
582 
583 	if (!smb_xa_complete(xa)) {
584 		smb_xa_close(xa);
585 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
586 		/* NOTREACHED */
587 	}
588 
589 	return (smb_nt_trans_dispatch(sr, xa));
590 }
591 
592 
593 int
594 smb_com_nt_transact_secondary(struct smb_request *sr)
595 {
596 	uint16_t tpscnt, tdscnt, fid;
597 	uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
598 	smb_xa_t *xa;
599 	int rc;
600 
601 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
602 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
603 		/* NOTREACHED */
604 	}
605 
606 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
607 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
608 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
609 			    ERRDOS, ERRnoaccess);
610 			/* NOTREACHED */
611 		}
612 	}
613 
614 	if (xa->smb_com != SMB_COM_TRANSACTION2) {
615 		return (SDRC_DROP_VC);
616 	}
617 
618 	rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
619 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
620 
621 	if (rc != 0) {
622 		smbsr_decode_error(sr);
623 		/* NOTREACHED */
624 	}
625 
626 	mutex_enter(&xa->xa_mutex);
627 	xa->smb_tpscnt = tpscnt;	/* might have shrunk */
628 	xa->smb_tdscnt = tdscnt;	/* might have shrunk */
629 	xa->xa_smb_fid = fid;		/* overwrite rules? */
630 	xa->req_disp_param = psdisp+pscnt;
631 	xa->req_disp_data  = dsdisp+dscnt;
632 
633 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
634 		mutex_exit(&xa->xa_mutex);
635 		smb_xa_close(xa);
636 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
637 		/* NOTREACHED */
638 	}
639 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
640 		mutex_exit(&xa->xa_mutex);
641 		smb_xa_close(xa);
642 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
643 		/* NOTREACHED */
644 	}
645 	mutex_exit(&xa->xa_mutex);
646 
647 	if (!smb_trans_ready(xa))
648 		return (SDRC_NO_REPLY);
649 
650 	if (!smb_xa_complete(xa))
651 		return (SDRC_NO_REPLY);
652 
653 	return (smb_nt_trans_dispatch(sr, xa));
654 }
655 
656 int
657 smb_trans_ready(struct smb_xa *xa)
658 {
659 	int rc;
660 
661 	mutex_enter(&xa->xa_mutex);
662 	rc = xa->req_disp_data >= xa->smb_tdscnt &&
663 	    xa->req_disp_param >= xa->smb_tpscnt;
664 	mutex_exit(&xa->xa_mutex);
665 
666 	return (rc);
667 }
668 
669 
670 /*
671  * smb_emit_SHARE_INFO_0
672  *
673  * This function will convert unicode chars to oem chars before
674  * and store the result in a fixed length, MAX_SHARE_NAME_LEN, buffer. If the
675  * length after conversion is longer than 12, -1 will be reported
676  * to indicate an error. The fixed length is a limitation of the
677  * smb protocol.
678  */
679 static int
680 smb_emit_SHARE_INFO_0(struct mbuf_chain *output, unsigned char *name)
681 {
682 	mts_wchar_t *unibuf;
683 	char *tmpbuf;
684 	unsigned int cpid = oem_get_smb_cpid();
685 	unsigned int length;
686 	char	name_buf[MAX_SHARE_NAME_LEN];
687 
688 	if (name == 0)
689 		tmpbuf = "";
690 	else
691 		tmpbuf = (char *)name;
692 
693 	length = strlen(tmpbuf) + 1;
694 	unibuf = MEM_MALLOC("smb", length * sizeof (mts_wchar_t));
695 
696 	(void) mts_mbstowcs(unibuf, tmpbuf, length);
697 	tmpbuf = MEM_MALLOC("smb", length);
698 	if (unicodestooems(tmpbuf, unibuf, length, cpid) == 0)
699 		(void) strcpy(tmpbuf, (char *)name);
700 
701 	if (strlen(tmpbuf) + 1 > MAX_SHARE_NAME_LEN) {
702 		MEM_FREE("smb", unibuf);
703 		MEM_FREE("smb", tmpbuf);
704 		return (-1);
705 	}
706 
707 	bzero(name_buf, sizeof (name_buf));
708 	(void) strcpy(name_buf, tmpbuf);
709 	(void) smb_encode_mbc(output, "13c", name_buf);
710 
711 	MEM_FREE("smb", unibuf);
712 	MEM_FREE("smb", tmpbuf);
713 
714 	return (0);
715 }
716 
717 static int
718 smb_emit_SHARE_INFO_1(struct mbuf_chain *output, struct mbuf_chain *text,
719     unsigned char *name, uint16_t type,
720     unsigned char *comment)
721 {
722 	if (smb_emit_SHARE_INFO_0(output, name) < 0)
723 		return (-1);
724 
725 	(void) smb_encode_mbc(output, ".wl", type, MBC_LENGTH(text));
726 	(void) smb_encode_mbc(text, "s",
727 	    (comment ? comment : (unsigned char *)"No comment"));
728 	return (0);
729 }
730 
731 static void /*ARGSUSED*/
732 smb_emit_SHARE_INFO_2(struct mbuf_chain *output, struct mbuf_chain *text,
733 	struct smb_request *sr, unsigned char *name, uint16_t type,
734 	unsigned char *comment, uint16_t access, char *path, char *password)
735 {
736 	unsigned char	pword[9];
737 
738 	/*
739 	 * XXX PGD.  Is there a bug here?  We zero pword, copy password
740 	 * into pword then ignore it and use password for smb_encode_mbc?
741 	 */
742 	bzero(pword, sizeof (pword));
743 	(void) strncpy((char *)pword, password, sizeof (pword));
744 	(void) smb_emit_SHARE_INFO_1(output, text, name, type, comment);
745 	(void) smb_encode_mbc(output, "wwwl9c.",
746 	    access,
747 	    smb_info.si.skc_maxconnections,
748 	    smb_svcstate_session_count(&smb_info.si_svc_sm_ctx),
749 	    MBC_LENGTH(text),
750 	    password);
751 	(void) smb_encode_mbc(text, "s", path);
752 }
753 
754 /*
755  * is_long_sharename
756  *
757  * This function is extracted from smb_emit_SHARE_INFO_0 only for
758  * finding shares that their names are longer than MAX_SHARE_NAME_LEN.
759  *
760  * The function returns 1 for long share names and 0 when the length
761  * is Ok.
762  */
763 static int
764 is_long_sharename(unsigned char *name)
765 {
766 	mts_wchar_t *unibuf;
767 	char *tmpbuf;
768 	unsigned int cpid = oem_get_smb_cpid();
769 	unsigned int length;
770 
771 	if (name == 0)
772 		tmpbuf = "";
773 	else
774 		tmpbuf = (char *)name;
775 
776 	length = strlen(tmpbuf) + 1;
777 	unibuf = MEM_MALLOC("smb", length * sizeof (mts_wchar_t));
778 	(void) mts_mbstowcs(unibuf, tmpbuf, length);
779 	tmpbuf = MEM_MALLOC("smb", length);
780 	if (unicodestooems(tmpbuf, unibuf, length, cpid) == 0)
781 		(void) strcpy(tmpbuf, (char *)name);
782 
783 	if (strlen(tmpbuf) + 1 > MAX_SHARE_NAME_LEN) {
784 		MEM_FREE("smb", unibuf);
785 		MEM_FREE("smb", tmpbuf);
786 		return (1);
787 	}
788 
789 	MEM_FREE("smb", unibuf);
790 	MEM_FREE("smb", tmpbuf);
791 
792 	return (0);
793 }
794 
795 /*
796  * This structure holds information about shares which will
797  * fit in the specified client buffer size.
798  *
799  * sei_bufsize: Client specified buffer size
800  * sei_count: Maximum number of shares that can be
801  *            sent in the buffer.
802  *
803  * The return data section consists of a number of SHARE_INFO_1 structures.
804  * In case there are multiple SHARE_INFO_1 data structures to return this
805  * function put all fixed length part of these structures in the return buffer
806  * and then put all the variable length data (shares' comment) at the end of
807  * buffer.
808  *
809  * sei_info_len: Size of fixed length part of SHARE_INFO_1
810  *               structures for sei_count shares
811  * sei_cmnt_len: Size of comments for sei_count shares
812  */
813 typedef struct {
814 	uint16_t sei_bufsize;
815 	short sei_count;
816 	int   sei_infolen;
817 	int   sei_cmntlen;
818 } smb_share_enum_t;
819 
820 /*
821  * smb_share_update_info
822  *
823  * Check to see if the given buffer has enough
824  * room to fit the information of the given share.
825  * If there is enough room update the passed max_???
826  * information.
827  *
828  * Return 1 if buffer is not full yet, 0 if it's full.
829  */
830 static int
831 smb_share_update_info(lmshare_info_t *si, smb_share_enum_t *shr_enum_info)
832 {
833 	int cmnt_len;
834 	int new_info_len = shr_enum_info->sei_infolen;
835 	int new_cmnt_len = shr_enum_info->sei_cmntlen;
836 
837 	if (lmshrd_is_special(si->share_name))
838 		cmnt_len = 1;
839 	else
840 		cmnt_len = (strlen(si->comment) + 1);
841 
842 	new_info_len += SHARE_INFO_1_SIZE;
843 	new_cmnt_len += cmnt_len;
844 
845 	if ((new_info_len + new_cmnt_len) < shr_enum_info->sei_bufsize) {
846 		shr_enum_info->sei_count++;
847 		shr_enum_info->sei_infolen = new_info_len;
848 		shr_enum_info->sei_cmntlen = new_cmnt_len;
849 		return (1);
850 	}
851 
852 	return (0);
853 }
854 
855 /*
856  * smb_share_skip_share
857  *
858  * Determines whether the given share should be enumerated
859  * or not. The share will not be enumerated if its name is
860  * long or it's autohome share.
861  *
862  * Return 1 if the share should be skipped; otherwise returns
863  * 0
864  */
865 static int
866 smb_share_skip_share(lmshare_info_t *si)
867 {
868 	if (is_long_sharename((unsigned char *)si->share_name)) {
869 		return (1);
870 	}
871 
872 	/* Skip autohome share if autohome filter is enabled */
873 	if (si->mode == LMSHRM_TRANS) {
874 		return (1);
875 	}
876 
877 	return (0);
878 }
879 
880 /*
881  * smb_share_add_autohome
882  *
883  * Determines if an autohome share should be added to shares' list
884  * for the given user.
885  * Autohome will be add when all the following conditions are true:
886  *
887  *  1. Autohome feature is enabled
888  *  2. A share with the same name as the given user exists
889  *  3. The share is not a permanent share
890  *  4. Share name is not longer than maximum allowed
891  */
892 static int
893 smb_share_add_autohome(char *username, lmshare_info_t *si)
894 {
895 	int do_add = 0;
896 
897 	do_add = (lmshrd_getinfo(username, si) == NERR_Success) &&
898 	    (si->mode & LMSHRM_TRANS) &&
899 	    (is_long_sharename((unsigned char *)(si->share_name)) == 0);
900 
901 	return (do_add);
902 }
903 
904 /*
905  * smb_share_total_info
906  *
907  * This function calculates following informations
908  *	- Maximum number of shares that can be sent for clients
909  *	  according to its buffer size (cli_bufsize)
910  *	- length of fixed information about above shares
911  *	- length of comments of above shares
912  *	- total number of shares that their names are no longer
913  *	  than MAX_SHARE_NAME_LEN.
914  *
915  * Added SMB user object to the parameter list to filter out other
916  * user autohome shares.
917  */
918 static void
919 smb_share_total_info(smb_share_enum_t *shr_enum_info, short *tot_shares_num,
920     smb_user_t *user)
921 {
922 	uint64_t iterator;
923 	lmshare_info_t *si;
924 	struct lmshare_info *auto_si;
925 	int more_room = 1;
926 
927 	si = kmem_zalloc(sizeof (lmshare_info_t), KM_SLEEP);
928 	auto_si = kmem_zalloc(sizeof (struct lmshare_info), KM_SLEEP);
929 
930 	*tot_shares_num = 0;
931 	shr_enum_info->sei_count = 0;
932 	shr_enum_info->sei_infolen = 0;
933 	shr_enum_info->sei_cmntlen = 0;
934 
935 	if (smb_share_add_autohome(user->u_name, auto_si)) {
936 		(*tot_shares_num)++;
937 		more_room = smb_share_update_info(auto_si, shr_enum_info);
938 	}
939 
940 	iterator = lmshrd_open_iterator(LMSHRM_ALL);
941 	if (iterator == 0) {
942 		kmem_free(si, sizeof (lmshare_info_t));
943 		kmem_free(auto_si, sizeof (struct lmshare_info));
944 		return;
945 	}
946 
947 	/* check for door errors */
948 	if (lmshrd_iterate(iterator, si) != NERR_Success) {
949 		(void) lmshrd_close_iterator(iterator);
950 		kmem_free(si, sizeof (lmshare_info_t));
951 		kmem_free(auto_si, sizeof (struct lmshare_info));
952 		return;
953 	}
954 
955 	while (*si->share_name != 0) {
956 		if (smb_share_skip_share(si)) {
957 			/* check for door errors */
958 			if (lmshrd_iterate(iterator, si) != NERR_Success) {
959 				(void) lmshrd_close_iterator(iterator);
960 				kmem_free(si, sizeof (lmshare_info_t));
961 				kmem_free(auto_si,
962 				    sizeof (struct lmshare_info));
963 				return;
964 			}
965 			continue;
966 		}
967 
968 		(*tot_shares_num)++;
969 
970 		if (more_room) {
971 			more_room = smb_share_update_info(si, shr_enum_info);
972 		}
973 
974 		/* check for door errors */
975 		if (lmshrd_iterate(iterator, si) != NERR_Success) {
976 			(void) lmshrd_close_iterator(iterator);
977 			kmem_free(si, sizeof (lmshare_info_t));
978 			kmem_free(auto_si, sizeof (struct lmshare_info));
979 			return;
980 		}
981 	}
982 
983 	(void) lmshrd_close_iterator(iterator);
984 	kmem_free(si, sizeof (lmshare_info_t));
985 	kmem_free(auto_si, sizeof (struct lmshare_info));
986 }
987 
988 /*
989  * smb_encode_SHARE_INFO_1
990  *
991  * This function is extracted from smb_emit_SHARE_INFO_1 and only
992  * encodes fixed part of SHARE_INFO_1 structure.
993  *
994  * The function returns -1 if encoding fails and 0 on success.
995  */
996 static int
997 smb_encode_SHARE_INFO_1(struct mbuf_chain *output, unsigned char *name,
998     uint16_t type, int cmnt_len)
999 {
1000 	if (smb_emit_SHARE_INFO_0(output, name) < 0)
1001 		return (-1);
1002 	(void) smb_encode_mbc(output, ".wl", type, cmnt_len);
1003 	return (0);
1004 }
1005 
1006 /*
1007  * collect_shares_info
1008  *
1009  * This function encodes information of shares_num of shares
1010  * into data_mb and cmnt_str.
1011  *
1012  * Added SMB user object to the parameter list to filter out other
1013  * user autohome shares.
1014  *
1015  */
1016 static void
1017 collect_shares_info(uint64_t iterator, int shares_num,
1018     struct mbuf_chain *data_mb,
1019     char *cmnt_str, int *cmnt_len,
1020     smb_user_t *user, int first_resp)
1021 {
1022 	int i = 0;
1023 	lmshare_info_t *si;
1024 	struct lmshare_info *tsi;
1025 	int is_special;
1026 
1027 	si = kmem_zalloc(sizeof (lmshare_info_t), KM_SLEEP);
1028 	tsi = kmem_zalloc(sizeof (struct lmshare_info), KM_SLEEP);
1029 
1030 	if (first_resp && smb_share_add_autohome(user->u_name, tsi)) {
1031 		if (smb_encode_SHARE_INFO_1(data_mb,
1032 		    (unsigned char *)tsi->share_name,
1033 		    tsi->stype, *cmnt_len) == 0) {
1034 			(void) memcpy(cmnt_str+(*cmnt_len),
1035 			    tsi->comment, strlen(tsi->comment)+1);
1036 			(*cmnt_len) += (strlen(tsi->comment) + 1);
1037 			i++;
1038 		}
1039 	}
1040 
1041 	/* check for door errors */
1042 	if (lmshrd_iterate(iterator, si) != NERR_Success) {
1043 		kmem_free(si, sizeof (lmshare_info_t));
1044 		kmem_free(tsi, sizeof (struct lmshare_info));
1045 		return;
1046 	}
1047 
1048 	while ((i < shares_num) && (*si->share_name != 0)) {
1049 		if (smb_share_skip_share(si)) {
1050 			goto next;
1051 		}
1052 
1053 
1054 		is_special = lmshrd_is_special(si->share_name);
1055 		/* check for door errors */
1056 		if (is_special == NERR_InternalError) {
1057 			kmem_free(si, sizeof (lmshare_info_t));
1058 			kmem_free(tsi, sizeof (struct lmshare_info));
1059 			return;
1060 		}
1061 
1062 		if (is_special) {
1063 			si->stype |= STYPE_HIDDEN;
1064 			if (smb_encode_SHARE_INFO_1(data_mb,
1065 			    (unsigned char *)si->share_name,
1066 			    si->stype, *cmnt_len) < 0) {
1067 				goto next;
1068 			}
1069 			cmnt_str[*cmnt_len] = '\0';
1070 			(*cmnt_len)++;
1071 		} else {
1072 			if (smb_encode_SHARE_INFO_1(data_mb,
1073 			    (unsigned char *)si->share_name, si->stype,
1074 			    *cmnt_len) < 0) {
1075 				goto next;
1076 			}
1077 			(void) memcpy(cmnt_str+(*cmnt_len), si->comment,
1078 			    strlen(si->comment)+1);
1079 			(*cmnt_len) += (strlen(si->comment) + 1);
1080 		}
1081 
1082 	next:
1083 		/* check for door errors */
1084 		if (lmshrd_iterate(iterator, si) != NERR_Success) {
1085 			kmem_free(si, sizeof (lmshare_info_t));
1086 			kmem_free(tsi, sizeof (struct lmshare_info));
1087 			return;
1088 		}
1089 	}
1090 	kmem_free(si, sizeof (lmshare_info_t));
1091 	kmem_free(tsi, sizeof (struct lmshare_info));
1092 }
1093 
1094 int
1095 smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
1096 {
1097 	smb_share_enum_t shr_enum_info;
1098 	short left_shares_cnt;		/* Number of shares not sent yet */
1099 
1100 	/*
1101 	 * Number of shares that should be sent
1102 	 * in the current response packet.
1103 	 * It can be a number between 0 and
1104 	 * max_share_scnt.
1105 	 */
1106 	short shares_scnt;
1107 
1108 	/*
1109 	 * Maximum number of shares that can be
1110 	 * sent in one response packet regarding
1111 	 * the maximum negotiated buffer size
1112 	 * for SMB messages.
1113 	 */
1114 	short max_shares_per_packet;
1115 
1116 	/*
1117 	 * Total number of shares on the server
1118 	 * that their name is not greater than
1119 	 * MAX_SHARE_NAME_LEN
1120 	 */
1121 	short shares_tot_num;
1122 
1123 	/*
1124 	 * Size of total data (info + cmnt)
1125 	 * that should be sent for client
1126 	 */
1127 	int shares_tot_byte;
1128 
1129 	/*
1130 	 * Maximum size of data that can be
1131 	 * sent in one SMB transaction response
1132 	 * according to the maximum negotiated
1133 	 * buffer size for SMB  packets
1134 	 */
1135 	int data_buf_limit;
1136 
1137 	/*
1138 	 * Number of comment bytes that will
1139 	 * be sent in the current response
1140 	 */
1141 	uint16_t cmnt_scnt;
1142 
1143 	/*
1144 	 * Number of data bytes that will
1145 	 * be sent in the current response
1146 	 */
1147 	uint16_t data_scnt;
1148 
1149 	/*
1150 	 * Total number of data bytes that
1151 	 * are sent till now. This is only
1152 	 * used for calculating current data
1153 	 * displacement
1154 	 */
1155 	uint16_t tot_data_scnt;
1156 
1157 	/*
1158 	 * Number of parameter bytes should
1159 	 * be sent for the current response.
1160 	 * It is 8 for the 1st response and
1161 	 * 0 for others
1162 	 */
1163 	uint16_t param_scnt;
1164 
1165 	/* number of setup and parameter bytes */
1166 	uint16_t n_setup, n_param;
1167 
1168 	/* data and parameter displacement */
1169 	uint16_t data_disp, param_disp;
1170 
1171 	/* return status by the 1st reply */
1172 	uint16_t ret_stat;
1173 
1174 	/* parameter and data offset and pad */
1175 	int param_off, param_pad, data_off, data_pad;
1176 
1177 	/*
1178 	 * total bytes of parameters and data
1179 	 * in the packet, plus the pad bytes.
1180 	 */
1181 	int tot_packet_bytes;
1182 
1183 	char first_resp;
1184 	uint16_t opcode, level, cli_bufsize;
1185 	unsigned char *r_fmt;
1186 	char fmt[10];
1187 	uint64_t iterator;
1188 	char *cmnt_str, *cmnt_start;
1189 	int cmnt_len;
1190 	struct mbuf_chain reply;
1191 	smb_user_t *user;
1192 
1193 	user = sr->uid_user;
1194 	ASSERT(user);
1195 
1196 	/*
1197 	 * Initialize the mbuf chain of reply to zero. If it is not
1198 	 * zero, code inside the while loop will try to free the chain.
1199 	 */
1200 	bzero(&reply, sizeof (struct mbuf_chain));
1201 
1202 	if (smb_decode_mbc(&xa->req_param_mb, "%wss(lev)w(size)w", sr,
1203 	    &opcode, &r_fmt, &r_fmt, &level, &cli_bufsize) != 0)
1204 		return (SDRC_UNSUPPORTED);
1205 
1206 	if (level != 1) {
1207 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
1208 		    NERR_BadTransactConfig, 0, 0, 0);
1209 		return (SDRC_NORMAL_REPLY);
1210 	}
1211 
1212 	n_setup = 0;	/* Setup count for NetShareEnum SMB is 0 */
1213 	n_param = 8;
1214 	data_buf_limit = sr->session->smb_msg_size -
1215 	    (SMB_HEADER_ED_LEN + RESP_HEADER_LEN + n_param);
1216 
1217 	shr_enum_info.sei_bufsize = cli_bufsize;
1218 	smb_share_total_info(&shr_enum_info, &shares_tot_num, user);
1219 
1220 	shares_tot_byte = shr_enum_info.sei_infolen + shr_enum_info.sei_cmntlen;
1221 
1222 	/* Check buffer to have enough space */
1223 	if (shares_tot_byte == 0) {
1224 		return (SDRC_ERROR_REPLY);
1225 	}
1226 
1227 	max_shares_per_packet = data_buf_limit / SHARE_INFO_1_SIZE;
1228 
1229 	shares_scnt = (shr_enum_info.sei_count > max_shares_per_packet)
1230 	    ? max_shares_per_packet : shr_enum_info.sei_count;
1231 
1232 	cmnt_str = MEM_MALLOC("smb", shr_enum_info.sei_cmntlen * sizeof (char));
1233 	cmnt_len = 0;
1234 	/* save start of buffer to free it at the end of function */
1235 	cmnt_start = cmnt_str;
1236 
1237 	iterator = lmshrd_open_iterator(LMSHRM_ALL);
1238 
1239 	if (iterator == NULL) {
1240 		MEM_FREE("smb", cmnt_str);
1241 		return (SDRC_DROP_VC);
1242 	}
1243 
1244 	/*
1245 	 * The rep_setup_mb is already initialized in smb_trans_dispatch().
1246 	 * Calling MBC_INIT() will initialized the structure and so the
1247 	 * pointer to the mbuf chains will be lost. Therefore, we need
1248 	 * to free the resources before calling MBC_INIT() again.
1249 	 */
1250 	m_freem(xa->rep_setup_mb.chain);
1251 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
1252 
1253 	left_shares_cnt = shr_enum_info.sei_count;
1254 	tot_data_scnt = 0;
1255 	cmnt_scnt = 0;
1256 
1257 	first_resp = 1;
1258 	while (tot_data_scnt < shares_tot_byte) {
1259 		/*
1260 		 * Calling MBC_INIT() will initialized the structure and so the
1261 		 * pointer to the mbuf chains will be lost. Therefore, we need
1262 		 * to free the resources if any before calling MBC_INIT().
1263 		 */
1264 		m_freem(xa->rep_data_mb.chain);
1265 		MBC_INIT(&xa->rep_data_mb, data_buf_limit);
1266 		collect_shares_info(iterator, shares_scnt, &xa->rep_data_mb,
1267 		    cmnt_str, &cmnt_len, user, first_resp);
1268 		data_scnt = shares_scnt * SHARE_INFO_1_SIZE;
1269 		left_shares_cnt -= shares_scnt;
1270 		if (left_shares_cnt < max_shares_per_packet)
1271 			shares_scnt = left_shares_cnt;
1272 		if (left_shares_cnt == 0) {
1273 			/*
1274 			 * Now send comments.
1275 			 * Append comments to the end of share_info_1
1276 			 * structures.
1277 			 */
1278 			cmnt_scnt = data_buf_limit -
1279 			    MBC_LENGTH(&xa->rep_data_mb);
1280 			if (cmnt_scnt > shr_enum_info.sei_cmntlen) {
1281 				/*LINTED E_ASSIGN_NARROW_CONV*/
1282 				cmnt_scnt = shr_enum_info.sei_cmntlen;
1283 			}
1284 			(void) sprintf(fmt, "%dc", cmnt_scnt);
1285 			(void) smb_encode_mbc(&xa->rep_data_mb, fmt, cmnt_str);
1286 			cmnt_str += cmnt_scnt;
1287 			shr_enum_info.sei_cmntlen -= cmnt_scnt;
1288 		}
1289 		data_scnt += cmnt_scnt;
1290 		tot_data_scnt += data_scnt;
1291 
1292 		/* Only the 1st response packet contains parameters */
1293 		param_scnt = (first_resp) ? n_param : 0;
1294 		param_pad = 1;				/* always one */
1295 		param_off = SMB_HEADER_ED_LEN + RESP_HEADER_LEN;
1296 		param_disp = (first_resp) ? 0 : n_param;
1297 
1298 		/*
1299 		 * Calling MBC_INIT() will initialized the structure and so the
1300 		 * pointer to the mbuf chains will be lost. Therefore, we need
1301 		 * to free the resources if any before calling MBC_INIT().
1302 		 */
1303 		m_freem(xa->rep_param_mb.chain);
1304 		MBC_INIT(&xa->rep_param_mb, param_scnt);
1305 		if (first_resp) {
1306 			first_resp = 0;
1307 			/* Prepare parameters for the 1st response packet */
1308 			ret_stat = (shares_tot_num > shr_enum_info.sei_count)
1309 			    ? ERROR_MORE_DATA : 0;
1310 			(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
1311 			    ret_stat, -shr_enum_info.sei_infolen,
1312 			    shr_enum_info.sei_count,
1313 			    shares_tot_num);
1314 		}
1315 
1316 		data_pad = (param_off + n_param) & 1;	/* Pad to short */
1317 
1318 		/* data off from hdr start */
1319 		data_off = param_off + param_scnt + data_pad;
1320 		data_disp = tot_data_scnt - data_scnt;
1321 		tot_packet_bytes = param_pad + param_scnt + data_pad +
1322 		    data_scnt;
1323 
1324 		/*
1325 		 * Calling MBC_INIT() will initialized the structure and so the
1326 		 * pointer to the mbuf chains will be lost. Therefore, we need
1327 		 * to free the resources if any before calling MBC_INIT().
1328 		 */
1329 		m_freem(reply.chain);
1330 		MBC_INIT(&reply, SMB_HEADER_ED_LEN
1331 		    + sizeof (uchar_t)		/* word parameters count */
1332 		    + 10*sizeof (ushort_t)	/* word parameters */
1333 		    + n_setup*sizeof (ushort_t)	/* setup parameters */
1334 		    + sizeof (ushort_t)		/* total data byte count */
1335 		    + tot_packet_bytes);
1336 
1337 		(void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT,
1338 		    sr->first_smb_com,
1339 		    sr->smb_rcls,
1340 		    sr->smb_reh,
1341 		    sr->smb_err,
1342 		    sr->smb_flg | SMB_FLAGS_REPLY,
1343 		    sr->smb_flg2,
1344 		    sr->smb_pid_high,
1345 		    sr->smb_sig,
1346 		    sr->smb_tid,
1347 		    sr->smb_pid,
1348 		    sr->smb_uid,
1349 		    sr->smb_mid);
1350 
1351 		(void) smb_encode_mbc(&reply,
1352 		    "b ww 2. www www b . C w #. C #. C",
1353 		    10 + n_setup,	/* wct */
1354 		    n_param,		/* Total Parameter Bytes */
1355 		    shares_tot_byte,	/* Total Data Bytes */
1356 		    param_scnt,		/* Total Parameter Bytes this buffer */
1357 		    param_off,		/* Param offset from header start */
1358 		    param_disp,		/* Param displacement */
1359 		    data_scnt,		/* Total Data Bytes this buffer */
1360 		    data_off,		/* Data offset from header start */
1361 		    data_disp,		/* Data displacement */
1362 		    n_setup,		/* suwcnt */
1363 		    &xa->rep_setup_mb, 	/* setup[] */
1364 		    tot_packet_bytes,	/* Total data bytes */
1365 		    param_pad,
1366 		    &xa->rep_param_mb,
1367 		    data_pad,
1368 		    &xa->rep_data_mb);
1369 
1370 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
1371 			smb_sign_reply(sr, NULL);
1372 
1373 		(void) smb_session_send(sr->session, 0, &reply);
1374 	}
1375 
1376 	(void) lmshrd_close_iterator(iterator);
1377 	MEM_FREE("smb", cmnt_start);
1378 	return (SDRC_NO_REPLY);
1379 }
1380 
1381 int
1382 smb_trans_net_share_get_info(struct smb_request *sr, struct smb_xa *xa)
1383 {
1384 	uint16_t		opcode, level, max_bytes, access;
1385 	uint32_t		type;
1386 	unsigned char		*req_fmt;
1387 	unsigned char		*rep_fmt;
1388 	struct mbuf_chain	str_mb;
1389 	char			*share;
1390 	char			*path;
1391 	char			*password;
1392 	char			*comment;
1393 	lmshare_info_t		si;
1394 	int			shr_found;
1395 
1396 	if (smb_decode_mbc(&xa->req_param_mb, "%wsss(lev)w(size)w", sr,
1397 	    &opcode, &req_fmt, &rep_fmt, &share, &level, &max_bytes) != 0)
1398 		return (SDRC_UNSUPPORTED);
1399 
1400 	(void) utf8_strlwr(share);
1401 	shr_found = lmshrd_getinfo(share, &si);
1402 	if (strcmp(share, "ipc$") == 0) {
1403 		type = STYPE_IPC;
1404 		path = "";
1405 		password = "";
1406 		access = SHARE_ACCESS_ALL;
1407 	} else if (shr_found) {
1408 		path = si.directory;
1409 		type = STYPE_DISKTREE;
1410 		if (path[strlen(path)] == '$')
1411 			type |= STYPE_HIDDEN;
1412 		password = "";
1413 		access = SHARE_ACCESS_ALL;
1414 	} else {
1415 		/* We have no idea what this share is... */
1416 		(void) smb_encode_mbc(&xa->rep_param_mb, "www",
1417 		    NERR_NetNameNotFound, 0, 0);
1418 		return (SDRC_NORMAL_REPLY);
1419 	}
1420 
1421 	if (shr_found)
1422 		comment = si.comment;
1423 	else
1424 		comment = "";
1425 
1426 	password = "";
1427 
1428 	MBC_INIT(&str_mb, max_bytes);
1429 
1430 	switch (level) {
1431 	case 0 :
1432 		(void) smb_emit_SHARE_INFO_0(&xa->rep_data_mb,
1433 		    (unsigned char *)share);
1434 		break;
1435 
1436 	case 1 :
1437 		(void) smb_emit_SHARE_INFO_1(&xa->rep_data_mb, &str_mb,
1438 		    (unsigned char *)share, type,
1439 		    (unsigned char *)comment);
1440 		break;
1441 
1442 	case 2 :
1443 		smb_emit_SHARE_INFO_2(&xa->rep_data_mb, &str_mb, sr,
1444 		    (unsigned char *)share, type, (unsigned char *)comment,
1445 		    access, path, password);
1446 	default:
1447 		m_freem(str_mb.chain);
1448 		return (SDRC_UNSUPPORTED);
1449 	}
1450 
1451 	(void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
1452 	    -MBC_LENGTH(&xa->rep_data_mb),
1453 	    MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
1454 	(void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
1455 	m_freem(str_mb.chain);
1456 	return (SDRC_NORMAL_REPLY);
1457 }
1458 
1459 int
1460 smb_trans_net_workstation_get_info(struct smb_request *sr, struct smb_xa *xa)
1461 {
1462 	uint16_t		opcode, level, max_bytes;
1463 	unsigned char		*req_fmt;
1464 	unsigned char		*rep_fmt;
1465 	struct mbuf_chain	str_mb;
1466 	char *domain;
1467 	char *hostname;
1468 
1469 	if ((smb_decode_mbc(&xa->req_param_mb, "%wss(lev)w(size)w", sr,
1470 	    &opcode, &req_fmt, &rep_fmt, &level, &max_bytes) != 0) ||
1471 	    (level != 10)) {
1472 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
1473 		    NERR_BadTransactConfig, 0, 0, 0);
1474 		return (SDRC_NORMAL_REPLY);
1475 	}
1476 
1477 	domain = smb_info.si.skc_resource_domain;
1478 	hostname = smb_info.si.skc_hostname;
1479 
1480 	MBC_INIT(&str_mb, max_bytes);
1481 
1482 	(void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
1483 
1484 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1485 	(void) smb_encode_mbc(&str_mb, "s", hostname);
1486 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1487 	(void) smb_encode_mbc(&str_mb, "s", "nobody");
1488 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1489 	(void) smb_encode_mbc(&str_mb, "s", domain);
1490 	(void) smb_encode_mbc(&xa->rep_data_mb, "bbl",
1491 	    SMB_VERSION_MAJOR, SMB_VERSION_MINOR, MBC_LENGTH(&str_mb));
1492 	(void) smb_encode_mbc(&str_mb, "s", domain);
1493 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1494 	(void) smb_encode_mbc(&str_mb, "s", domain);
1495 
1496 	(void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
1497 	    -MBC_LENGTH(&xa->rep_data_mb),
1498 	    MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
1499 	(void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
1500 	m_freem(str_mb.chain);
1501 	return (SDRC_NORMAL_REPLY);
1502 }
1503 
1504 int
1505 smb_trans_net_user_get_info(struct smb_request *sr, struct smb_xa *xa)
1506 {
1507 	uint16_t		opcode, level, max_bytes;
1508 	unsigned char		*req_fmt;
1509 	unsigned char		*rep_fmt;
1510 	unsigned char		*user;
1511 	int rc;
1512 
1513 	rc = smb_decode_mbc(&xa->req_param_mb, "%wssww", sr,
1514 	    &opcode,
1515 	    &req_fmt,
1516 	    &rep_fmt,
1517 	    &user,
1518 	    &level,
1519 	    &max_bytes);
1520 
1521 	if (rc != 0)
1522 		return (SDRC_UNSUPPORTED);
1523 
1524 	(void) smb_encode_mbc(&xa->rep_param_mb, "www",
1525 	    NERR_UserNotFound, 0, 0);
1526 	return (SDRC_NORMAL_REPLY);
1527 }
1528 
1529 
1530 int
1531 smb_trans_server_get_info(struct smb_request *sr, struct smb_xa *xa)
1532 {
1533 	uint16_t		opcode, level, buf_size;
1534 	char			*req_fmt;
1535 	char			*rep_fmt;
1536 	char			server_name[16];
1537 	struct mbuf_chain	str_mb;
1538 	char *hostname;
1539 	char *comment;
1540 
1541 	if (smb_decode_mbc(&xa->req_param_mb, "%wssww", sr,
1542 	    &opcode, &req_fmt, &rep_fmt, &level, &buf_size) != 0) {
1543 		smbsr_decode_error(sr);
1544 		/* NOTREACHED */
1545 	}
1546 
1547 	comment = smb_info.si.skc_system_comment;
1548 	hostname = smb_info.si.skc_hostname;
1549 
1550 	MBC_INIT(&str_mb, buf_size);
1551 
1552 	bzero(server_name, sizeof (server_name));
1553 	(void) strncpy(server_name, hostname, sizeof (server_name));
1554 
1555 	switch (level) {
1556 	case 0:
1557 		(void) smb_encode_mbc(&xa->rep_data_mb, "16c", server_name);
1558 		break;
1559 	case 1:
1560 		(void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
1561 		(void) smb_encode_mbc(&xa->rep_data_mb, "16cbbll", server_name,
1562 		    SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
1563 		    MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
1564 		(void) smb_encode_mbc(&str_mb, "s", comment);
1565 		break;
1566 	case 2:
1567 		/* B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWz */
1568 		(void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
1569 					/*  B16BBDz */
1570 		(void) smb_encode_mbc(&xa->rep_data_mb, "16cbbll", server_name,
1571 		    SMB_VERSION_MAJOR,
1572 		    SMB_VERSION_MINOR, MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
1573 		(void) smb_encode_mbc(&str_mb, "s", comment);
1574 		(void) smb_encode_mbc(&xa->rep_data_mb, "lllwwl",
1575 		    (uint32_t)1,
1576 		    (uint32_t)2,
1577 		    (uint32_t)3,
1578 		    (uint16_t)4,
1579 		    (uint16_t)5,
1580 		    MBC_LENGTH(&str_mb));
1581 		(void) smb_encode_mbc(&str_mb, "s", "str1");
1582 		(void) smb_encode_mbc(&xa->rep_data_mb, "wwwwwww21cbl",
1583 		    (uint16_t)6,
1584 		    (uint16_t)7,
1585 		    (uint16_t)8,
1586 		    (uint16_t)9,
1587 		    (uint16_t)10,
1588 		    (uint16_t)11,
1589 		    (uint16_t)12,
1590 		    "21 byte comment       ",
1591 		    (unsigned char)13,
1592 		    MBC_LENGTH(&str_mb));
1593 		(void) smb_encode_mbc(&str_mb, "s", "str2");
1594 		(void) smb_encode_mbc(&xa->rep_data_mb,
1595 		    "wwwwwwwwwwwwwwwwwwwwwwl",
1596 		    (uint16_t)14,
1597 		    (uint16_t)15,
1598 		    (uint16_t)16,
1599 		    (uint16_t)17,
1600 		    (uint16_t)18,
1601 		    (uint16_t)19,
1602 		    (uint16_t)20,
1603 		    (uint16_t)21,
1604 		    (uint16_t)22,
1605 		    (uint16_t)23,
1606 		    (uint16_t)24,
1607 		    (uint16_t)25,
1608 		    (uint16_t)26,
1609 		    (uint16_t)27,
1610 		    (uint16_t)28,
1611 		    (uint16_t)29,
1612 		    (uint16_t)20,
1613 		    (uint16_t)31,
1614 		    (uint16_t)32,
1615 		    (uint16_t)33,
1616 		    (uint16_t)34,
1617 		    (uint16_t)35,
1618 		    MBC_LENGTH(&str_mb));
1619 		(void) smb_encode_mbc(&str_mb, "s", "str3");
1620 		break;
1621 	default:
1622 		m_freem(str_mb.chain);
1623 		return (SDRC_UNSUPPORTED);
1624 	}
1625 
1626 	(void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
1627 	    -MBC_LENGTH(&xa->rep_data_mb),
1628 	    (MBC_LENGTH(&xa->rep_data_mb)) +
1629 	    (MBC_LENGTH(&str_mb)));
1630 	(void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
1631 	m_freem(str_mb.chain);
1632 	return (SDRC_NORMAL_REPLY);
1633 }
1634 
1635 /*
1636  * 6.4 The NetServerEnum2 RAP Service
1637  *
1638  * The NetServerEnum2 RAP service lists all computers of the specified type
1639  * or types that are visible in the specified domains. It may also
1640  * enumerate domains.
1641  *
1642  * The following definition uses the notation and terminology defined in
1643  * the CIFS Remote Administration Protocol specification, which is required
1644  * in order to make it well-defined. The definition is:
1645  *
1646  *     uint16_t NetServerEnum2 (
1647  *         uint16_t  sLevel,
1648  *         RCVBUF          pbBuffer,
1649  *         RCVBUFLEN       cbBuffer,
1650  *         ENTCOUNT        pcEntriesRead,
1651  *         uint16_t  *pcTotalAvail,
1652  *         uint32_t   fServerType,
1653  *         char            *pszDomain,
1654  *     );
1655  *
1656  * where:
1657  *
1658  *    sLevel specifies the level of detail (0 or 1) requested.
1659  *
1660  *    pbBuffer points to the buffer to receive the returned data. If the
1661  *    function is successful, the buffer contains a sequence of
1662  *    server_info_x structures, where x is 0 or 1, depending on the
1663  *    level of detail requested.
1664  *
1665  *    cbBuffer specifies the size, in bytes, of the buffer pointed to by
1666  *    the pbBuffer parameter.
1667  *
1668  *    pcEntriesRead points to a 16 bit variable that receives a count of
1669  *    the number of servers enumerated in the buffer. This count is
1670  *    valid only if NetServerEnum2 returns the NERR_Success or
1671  *    ERROR_MORE_DATA values.
1672  *
1673  *    pcTotal Avail points to a 16 bit variable that receives a count of
1674  *    the total number of available entries. This count is valid only if
1675  *    NetServerEnum2 returns the NERR_Success or ERROR_MORE_DATA values.
1676  *
1677  *     fServerType specifies the type or types of computers to enumerate.
1678  *     Computers that match at least one of the specified types are
1679  *     returned in the buffer. Possible values are defined in the request
1680  *     parameters section.
1681  *
1682  *    pszDomain points to a null-terminated string that contains the
1683  *    name of the workgroup in which to enumerate computers of the
1684  *    specified type or types. If the pszDomain parameter is a null
1685  *    string or a null pointer, servers are enumerated for the current
1686  *    domain of the computer.
1687  *
1688  * 6.4.1 Transaction Request Parameters section
1689  *
1690  * The Transaction request parameters section in this instance contains:
1691  * . The 16 bit function number for NetServerEnum2 which is 104.
1692  * . The parameter descriptor string which is "WrLehDz".
1693  * . The data descriptor string for the (returned) data which is "B16" for
1694  *   level detail 0 or "B16BBDz" for level detail 1.
1695  * . The actual parameters as described by the parameter descriptor
1696  *   string.
1697  *
1698  * The parameters are:
1699  * . A 16 bit integer with a value of 0 or 1 (corresponding to the "W" in
1700  *   the parameter descriptor string. This represents the level of detail
1701  *   the server is expected to return
1702  * . A 16 bit integer that contains the size of the receive buffer.
1703  * . A 32 bit integer that represents the type of servers the function
1704  *   should enumerate. The possible values may be any of the following or
1705  *   a combination of the following:
1706  *
1707  * SV_TYPE_WORKSTATION        0x00000001 All workstations
1708  * SV_TYPE_SERVER             0x00000002 All servers
1709  * SV_TYPE_SQLSERVER          0x00000004 Any server running with SQL
1710  *                                       server
1711  * SV_TYPE_DOMAIN_CTRL        0x00000008 Primary domain controller
1712  * SV_TYPE_DOMAIN_BAKCTRL     0x00000010 Backup domain controller
1713  * SV_TYPE_TIME_SOURCE        0x00000020 Server running the timesource
1714  *                                       service
1715  * SV_TYPE_AFP                0x00000040 Apple File Protocol servers
1716  * SV_TYPE_NOVELL             0x00000080 Novell servers
1717  * SV_TYPE_DOMAIN_MEMBER      0x00000100 Domain Member
1718  * SV_TYPE_PRINTQ_SERVER      0x00000200 Server sharing print queue
1719  * SV_TYPE_DIALIN_SERVER      0x00000400 Server running dialin service.
1720  * SV_TYPE_XENIX_SERVER       0x00000800 Xenix server
1721  * SV_TYPE_NT                 0x00001000 NT server
1722  * SV_TYPE_WFW                0x00002000 Server running Windows for
1723  *                                       Workgroups
1724  * SV_TYPE_SERVER_NT          0x00008000 Windows NT non DC server
1725  * SV_TYPE_POTENTIAL_BROWSER  0x00010000 Server that can run the browser
1726  *                                       service
1727  * SV_TYPE_BACKUP_BROWSER     0x00020000 Backup browser server
1728  * SV_TYPE_MASTER_BROWSER     0x00040000 Master browser server
1729  * SV_TYPE_DOMAIN_MASTER      0x00080000 Domain Master Browser server
1730  * SV_TYPE_LOCAL_LIST_ONLY    0x40000000 Enumerate only entries marked
1731  *                                       "local"
1732  * SV_TYPE_DOMAIN_ENUM        0x80000000 Enumerate Domains. The pszDomain
1733  *                                       parameter must be NULL.
1734  *
1735  * . A null terminated ASCII string representing the pszDomain parameter
1736  *   described above
1737  *
1738  * 6.4.2 Transaction Request Data section
1739  *
1740  * There is no data or auxiliary data to send as part of the request.
1741  *
1742  * 6.4.3 Transaction Response Parameters section
1743  *
1744  * The transaction response parameters section consists of:
1745  * . A 16 bit word indicating the return status. The possible values are:
1746  *
1747  * Code                   Value  Description
1748  * NERR_Success           0      No errors encountered
1749  * ERROR_MORE_DATA        234    Additional data is available
1750  * NERR_ServerNotStarted  2114   The RAP service on the remote computer
1751  *                               is not running
1752  * NERR_BadTransactConfig 2141   The server is not configured for
1753  *                               transactions, IPC$ is not shared
1754  *
1755  * . A 16 bit "converter" word.
1756  * . A 16 bit number representing the number of entries returned.
1757  * . A 16 bit number representing the total number of available entries.
1758  *   If the supplied buffer is large enough, this will equal the number of
1759  *   entries returned.
1760  *
1761  * 6.4.4 Transaction Response Data section
1762  *
1763  * The return data section consists of a number of SERVER_INFO_1 structures.
1764  * The number of such structures present is determined by the third entry
1765  * (described above) in the return parameters section.
1766  *
1767  * At level detail 0, the Transaction response data section contains a
1768  * number of SERVER_INFO_0 data structure. The number of such structures is
1769  * equal to the 16 bit number returned by the server in the third parameter
1770  * in the Transaction response parameter section. The SERVER_INFO_0 data
1771  * structure is defined as:
1772  *
1773  *     struct SERVER_INFO_0 {
1774  *         char        sv0_name[16];
1775  *     };
1776  *
1777  *  where:
1778  *
1779  *    sv0_name is a null-terminated string that specifies the name of a
1780  *    computer or domain .
1781  *
1782  * At level detail 1, the Transaction response data section contains a
1783  * number of SERVER_INFO_1 data structure. The number of such structures is
1784  * equal to the 16 bit number returned by the server in the third parameter
1785  * in the Transaction response parameter section. The SERVER_INFO_1 data
1786  * structure is defined as:
1787  *
1788  *     struct SERVER_INFO_1 {
1789  *         char            sv1_name[16];
1790  *         char            sv1_version_major;
1791  *         char            sv1_version_minor;
1792  *         uint32_t   sv1_type;
1793  *         char        *sv1_comment_or_master_browser;
1794  *     };
1795  *
1796  *    sv1_name contains a null-terminated string that specifies the name
1797  *    of a computer, or a domain name if SV_TYPE_DOMAIN_ENUM is set in
1798  *    sv1_type.
1799  *
1800  *    sv1_version_major whatever was specified in the HostAnnouncement
1801  *    or DomainAnnouncement frame with which the entry was registered.
1802  *
1803  *    sv1_version_minor whatever was specified in the HostAnnouncement
1804  *    or DomainAnnouncement frame with which the entry was registered.
1805  *
1806  *    sv1_type specifies the type of software the computer is running.
1807  *    The member can be one or a combination of the values defined above
1808  *    in the Transaction request parameters section for fServerType.
1809  *
1810  *
1811  *    sv1_comment_or_master_browser points to a null-terminated string. If
1812  *    the sv1_type indicates that the entry is for a domain, this
1813  *    specifies the name of server running the domain master browser;
1814  *    otherwise, it specifies a comment describing the server. The comment
1815  *    can be a null string or the pointer may be a null pointer.
1816  *
1817  *    In case there are multiple SERVER_INFO_1 data structures to
1818  *    return, the server may put all these fixed length structures in
1819  *    the return buffer, leave some space and then put all the variable
1820  *    length data (the actual value of the sv1_comment strings) at the
1821  *    end of the buffer.
1822  *
1823  * There is no auxiliary data to receive.
1824  */
1825 
1826 int
1827 smb_trans_net_server_enum2(struct smb_request *sr, struct smb_xa *xa)
1828 {
1829 	uint16_t opcode, level, max_bytes;
1830 	uint32_t server_type;
1831 	unsigned char *domain;
1832 	struct mbuf_chain str_mb;
1833 	char *hostname, *s;
1834 	smb_kmod_cfg_t *si;
1835 
1836 	if (smb_decode_mbc(&xa->req_param_mb,
1837 	    "%w s(request format) s(reply format) wwls", sr, &opcode, &s, &s,
1838 	    &level, &max_bytes, &server_type, &domain) != 0)
1839 		return (SDRC_UNSUPPORTED);
1840 
1841 	si = &smb_info.si;
1842 
1843 	if (utf8_strcasecmp(si->skc_resource_domain, (char *)domain) != 0) {
1844 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
1845 		return (SDRC_NORMAL_REPLY);
1846 	}
1847 
1848 	if ((server_type & MY_SERVER_TYPE) == 0) {
1849 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
1850 		return (SDRC_NORMAL_REPLY);
1851 	}
1852 
1853 	MBC_INIT(&str_mb, max_bytes);
1854 
1855 	hostname = si->skc_hostname;
1856 
1857 	(void) smb_encode_mbc(&xa->rep_data_mb, "16c", hostname);
1858 	if (level == 1) {
1859 		(void) smb_encode_mbc(&xa->rep_data_mb, "bbll",
1860 		    SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
1861 		    MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
1862 		(void) smb_encode_mbc(&str_mb, "s", si->skc_system_comment);
1863 	}
1864 
1865 	(void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0,
1866 	    -MBC_LENGTH(&xa->rep_data_mb), 1, 1);
1867 	(void) smb_encode_mbc(&xa->rep_data_mb, "m", str_mb.chain);
1868 	return (SDRC_NORMAL_REPLY);
1869 }
1870 
1871 /*
1872  * is_supported_pipe
1873  *
1874  * Currently, just return 0 if the pipe is \\PIPE\repl otherwise
1875  * return 1.
1876  */
1877 int
1878 is_supported_pipe(char *pname)
1879 {
1880 	if (utf8_strcasecmp(pname, PIPE_REPL) == 0)
1881 		return (0);
1882 
1883 	return (1);
1884 }
1885 
1886 int
1887 smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
1888 {
1889 	int		rc, pos;
1890 	int		total_bytes, n_setup, n_param, n_data;
1891 	int		param_off, param_pad, data_off, data_pad;
1892 	uint16_t	opcode;
1893 	uint16_t	devstate;
1894 	char		*req_fmt;
1895 	char		*rep_fmt;
1896 	struct vardata_block vdb;
1897 
1898 	n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
1899 	n_setup++;
1900 	n_setup = n_setup & ~0x0001;
1901 	n_param = (xa->smb_mprcnt < smb_maxbufsize)
1902 	    ? xa->smb_mprcnt : smb_maxbufsize;
1903 	n_param++;
1904 	n_param = n_param & ~0x0001;
1905 	rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
1906 	n_data =  (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
1907 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
1908 	MBC_INIT(&xa->rep_param_mb, n_param);
1909 	MBC_INIT(&xa->rep_data_mb, n_data);
1910 
1911 	if (xa->smb_suwcnt > 0 && STYPE_ISIPC(sr->tid_tree->t_res_type)) {
1912 		rc = smb_decode_mbc(&xa->req_setup_mb, "ww", &opcode,
1913 		    &sr->smb_fid);
1914 		if (rc != 0)
1915 			goto trans_err_not_supported;
1916 		switch (opcode) {
1917 		case TRANS_SET_NMPIPE_STATE:
1918 			if ((rc = smb_decode_mbc(&xa->req_param_mb, "w",
1919 			    &devstate)) != 0)
1920 				goto trans_err_not_supported;
1921 
1922 			rc = SDRC_NORMAL_REPLY;
1923 			break;
1924 
1925 		case TRANS_TRANSACT_NMPIPE:
1926 			sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
1927 			    sr->smb_fid);
1928 			if (sr->fid_ofile == NULL) {
1929 				smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
1930 				    ERRDOS, ERRbadfid);
1931 				/* NOTREACHED */
1932 			}
1933 
1934 			rc = smb_decode_mbc(&xa->req_data_mb, "#B",
1935 			    xa->smb_tdscnt, &vdb);
1936 			if (rc != 0)
1937 				goto trans_err_not_supported;
1938 
1939 			rc = smb_rpc_transact(sr, &vdb.uio);
1940 			break;
1941 
1942 		case TRANS_WAIT_NMPIPE:
1943 			if (is_supported_pipe(xa->xa_smb_trans_name) == 0) {
1944 				smbsr_error(sr, 0, ERRDOS, ERRbadfile);
1945 				/* NOT REACHED */
1946 			}
1947 			rc = SDRC_NORMAL_REPLY;
1948 			break;
1949 
1950 		default:
1951 			goto trans_err_not_supported;
1952 		}
1953 	} else {
1954 		if ((utf8_strcasecmp(xa->xa_smb_trans_name,
1955 		    PIPE_LANMAN) != 0) &&
1956 		    (utf8_strcasecmp(
1957 		    xa->xa_smb_trans_name, MAILSLOT_LANMAN) != 0) &&
1958 		    (utf8_strcasecmp(
1959 		    xa->xa_smb_trans_name, MAILSLOT_BROWSE) != 0) &&
1960 		    (utf8_strcasecmp(
1961 		    xa->xa_smb_trans_name, MAILSLOT_MSBROWSE) != 0))
1962 			goto trans_err_not_supported;
1963 
1964 		if ((rc = smb_decode_mbc(&xa->req_param_mb, "%wss\b", sr,
1965 		    &opcode, &req_fmt, &rep_fmt)) != 0)
1966 			goto trans_err_not_supported;
1967 
1968 		/* for now, only respond to the */
1969 		switch (opcode) {
1970 		case API_WshareEnum:
1971 			rc = smb_trans_net_share_enum(sr, xa);
1972 			break;
1973 
1974 		case API_WshareGetInfo:
1975 			rc = smb_trans_net_share_get_info(sr, xa);
1976 			break;
1977 
1978 		case API_WserverGetInfo:
1979 			rc = smb_trans_server_get_info(sr, xa);
1980 			break;
1981 
1982 		case API_WUserGetInfo:
1983 			rc = smb_trans_net_user_get_info(sr, xa);
1984 			break;
1985 
1986 		case API_WWkstaGetInfo:
1987 			rc = smb_trans_net_workstation_get_info(sr, xa);
1988 			break;
1989 
1990 		case API_NetServerEnum2:
1991 			rc = smb_trans_net_server_enum2(sr, xa);
1992 			break;
1993 
1994 		default:
1995 			goto trans_err_not_supported;
1996 		}
1997 	}
1998 
1999 	switch (rc) {
2000 	case SDRC_NORMAL_REPLY:
2001 		break;
2002 
2003 	case SDRC_DROP_VC:
2004 	case SDRC_NO_REPLY:
2005 	case SDRC_ERROR_REPLY:
2006 		return (rc);
2007 
2008 	case SDRC_UNIMPLEMENTED:
2009 	case SDRC_UNSUPPORTED:
2010 		goto trans_err_not_supported;
2011 
2012 	default:
2013 		break;
2014 	}
2015 
2016 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
2017 	n_param = MBC_LENGTH(&xa->rep_param_mb);
2018 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
2019 
2020 	if (xa->smb_msrcnt < n_setup ||
2021 	    xa->smb_mprcnt < n_param ||
2022 	    xa->smb_mdrcnt < n_data) {
2023 		goto trans_err_too_small;
2024 	}
2025 
2026 	/* neato, blast it over there */
2027 
2028 	n_setup = (n_setup + 1) / 2;		/* Convert to setup words */
2029 	param_pad = 1;				/* always one */
2030 	param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
2031 	data_pad = (param_off + n_param) & 1;	/* Pad to short */
2032 	/* Param off from hdr start */
2033 	data_off = param_off + n_param + data_pad;
2034 	total_bytes = param_pad + n_param + data_pad + n_data;
2035 
2036 	smbsr_encode_result(sr, 10+n_setup, total_bytes,
2037 	    "b ww 2. www www b . C w #. C #. C",
2038 	    10 + n_setup,		/* wct */
2039 	    n_param,			/* Total Parameter Bytes */
2040 	    n_data,			/* Total Data Bytes */
2041 	    n_param,			/* Total Parameter Bytes this buffer */
2042 	    param_off,			/* Param offset from header start */
2043 	    0,				/* Param displacement */
2044 	    n_data,			/* Total Data Bytes this buffer */
2045 	    data_off,			/* Data offset from header start */
2046 	    0,				/* Data displacement */
2047 	    n_setup,			/* suwcnt */
2048 	    &xa->rep_setup_mb, /* setup[] */
2049 	    total_bytes,		/* Total data bytes */
2050 	    param_pad,
2051 	    &xa->rep_param_mb,
2052 	    data_pad,
2053 	    &xa->rep_data_mb);
2054 	return (SDRC_NORMAL_REPLY);
2055 
2056 trans_err_too_small:
2057 	rc = NERR_BufTooSmall;
2058 	goto trans_err;
2059 
2060 trans_err_not_supported:
2061 	rc = ERROR_NOT_SUPPORTED;
2062 	goto trans_err;
2063 
2064 trans_err:
2065 	pos = MBC_LENGTH(&sr->reply) + 23;
2066 	smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
2067 	    10,		/* wct */
2068 	    4, 0,	/* tpscnt tdscnt */
2069 	    4, pos, 0,	/* pscnt psoff psdisp */
2070 	    0, 0, 0,	/* dscnt dsoff dsdisp */
2071 	    0,		/* suwcnt */
2072 	    4,		/* bcc */
2073 	    rc,
2074 	    0);		/* converter word? */
2075 
2076 	return (SDRC_NORMAL_REPLY);
2077 }
2078 
2079 int
2080 smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa)
2081 {
2082 	int		rc, pos;
2083 	int		total_bytes, n_setup, n_param, n_data;
2084 	int		param_off, param_pad, data_off, data_pad;
2085 	uint16_t	opcode;
2086 	uint16_t  nt_unknown_secret = 0x0100;
2087 	char *fmt;
2088 
2089 	n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
2090 	n_setup++;
2091 	n_setup = n_setup & ~0x0001;
2092 	n_param = (xa->smb_mprcnt < smb_maxbufsize)
2093 	    ? xa->smb_mprcnt : smb_maxbufsize;
2094 	n_param++;
2095 	n_param = n_param & ~0x0001;
2096 	rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
2097 	n_data =  (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
2098 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
2099 	MBC_INIT(&xa->rep_param_mb, n_param);
2100 	MBC_INIT(&xa->rep_data_mb, n_data);
2101 
2102 	if (smb_decode_mbc(&xa->req_setup_mb, "w", &opcode) != 0)
2103 		goto trans_err_not_supported;
2104 
2105 	/*
2106 	 * Save this for /proc to read later.
2107 	 */
2108 	xa->smb_func = opcode;
2109 
2110 	/* for now, only respond to the */
2111 	switch (opcode) {
2112 	case TRANS2_CREATE_DIRECTORY:
2113 		rc = smb_com_trans2_create_directory(sr, xa);
2114 		break;
2115 
2116 	case TRANS2_FIND_FIRST2:
2117 		/*
2118 		 * Should have enough room to send the response
2119 		 * data back to client.
2120 		 */
2121 		if (n_data == 0) {
2122 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
2123 			    ERRDOS, ERROR_BAD_LENGTH);
2124 			/* NOT REACHED */
2125 		}
2126 		rc = smb_com_trans2_find_first2(sr, xa);
2127 		break;
2128 
2129 	case TRANS2_FIND_NEXT2:
2130 		/*
2131 		 * Should have enough room to send the response
2132 		 * data back to client.
2133 		 */
2134 		if (n_data == 0) {
2135 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
2136 			    ERRDOS, ERROR_BAD_LENGTH);
2137 			/* NOT REACHED */
2138 		}
2139 		rc = smb_com_trans2_find_next2(sr, xa);
2140 		break;
2141 
2142 	case TRANS2_QUERY_FS_INFORMATION:
2143 		/*
2144 		 * Should have enough room to send the response
2145 		 * data back to client.
2146 		 */
2147 		if (n_data == 0) {
2148 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
2149 			    ERRDOS, ERROR_BAD_LENGTH);
2150 			/* NOT REACHED */
2151 		}
2152 		rc = smb_com_trans2_query_fs_information(sr, xa);
2153 		break;
2154 
2155 	case TRANS2_QUERY_PATH_INFORMATION:
2156 		/*
2157 		 * Should have enough room to send the response
2158 		 * data back to client.
2159 		 */
2160 		if (n_data == 0) {
2161 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
2162 			    ERRDOS, ERROR_BAD_LENGTH);
2163 			/* NOT REACHED */
2164 		}
2165 		rc = smb_com_trans2_query_path_information(sr, xa);
2166 		break;
2167 
2168 	case TRANS2_QUERY_FILE_INFORMATION:
2169 		/*
2170 		 * Should have enough room to send the response
2171 		 * data back to client.
2172 		 */
2173 		if (n_data == 0) {
2174 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
2175 			    ERRDOS, ERROR_BAD_LENGTH);
2176 			/* NOT REACHED */
2177 		}
2178 		rc = smb_com_trans2_query_file_information(sr, xa);
2179 		break;
2180 
2181 	case TRANS2_SET_PATH_INFORMATION:
2182 		rc = smb_com_trans2_set_path_information(sr, xa);
2183 		break;
2184 
2185 	case TRANS2_SET_FILE_INFORMATION:
2186 		rc = smb_com_trans2_set_file_information(sr, xa);
2187 		break;
2188 	default:
2189 		goto trans_err_not_supported;
2190 	}
2191 
2192 	switch (rc) {
2193 	case SDRC_NORMAL_REPLY:
2194 		break;
2195 
2196 	case SDRC_DROP_VC:
2197 	case SDRC_NO_REPLY:
2198 	case SDRC_ERROR_REPLY:
2199 		return (rc);
2200 
2201 	case SDRC_UNIMPLEMENTED:
2202 	case SDRC_UNSUPPORTED:
2203 		goto trans_err_not_supported;
2204 
2205 	default:
2206 		break;
2207 	}
2208 
2209 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
2210 	n_param = MBC_LENGTH(&xa->rep_param_mb);
2211 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
2212 
2213 	if (xa->smb_msrcnt < n_setup ||
2214 	    xa->smb_mprcnt < n_param ||
2215 	    xa->smb_mdrcnt < n_data) {
2216 		goto trans_err_too_small;
2217 	}
2218 
2219 	/* neato, blast it over there */
2220 
2221 	n_setup = (n_setup + 1) / 2;		/* Conver to setup words */
2222 	param_pad = 1;				/* must be one */
2223 	param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
2224 
2225 	/*
2226 	 * Including the nt_unknown_secret value persuades netmon to
2227 	 * display the correct data format for QueryPathInfo and
2228 	 * QueryFileInfo.
2229 	 */
2230 	if (opcode == TRANS2_QUERY_FILE_INFORMATION ||
2231 	    opcode == TRANS2_QUERY_PATH_INFORMATION) {
2232 		data_pad = sizeof (uint16_t);
2233 		data_off = param_off + n_param + data_pad;
2234 		fmt = "b ww 2. www www b . C w #. C w C";
2235 		nt_unknown_secret = 0x0100;
2236 	}
2237 	else
2238 	{
2239 		data_pad = (param_off + n_param) & 1; /* Pad to short */
2240 		/* Param off from hdr start */
2241 		data_off = param_off + n_param + data_pad;
2242 		fmt = "b ww 2. www www b . C w #. C #. C";
2243 		/*LINTED E_ASSIGN_NARROW_CONV*/
2244 		nt_unknown_secret = data_pad;
2245 	}
2246 
2247 	total_bytes = param_pad + n_param + data_pad + n_data;
2248 
2249 	smbsr_encode_result(sr, 10+n_setup, total_bytes,
2250 	    fmt,
2251 	    10 + n_setup,		/* wct */
2252 	    n_param,			/* Total Parameter Bytes */
2253 	    n_data /* + data_pad */,	/* Total Data Bytes */
2254 	    n_param,			/* Total Parameter Bytes this buffer */
2255 	    param_off,			/* Param offset from header start */
2256 	    0,				/* Param displacement */
2257 	    n_data /* + data_pad */,	/* Total Data Bytes this buffer */
2258 	    data_off,			/* Data offset from header start */
2259 	    0,				/* Data displacement */
2260 	    n_setup,			/* suwcnt */
2261 	    &xa->rep_setup_mb,		/* setup[] */
2262 	    total_bytes,		/* Total data bytes */
2263 	    param_pad,
2264 	    &xa->rep_param_mb,
2265 	    nt_unknown_secret,
2266 	    &xa->rep_data_mb);
2267 	return (SDRC_NORMAL_REPLY);
2268 
2269 trans_err_too_small:
2270 	rc = NERR_BufTooSmall;
2271 	goto trans_err;
2272 
2273 trans_err_not_supported:
2274 	rc = ERROR_NOT_SUPPORTED;
2275 	goto trans_err;
2276 
2277 trans_err:
2278 	pos = MBC_LENGTH(&sr->reply) + 23;
2279 	smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
2280 	    10,		/* wct */
2281 	    4, 0,	/* tpscnt tdscnt */
2282 	    4, pos, 0,	/* pscnt psoff psdisp */
2283 	    0, 0, 0,	/* dscnt dsoff dsdisp */
2284 	    0,		/* suwcnt */
2285 	    4,		/* bcc */
2286 	    rc,
2287 	    0);		/* converter word? */
2288 	return (SDRC_NORMAL_REPLY);
2289 }
2290 
2291 smb_xa_t *
2292 smb_xa_create(
2293     smb_session_t	*session,
2294     smb_request_t	*sr,
2295     uint32_t		total_parameter_count,
2296     uint32_t		total_data_count,
2297     uint32_t		max_parameter_count,
2298     uint32_t		max_data_count,
2299     uint32_t		max_setup_count,
2300     uint32_t		setup_word_count)
2301 {
2302 	smb_xa_t	*xa, *nxa;
2303 	smb_llist_t	*xlist;
2304 
2305 	xa = MEM_ZALLOC("xa", sizeof (smb_xa_t));
2306 	xa->xa_refcnt = 1;
2307 	xa->smb_com = sr->smb_com;
2308 	xa->smb_flg = sr->smb_flg;
2309 	xa->smb_flg2 = sr->smb_flg2;
2310 	xa->smb_tid = sr->smb_tid;
2311 	xa->smb_pid = sr->smb_pid;
2312 	xa->smb_uid = sr->smb_uid;
2313 	xa->xa_smb_mid = sr->smb_mid;
2314 	xa->reply_seqnum = sr->reply_seqnum;
2315 	xa->smb_tpscnt = total_parameter_count;
2316 	xa->smb_tdscnt = total_data_count;
2317 	xa->smb_mprcnt = max_parameter_count;
2318 	xa->smb_mdrcnt = max_data_count;
2319 	xa->smb_msrcnt = max_setup_count;
2320 	xa->smb_suwcnt = setup_word_count;
2321 	xa->xa_session = session;
2322 	xa->xa_magic = SMB_XA_MAGIC;
2323 
2324 	/*
2325 	 * The new xa structure is checked against the current list to see
2326 	 * if it exists already.
2327 	 */
2328 	xlist = &session->s_xa_list;
2329 	smb_llist_enter(xlist, RW_WRITER);
2330 	nxa = smb_llist_head(xlist);
2331 	while (nxa) {
2332 		ASSERT(nxa->xa_magic == SMB_XA_MAGIC);
2333 		if (nxa->xa_smb_mid == xa->xa_smb_mid &&
2334 		    nxa->smb_pid == xa->smb_pid &&
2335 		    !SMB_XA_CLOSED(nxa) &&
2336 		    !(nxa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
2337 			smb_llist_exit(xlist);
2338 			MEM_FREE("xa", xa);
2339 			return (NULL);
2340 		}
2341 		nxa = smb_llist_next(xlist, nxa);
2342 	}
2343 	smb_llist_insert_tail(xlist, xa);
2344 	smb_llist_exit(xlist);
2345 	return (xa);
2346 }
2347 
2348 void
2349 smb_xa_delete(smb_xa_t *xa)
2350 {
2351 	ASSERT(xa->xa_refcnt == 0);
2352 	ASSERT(SMB_XA_CLOSED(xa));
2353 
2354 	if (xa->xa_smb_trans_name)
2355 		MEM_FREE("smb", xa->xa_smb_trans_name);
2356 
2357 	if (xa->rep_setup_mb.chain != NULL)
2358 		m_freem(xa->rep_setup_mb.chain);
2359 	if (xa->rep_param_mb.chain != NULL)
2360 		m_freem(xa->rep_param_mb.chain);
2361 	if (xa->rep_data_mb.chain != NULL)
2362 		m_freem(xa->rep_data_mb.chain);
2363 
2364 	xa->xa_magic = (uint32_t)~SMB_XA_MAGIC;
2365 	MEM_FREE("xa", xa);
2366 }
2367 
2368 smb_xa_t *
2369 smb_xa_hold(smb_xa_t *xa)
2370 {
2371 	mutex_enter(&xa->xa_mutex);
2372 	xa->xa_refcnt++;
2373 	ASSERT(xa->xa_refcnt);
2374 	mutex_exit(&xa->xa_mutex);
2375 	return (xa);
2376 }
2377 
2378 void
2379 smb_xa_rele(smb_session_t *session, smb_xa_t *xa)
2380 {
2381 	mutex_enter(&xa->xa_mutex);
2382 	ASSERT(xa->xa_refcnt);
2383 	xa->xa_refcnt--;
2384 	if (SMB_XA_CLOSED(xa) && (xa->xa_refcnt == 0)) {
2385 		mutex_exit(&xa->xa_mutex);
2386 		smb_llist_enter(&session->s_xa_list, RW_WRITER);
2387 		smb_llist_remove(&session->s_xa_list, xa);
2388 		smb_llist_exit(&session->s_xa_list);
2389 		smb_xa_delete(xa);
2390 		return;
2391 	}
2392 	mutex_exit(&xa->xa_mutex);
2393 }
2394 
2395 int
2396 smb_xa_open(smb_xa_t *xa)
2397 {
2398 	int rc;
2399 
2400 	mutex_enter(&xa->xa_mutex);
2401 
2402 	ASSERT((xa->xa_flags & SMB_XA_FLAG_OPEN) == 0);
2403 
2404 	if ((xa->xa_flags & SMB_XA_FLAG_CLOSE) == 0) {
2405 		xa->xa_flags |= SMB_XA_FLAG_OPEN;
2406 		rc = 0;
2407 	} else {
2408 		rc = ERROR_INVALID_HANDLE;
2409 	}
2410 
2411 	mutex_exit(&xa->xa_mutex);
2412 
2413 	return (rc);
2414 }
2415 
2416 void
2417 smb_xa_close(smb_xa_t *xa)
2418 {
2419 	mutex_enter(&xa->xa_mutex);
2420 	xa->xa_flags |= SMB_XA_FLAG_CLOSE;
2421 	xa->xa_flags &= ~SMB_XA_FLAG_OPEN;
2422 
2423 	if (xa->xa_refcnt == 0) {
2424 		mutex_exit(&xa->xa_mutex);
2425 		smb_llist_enter(&xa->xa_session->s_xa_list, RW_WRITER);
2426 		smb_llist_remove(&xa->xa_session->s_xa_list, xa);
2427 		smb_llist_exit(&xa->xa_session->s_xa_list);
2428 		smb_xa_delete(xa);
2429 		return;
2430 	}
2431 
2432 	mutex_exit(&xa->xa_mutex);
2433 }
2434 
2435 int
2436 smb_xa_complete(smb_xa_t *xa)
2437 {
2438 	int rc;
2439 
2440 	mutex_enter(&xa->xa_mutex);
2441 	if (xa->xa_flags & (SMB_XA_FLAG_COMPLETE | SMB_XA_FLAG_CLOSE)) {
2442 		rc = 0;
2443 	} else {
2444 		rc = 1;
2445 		xa->xa_flags |= SMB_XA_FLAG_COMPLETE;
2446 	}
2447 	mutex_exit(&xa->xa_mutex);
2448 	return (rc);
2449 }
2450 
2451 smb_xa_t *
2452 smb_xa_find(
2453     smb_session_t	*session,
2454     uint16_t		pid,
2455     uint16_t		mid)
2456 {
2457 	smb_xa_t	*xa;
2458 	smb_llist_t	*xlist;
2459 
2460 	xlist = &session->s_xa_list;
2461 	smb_llist_enter(xlist, RW_READER);
2462 	xa = smb_llist_head(xlist);
2463 	while (xa) {
2464 		mutex_enter(&xa->xa_mutex);
2465 		if (xa->xa_smb_mid == mid &&
2466 		    xa->smb_pid == pid &&
2467 		    !SMB_XA_CLOSED(xa) &&
2468 		    !(xa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
2469 			xa->xa_refcnt++;
2470 			ASSERT(xa->xa_refcnt);
2471 			mutex_exit(&xa->xa_mutex);
2472 			break;
2473 		}
2474 		mutex_exit(&xa->xa_mutex);
2475 		xa = smb_llist_next(xlist, xa);
2476 	}
2477 	smb_llist_exit(xlist);
2478 	return (xa);
2479 }
2480