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