xref: /onnv-gate/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_transact.c (revision 8334:5f1c6a3b0fad)
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  * SMB transaction functions.
28  */
29 
30 #include <syslog.h>
31 #include <strings.h>
32 
33 #include <smbsrv/libsmbrdr.h>
34 #include <smbsrv/ntstatus.h>
35 #include <smbsrv/smb.h>
36 #include <smbrdr.h>
37 
38 /*
39  * The pipe filename, length (including the null terminator)
40  * and the buffer size for the transaction. Moving to unicode
41  * revealed that the length should not include the null.
42  */
43 #define	TX_FILENAME		"\\PIPE\\"
44 #define	TX_FILENAME_ASCII_LEN	6
45 #define	TX_FILENAME_WCHAR_LEN	14
46 
47 
48 static int prep_smb_transact(smb_msgbuf_t *, unsigned short, char *,
49     unsigned short, unsigned short, unsigned);
50 static int decode_smb_transact(smb_msgbuf_t *, char *, unsigned,
51     smb_transact_rsp_t *);
52 
53 /*
54  * smbrdr_transact
55  *
56  * Send a SMB_COM_TRANSACTION request.
57  */
58 int
59 smbrdr_transact(int fid, char *out_buf, int out_len, char *in_buf, int in_len)
60 {
61 	struct sdb_session *session;
62 	struct sdb_netuse *netuse;
63 	struct sdb_ofile *ofile;
64 	struct sdb_logon *logon;
65 	smb_transact_rsp_t rsp;
66 	smbrdr_handle_t srh;
67 	smb_msgbuf_t *mb;
68 	DWORD status;
69 	int rc;
70 	unsigned short rcv_dcnt;
71 	int cur_inlen;
72 	int first_rsp;
73 
74 	if ((ofile = smbrdr_ofile_get(fid)) == 0)
75 		return (-1);
76 
77 	netuse = ofile->netuse;
78 	session = netuse->session;
79 	logon = &session->logon;
80 
81 	status = smbrdr_request_init(&srh, SMB_COM_TRANSACTION,
82 	    session, logon, netuse);
83 
84 	if (status != NT_STATUS_SUCCESS) {
85 		syslog(LOG_DEBUG, "smbrdr_transact: %s",
86 		    xlate_nt_status(status));
87 		smbrdr_ofile_put(ofile);
88 		return (-1);
89 	}
90 
91 	mb = &srh.srh_mbuf;
92 
93 	rc = prep_smb_transact(mb, ofile->fid, out_buf, out_len, in_len,
94 	    session->remote_caps & CAP_UNICODE);
95 	if (rc < 0) {
96 		syslog(LOG_DEBUG, "smbrdr_transact: prep failed");
97 		smbrdr_handle_free(&srh);
98 		smbrdr_ofile_put(ofile);
99 		return (rc);
100 	}
101 
102 	smbrdr_lock_transport();
103 
104 	status = smbrdr_send(&srh);
105 	if (status != NT_STATUS_SUCCESS) {
106 		smbrdr_unlock_transport();
107 		smbrdr_handle_free(&srh);
108 		smbrdr_ofile_put(ofile);
109 		syslog(LOG_DEBUG, "smbrdr_transact: send failed");
110 		return (-1);
111 	}
112 
113 	rcv_dcnt = 0;
114 	cur_inlen = in_len;
115 	first_rsp = 1;
116 
117 	do {
118 		if (smbrdr_rcv(&srh, first_rsp) != NT_STATUS_SUCCESS) {
119 			syslog(LOG_DEBUG, "smbrdr_transact: nb_rcv failed");
120 			rc = -1;
121 			break;
122 		}
123 
124 		rc = decode_smb_transact(mb, in_buf, cur_inlen, &rsp);
125 		if (rc < 0 || rsp.TotalDataCount > in_len) {
126 			syslog(LOG_DEBUG,
127 			    "smbrdr_transact: decode failed");
128 			rc = -1;
129 			break;
130 		}
131 
132 		rcv_dcnt += rsp.DataCount;
133 		cur_inlen -= rsp.DataCount;
134 		first_rsp = 0;
135 
136 	} while (rcv_dcnt < rsp.TotalDataCount);
137 
138 	smbrdr_unlock_transport();
139 	smbrdr_handle_free(&srh);
140 	smbrdr_ofile_put(ofile);
141 
142 	return ((rc < 0) ? rc : rcv_dcnt);
143 }
144 
145 
146 /*
147  * prep_smb_transact
148  *
149  * Prepare the SMB_COM_TRANSACTION request.
150  */
151 static int
152 prep_smb_transact(smb_msgbuf_t *mb, unsigned short fid, char *out,
153     unsigned short out_len, unsigned short in_max, unsigned unicode)
154 {
155 	int data_off;
156 	int rc;
157 	unsigned short bcc;
158 
159 	/*
160 	 * The byte count seems to include the pad
161 	 * byte to word align the filename and two
162 	 * spurious pad bytes between the filename
163 	 * and the transaction data.
164 	 */
165 	bcc = out_len + 3;
166 	bcc += (unicode) ? TX_FILENAME_WCHAR_LEN : TX_FILENAME_ASCII_LEN;
167 
168 	data_off  = 32;		/* sizeof SMB header up to smb_wct */
169 	data_off += 1;		/* sizeof smb_wct */
170 	data_off += 16*2;	/* sizeof word parameters */
171 	data_off += 2;		/* sizeof smb_bcc */
172 	data_off += (unicode) ? TX_FILENAME_WCHAR_LEN : TX_FILENAME_ASCII_LEN;
173 	data_off += 3;
174 	/* this is where data starts */
175 
176 	rc = smb_msgbuf_encode(mb,
177 	    "(wct)b"
178 	    "(tpscnt)w (tdscnt)w (mprcnt)w (mdrcnt)w (msrcnt)b"
179 	    "(rsvd). (flags)w (timeo)l  (rsvd1)2."
180 	    "(pscnt)w (psoff)w (dscnt)w (dsoff)w (suwcnt)b"
181 	    "(rsvd2). (pipop)w (fid)w (bcc)w (fname)u",
182 	    16,				/* smb_wct */
183 	    0,				/* total parm bytes */
184 	    out_len,			/* total data bytes */
185 	    0,				/* max parm bytes to ret */
186 	    in_max,			/* max data bytes to ret */
187 	    0,				/* max setup words to ret */
188 	    0,				/* transact flags */
189 	    0,				/* transact timeout */
190 	    0,				/* parameter bytes */
191 	    data_off,			/* parameter offset */
192 	    out_len,			/* data bytes */
193 	    data_off,			/* data offset */
194 	    2,				/* total setup words */
195 	    0x0026,			/* OP=TransactNmPipe */
196 	    fid,			/* FID */
197 	    bcc,			/* byte count */
198 	    TX_FILENAME);		/* file name */
199 
200 	/*
201 	 * Transaction data - padded.
202 	 */
203 	rc = smb_msgbuf_encode(mb, "..#c", out_len, out);
204 	return (rc);
205 }
206 
207 
208 /*
209  * decode_smb_transact
210  *
211  * Decode the response from the SMB_COM_TRANSACTION request.
212  */
213 static int
214 decode_smb_transact(smb_msgbuf_t *mb, char *in, unsigned in_len,
215     smb_transact_rsp_t *rsp)
216 {
217 	int rc;
218 
219 	rc = smb_msgbuf_decode(mb, "b", &rsp->WordCount);
220 	if (rc <= 0 || rsp->WordCount < 10) {
221 		return (-1);
222 	}
223 
224 	rc = smb_msgbuf_decode(mb,
225 	    "(tpscnt)w (tdscnt)w (rsvd)2."
226 	    "(pscnt)w (psoff)w (psdisp)w (dscnt)w (dsoff)w"
227 	    "(dsdisp)w (suwcnt)b (rsvd). (bcc)w",
228 	    &rsp->TotalParamCount,		/* Total parm bytes */
229 	    &rsp->TotalDataCount,		/* Total data bytes */
230 	    &rsp->ParamCount,			/* Parm bytes this buffer */
231 	    &rsp->ParamOffset,			/* Parm offset from hdr */
232 	    &rsp->ParamDisplacement,		/* Parm displacement */
233 	    &rsp->DataCount,			/* Data bytes this buffer */
234 	    &rsp->DataOffset,			/* Data offset from hdr */
235 	    &rsp->DataDisplacement,		/* Data displacement */
236 	    &rsp->SetupCount,			/* Setup word count */
237 	    &rsp->BCC);				/* smb_bcc */
238 
239 	if (rc <= 0)
240 		return (-1);
241 
242 	if (rsp->DataCount > in_len)
243 		return (-1);
244 
245 	bcopy(mb->base + rsp->DataOffset,
246 	    in + rsp->DataDisplacement, rsp->DataCount);
247 
248 	return (0);
249 }
250