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