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 */
25
26 /*
27 * SMB ReadX functions.
28 */
29
30 #include <strings.h>
31
32 #include <smbsrv/libsmbrdr.h>
33 #include <smbsrv/netbios.h>
34 #include <smbrdr.h>
35
36 #define SMBRDR_READX_RSP_OVERHEAD \
37 (NETBIOS_HDR_SZ + SMB_HEADER_LEN + sizeof (smb_read_andx_rsp_t))
38 #define SMBRDR_READX_RSP_DATA_MAXLEN \
39 (SMBRDR_REQ_BUFSZ - SMBRDR_READX_RSP_OVERHEAD)
40
41 static int smbrdr_decode_readx_rsp(smb_msgbuf_t *, char *, unsigned,
42 smb_read_andx_rsp_t *);
43
44 /*
45 * smbrdr_readx
46 *
47 * Send SMB_COM_READ_ANDX request.
48 */
49 int
smbrdr_readx(int fid,char * in_buf,int in_len)50 smbrdr_readx(int fid, char *in_buf, int in_len)
51 {
52 struct sdb_netuse *netuse;
53 struct sdb_ofile *ofile;
54 smb_read_andx_rsp_t rsp;
55 smbrdr_handle_t srh;
56 smb_msgbuf_t *mb;
57 DWORD status;
58 int rc, max_return;
59
60 if ((ofile = smbrdr_ofile_get(fid)) == NULL)
61 return (-1);
62
63 netuse = ofile->netuse;
64
65 status = smbrdr_request_init(&srh, SMB_COM_READ_ANDX,
66 netuse->session, &netuse->session->logon, netuse);
67
68 if (status != NT_STATUS_SUCCESS) {
69 smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_readx: %s",
70 xlate_nt_status(status));
71 smbrdr_ofile_put(ofile);
72 return (-1);
73 }
74
75 mb = &(srh.srh_mbuf);
76
77 max_return = (in_len > SMBRDR_READX_RSP_DATA_MAXLEN) ?
78 SMBRDR_READX_RSP_DATA_MAXLEN : in_len;
79
80 rc = smb_msgbuf_encode(mb, "bbbwwlwwlwlw",
81 12, /* Count of parameter words */
82 0xFF, /* Secondary (X) command; 0xFF = none */
83 0, /* Reserved (must be 0) */
84 0, /* Offset to next command WordCount */
85 ofile->fid, /* File handle */
86 0, /* Offset in file to begin read */
87 max_return, /* Max number of bytes to return */
88 /* Reserved for obsolescent requests [0 = non-blocking read] */
89 max_return,
90 /*
91 * High 16 bits of MaxCount if CAP_LARGE_READX;
92 * else MUST BE ZERO
93 */
94 0,
95 max_return, /* Reserved for obsolescent requests */
96 /* Upper 32 bits of offset (only if WordCount is 12) */
97 0,
98 0); /* Count of data bytes = 0 */
99
100 if (rc < 0) {
101 smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_readx: prep failed");
102 smbrdr_handle_free(&srh);
103 smbrdr_ofile_put(ofile);
104 return (rc);
105 }
106
107 smbrdr_lock_transport();
108
109 status = smbrdr_send(&srh);
110 if (status != NT_STATUS_SUCCESS) {
111 smbrdr_unlock_transport();
112 smbrdr_handle_free(&srh);
113 smbrdr_ofile_put(ofile);
114 smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_readx: send failed");
115 return (-1);
116 }
117
118 status = smbrdr_rcv(&srh, 1);
119
120 if (status != NT_STATUS_SUCCESS) {
121 smb_log(smbrdr_log_hdl, LOG_DEBUG,
122 "smbrdr_readx: nb_rcv failed");
123 smbrdr_unlock_transport();
124 smbrdr_handle_free(&srh);
125 smbrdr_ofile_put(ofile);
126 return (-1);
127 }
128
129 rc = smbrdr_decode_readx_rsp(mb, in_buf, in_len, &rsp);
130
131 if (rc < 0) {
132 smb_log(smbrdr_log_hdl, LOG_DEBUG,
133 "smbrdr_readx: decode failed");
134 smbrdr_unlock_transport();
135 smbrdr_handle_free(&srh);
136 smbrdr_ofile_put(ofile);
137 return (-1);
138 }
139
140 smbrdr_unlock_transport();
141 smbrdr_handle_free(&srh);
142 smbrdr_ofile_put(ofile);
143
144 return ((rc < 0) ? rc : rsp.DataLength);
145 }
146
147 /*
148 * smbrdr_decode_readx_rsp
149 *
150 * Decode the response from the SMB_COM_READ_ANDX request. The payload
151 * of the response is appended to the end of SmbTransact response data
152 * in the RPC receive buffer.
153 *
154 * Return -1 on error, 0 upon success.
155 */
156 static int
smbrdr_decode_readx_rsp(smb_msgbuf_t * mb,char * in,unsigned in_len,smb_read_andx_rsp_t * rsp)157 smbrdr_decode_readx_rsp(smb_msgbuf_t *mb,
158 char *in,
159 unsigned in_len,
160 smb_read_andx_rsp_t *rsp)
161 {
162 int rc;
163
164 rc = smb_msgbuf_decode(mb, "bbbwwwwwwlwwww",
165 &rsp->WordCount,
166 &rsp->AndXCmd,
167 &rsp->AndXReserved,
168 &rsp->AndXOffset,
169 &rsp->Remaining,
170 &rsp->DataCompactionMode,
171 &rsp->Reserved,
172 &rsp->DataLength,
173 &rsp->DataOffset,
174 &rsp->DataLengthHigh,
175 &rsp->Reserved2[0],
176 &rsp->Reserved2[1],
177 &rsp->Reserved2[2],
178 &rsp->ByteCount);
179
180 if (rc <= 0)
181 return (-1);
182
183 if (rsp->DataLength > in_len)
184 return (-1);
185
186 bcopy(mb->base + rsp->DataOffset, in, rsp->DataLength);
187
188 return (0);
189 }
190