1adee6784SGordon Ross /*
2adee6784SGordon Ross * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
3adee6784SGordon Ross *
4adee6784SGordon Ross * @APPLE_LICENSE_HEADER_START@
5adee6784SGordon Ross *
6adee6784SGordon Ross * This file contains Original Code and/or Modifications of Original Code
7adee6784SGordon Ross * as defined in and that are subject to the Apple Public Source License
8adee6784SGordon Ross * Version 2.0 (the 'License'). You may not use this file except in
9adee6784SGordon Ross * compliance with the License. Please obtain a copy of the License at
10adee6784SGordon Ross * http://www.opensource.apple.com/apsl/ and read it before using this
11adee6784SGordon Ross * file.
12adee6784SGordon Ross *
13adee6784SGordon Ross * The Original Code and all software distributed under the License are
14adee6784SGordon Ross * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15adee6784SGordon Ross * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16adee6784SGordon Ross * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17adee6784SGordon Ross * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18adee6784SGordon Ross * Please see the License for the specific language governing rights and
19adee6784SGordon Ross * limitations under the License.
20adee6784SGordon Ross *
21adee6784SGordon Ross * @APPLE_LICENSE_HEADER_END@
22adee6784SGordon Ross */
23adee6784SGordon Ross
24adee6784SGordon Ross /*
25adee6784SGordon Ross * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
26adee6784SGordon Ross */
27adee6784SGordon Ross
28adee6784SGordon Ross #include <sys/param.h>
29adee6784SGordon Ross #include <sys/systm.h>
30adee6784SGordon Ross #include <sys/kmem.h>
31adee6784SGordon Ross #include <sys/proc.h>
32adee6784SGordon Ross #include <sys/lock.h>
33adee6784SGordon Ross #include <sys/socket.h>
34adee6784SGordon Ross #include <sys/uio.h>
35adee6784SGordon Ross #include <sys/random.h>
36adee6784SGordon Ross #include <sys/note.h>
37adee6784SGordon Ross #include <sys/errno.h>
38adee6784SGordon Ross #include <sys/cmn_err.h>
39adee6784SGordon Ross
40adee6784SGordon Ross #include <smb/ntaccess.h>
41adee6784SGordon Ross #include <smb/winioctl.h>
42adee6784SGordon Ross
43adee6784SGordon Ross #include <netsmb/smb_osdep.h>
44adee6784SGordon Ross
45adee6784SGordon Ross #include <netsmb/smb.h>
46adee6784SGordon Ross #include <netsmb/smb2.h>
47adee6784SGordon Ross #include <netsmb/smb_conn.h>
48adee6784SGordon Ross #include <netsmb/smb_subr.h>
49adee6784SGordon Ross #include <netsmb/smb_tran.h>
50adee6784SGordon Ross #include <netsmb/smb_rq.h>
51adee6784SGordon Ross #include <netsmb/smb2_rq.h>
52adee6784SGordon Ross
53*686670eaSGordon Ross /*
54*686670eaSGordon Ross * Supported dialects. Keep sorted by number because of how the
55*686670eaSGordon Ross * vc_maxver check below may truncate this list.
56*686670eaSGordon Ross */
57*686670eaSGordon Ross #define NDIALECTS 3
58*686670eaSGordon Ross static const uint16_t smb2_dialects[NDIALECTS] = {
59*686670eaSGordon Ross SMB2_DIALECT_0210,
60*686670eaSGordon Ross SMB2_DIALECT_0300,
61*686670eaSGordon Ross SMB2_DIALECT_0302,
62adee6784SGordon Ross };
63adee6784SGordon Ross
64adee6784SGordon Ross /* Optional capabilities we advertise (none yet). */
65adee6784SGordon Ross uint32_t smb2_clnt_caps = 0;
66adee6784SGordon Ross
67adee6784SGordon Ross /* How many credits to ask for during ssn. setup. */
68adee6784SGordon Ross uint16_t smb2_ss_req_credits = 64;
69adee6784SGordon Ross
70adee6784SGordon Ross /*
71adee6784SGordon Ross * Default timeout values, all in seconds.
72adee6784SGordon Ross * Make these tunable (only via mdb for now).
73adee6784SGordon Ross */
74adee6784SGordon Ross int smb2_timo_notice = 15;
75adee6784SGordon Ross int smb2_timo_default = 30;
76adee6784SGordon Ross int smb2_timo_logon = 45;
77adee6784SGordon Ross int smb2_timo_open = 45;
78adee6784SGordon Ross int smb2_timo_read = 45;
79adee6784SGordon Ross int smb2_timo_write = 60;
80adee6784SGordon Ross int smb2_timo_append = 90;
81adee6784SGordon Ross
82adee6784SGordon Ross /*
83adee6784SGordon Ross * This is a special handler for the odd SMB1-to-SMB2 negotiate
84adee6784SGordon Ross * response, where an SMB1 request gets an SMB2 response.
85adee6784SGordon Ross *
86adee6784SGordon Ross * Unlike most parse functions here, this needs to parse both
87adee6784SGordon Ross * the SMB2 header and the nego. response body. Note that
88adee6784SGordon Ross * the only "SMB2" dialect our SMB1 negotiate offered was
89adee6784SGordon Ross * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid
90adee6784SGordon Ross * SMB2 dialect we should get is: SMB2_DIALECT_02ff
91adee6784SGordon Ross */
92adee6784SGordon Ross int
smb2_parse_smb1nego_resp(struct smb_rq * rqp)93adee6784SGordon Ross smb2_parse_smb1nego_resp(struct smb_rq *rqp)
94adee6784SGordon Ross {
95adee6784SGordon Ross struct smb_vc *vcp = rqp->sr_vc;
96adee6784SGordon Ross struct smb_sopt *sp = &vcp->vc_sopt;
97adee6784SGordon Ross struct mdchain *mdp;
98adee6784SGordon Ross uint16_t length = 0;
99adee6784SGordon Ross int error;
100adee6784SGordon Ross
101adee6784SGordon Ross /* Get pointer to response data */
102adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
103adee6784SGordon Ross
104adee6784SGordon Ross error = smb2_rq_parsehdr(rqp);
105adee6784SGordon Ross if (error != 0)
106adee6784SGordon Ross return (error);
107adee6784SGordon Ross
108adee6784SGordon Ross /*
109adee6784SGordon Ross * Parse SMB 2/3 Negotiate Response
110adee6784SGordon Ross * We are already pointing to begining of Response data
111adee6784SGordon Ross */
112adee6784SGordon Ross
113adee6784SGordon Ross /* Check structure size is 65 */
114adee6784SGordon Ross md_get_uint16le(mdp, &length);
115adee6784SGordon Ross if (length != 65)
116adee6784SGordon Ross return (EBADRPC);
117adee6784SGordon Ross
118adee6784SGordon Ross /* Get Security Mode */
119adee6784SGordon Ross md_get_uint16le(mdp, &sp->sv2_security_mode);
120adee6784SGordon Ross
121adee6784SGordon Ross /* Get Dialect. */
122*686670eaSGordon Ross error = md_get_uint16le(mdp, &sp->sv_proto);
123adee6784SGordon Ross if (error != 0)
124adee6784SGordon Ross return (error);
125adee6784SGordon Ross
126adee6784SGordon Ross /* What dialect did we get? */
127*686670eaSGordon Ross if (sp->sv_proto != SMB2_DIALECT_02ff) {
128*686670eaSGordon Ross SMBERROR("Unknown dialect 0x%x\n", sp->sv_proto);
129adee6784SGordon Ross return (EINVAL);
130adee6784SGordon Ross }
131adee6784SGordon Ross /* Set our (internal) SMB1 dialect also. */
132adee6784SGordon Ross sp->sv_proto = SMB_DIALECT_SMB2_FF;
133adee6784SGordon Ross
134adee6784SGordon Ross /*
135adee6784SGordon Ross * This request did not go through smb2_iod_addrq and
136adee6784SGordon Ross * smb2_iod_process() so the SMB2 message ID state is
137adee6784SGordon Ross * behind what we need it to be. Fix that.
138adee6784SGordon Ross */
139adee6784SGordon Ross vcp->vc2_next_message_id = 1;
140adee6784SGordon Ross vcp->vc2_limit_message_id = 2;
141adee6784SGordon Ross
142adee6784SGordon Ross /*
143adee6784SGordon Ross * Skip parsing the rest. We'll get a normal
144adee6784SGordon Ross * SMB2 negotiate next and do negotiate then.
145adee6784SGordon Ross */
146adee6784SGordon Ross return (0);
147adee6784SGordon Ross }
148adee6784SGordon Ross
149adee6784SGordon Ross int
smb2_smb_negotiate(struct smb_vc * vcp,struct smb_cred * scred)150adee6784SGordon Ross smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
151adee6784SGordon Ross {
152adee6784SGordon Ross smb_sopt_t *sp = &vcp->vc_sopt;
153adee6784SGordon Ross smbioc_ssn_work_t *wk = &vcp->vc_work;
154adee6784SGordon Ross struct smb_rq *rqp = NULL;
155adee6784SGordon Ross struct mbchain *mbp = NULL;
156adee6784SGordon Ross struct mdchain *mdp = NULL;
157*686670eaSGordon Ross uint16_t *ndialects_p;
158adee6784SGordon Ross uint16_t ndialects = NDIALECTS;
159adee6784SGordon Ross boolean_t will_sign = B_FALSE;
160adee6784SGordon Ross uint16_t length = 0;
161adee6784SGordon Ross uint16_t security_mode;
162adee6784SGordon Ross uint16_t sec_buf_off;
163adee6784SGordon Ross uint16_t sec_buf_len;
164adee6784SGordon Ross int err, i;
165adee6784SGordon Ross
166adee6784SGordon Ross /*
167adee6784SGordon Ross * Compute security mode
168adee6784SGordon Ross */
169adee6784SGordon Ross if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
170adee6784SGordon Ross security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
171adee6784SGordon Ross } else {
172adee6784SGordon Ross security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
173adee6784SGordon Ross }
174adee6784SGordon Ross
175adee6784SGordon Ross err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp);
176adee6784SGordon Ross if (err)
177adee6784SGordon Ross return (err);
178adee6784SGordon Ross
179adee6784SGordon Ross /*
180adee6784SGordon Ross * Build the SMB2 negotiate request.
181adee6784SGordon Ross */
182adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
183adee6784SGordon Ross mb_put_uint16le(mbp, 36); /* Struct Size */
184*686670eaSGordon Ross ndialects_p = mb_reserve(mbp, 2); /* Dialect Count */
185adee6784SGordon Ross mb_put_uint16le(mbp, security_mode);
186adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Reserved */
187adee6784SGordon Ross mb_put_uint32le(mbp, smb2_clnt_caps);
188adee6784SGordon Ross mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
189adee6784SGordon Ross mb_put_uint64le(mbp, 0); /* Start Time */
190adee6784SGordon Ross for (i = 0; i < ndialects; i++) { /* Dialects */
191*686670eaSGordon Ross if (smb2_dialects[i] > vcp->vc_maxver)
192*686670eaSGordon Ross break;
193adee6784SGordon Ross mb_put_uint16le(mbp, smb2_dialects[i]);
194adee6784SGordon Ross }
195*686670eaSGordon Ross *ndialects_p = htoles(i);
196adee6784SGordon Ross
197adee6784SGordon Ross /*
198adee6784SGordon Ross * Do the OTW call.
199adee6784SGordon Ross */
200adee6784SGordon Ross err = smb2_rq_internal(rqp, smb2_timo_default);
201adee6784SGordon Ross if (err) {
202adee6784SGordon Ross goto errout;
203adee6784SGordon Ross }
204adee6784SGordon Ross /* Should only get status success. */
205adee6784SGordon Ross if (rqp->sr_error != NT_STATUS_SUCCESS) {
206adee6784SGordon Ross err = ENOTSUP;
207adee6784SGordon Ross goto errout;
208adee6784SGordon Ross }
209adee6784SGordon Ross
210adee6784SGordon Ross /*
211adee6784SGordon Ross * Decode the negotiate response
212adee6784SGordon Ross */
213adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
214adee6784SGordon Ross
215adee6784SGordon Ross md_get_uint16le(mdp, &length); /* Struct size */
216adee6784SGordon Ross if (length != 65) {
217adee6784SGordon Ross err = EBADRPC;
218adee6784SGordon Ross goto errout;
219adee6784SGordon Ross }
220adee6784SGordon Ross
221adee6784SGordon Ross md_get_uint16le(mdp, &sp->sv2_security_mode);
222*686670eaSGordon Ross md_get_uint16le(mdp, &sp->sv_proto); /* dialect */
223adee6784SGordon Ross md_get_uint16le(mdp, NULL); /* reserved */
224adee6784SGordon Ross md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
225adee6784SGordon Ross md_get_uint32le(mdp, &sp->sv2_capabilities);
226adee6784SGordon Ross md_get_uint32le(mdp, &sp->sv2_maxtransact);
227adee6784SGordon Ross md_get_uint32le(mdp, &sp->sv2_maxread);
228adee6784SGordon Ross md_get_uint32le(mdp, &sp->sv2_maxwrite);
229adee6784SGordon Ross md_get_uint64le(mdp, NULL); /* curr_time */
230adee6784SGordon Ross md_get_uint64le(mdp, NULL); /* boot_time */
231adee6784SGordon Ross
232adee6784SGordon Ross /* Get Security Blob offset and length */
233adee6784SGordon Ross md_get_uint16le(mdp, &sec_buf_off);
234adee6784SGordon Ross err = md_get_uint16le(mdp, &sec_buf_len);
235adee6784SGordon Ross if (err != 0)
236adee6784SGordon Ross goto errout;
237adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* reserved */
238adee6784SGordon Ross
239adee6784SGordon Ross /*
240adee6784SGordon Ross * Security buffer offset is from the beginning of SMB 2 Header
241adee6784SGordon Ross * Calculate how much further we have to go to get to it.
242adee6784SGordon Ross * Current offset is: SMB2_HDRLEN + 64
243adee6784SGordon Ross */
244adee6784SGordon Ross if (sec_buf_len != 0) {
245adee6784SGordon Ross int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64);
246adee6784SGordon Ross if (skip < 0) {
247adee6784SGordon Ross err = EBADRPC;
248adee6784SGordon Ross goto errout;
249adee6784SGordon Ross }
250adee6784SGordon Ross if (skip > 0) {
251adee6784SGordon Ross md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
252adee6784SGordon Ross }
253adee6784SGordon Ross
254adee6784SGordon Ross /*
255adee6784SGordon Ross * Copy the security blob out to user space.
256adee6784SGordon Ross * Buffer addr,size in vc_auth_rbuf,rlen
257adee6784SGordon Ross */
258adee6784SGordon Ross if (wk->wk_u_auth_rlen < sec_buf_len) {
259adee6784SGordon Ross SMBSDEBUG("vc_auth_rbuf too small");
260adee6784SGordon Ross /* Give caller required size. */
261adee6784SGordon Ross wk->wk_u_auth_rlen = sec_buf_len;
262adee6784SGordon Ross err = EMSGSIZE;
263adee6784SGordon Ross goto errout;
264adee6784SGordon Ross }
265adee6784SGordon Ross wk->wk_u_auth_rlen = sec_buf_len;
266adee6784SGordon Ross err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
267*686670eaSGordon Ross sec_buf_len, MB_MUSER);
268adee6784SGordon Ross if (err) {
269adee6784SGordon Ross goto errout;
270adee6784SGordon Ross }
271adee6784SGordon Ross }
272adee6784SGordon Ross
273adee6784SGordon Ross /*
274adee6784SGordon Ross * Decoded everything. Now decisions.
275adee6784SGordon Ross */
276adee6784SGordon Ross
277adee6784SGordon Ross /*
278adee6784SGordon Ross * Turn on signing if either Server or client requires it,
279adee6784SGordon Ross * except: anonymous sessions can't sign.
280adee6784SGordon Ross */
281adee6784SGordon Ross if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
282adee6784SGordon Ross (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED))
283adee6784SGordon Ross will_sign = B_TRUE;
284adee6784SGordon Ross if (vcp->vc_vopt & SMBVOPT_ANONYMOUS)
285adee6784SGordon Ross will_sign = B_FALSE;
286adee6784SGordon Ross SMBSDEBUG("Security signatures: %d", (int)will_sign);
287adee6784SGordon Ross if (will_sign)
288adee6784SGordon Ross vcp->vc_flags |= SMBV_SIGNING;
289adee6784SGordon Ross
290adee6784SGordon Ross /*
291adee6784SGordon Ross * ToDo - too many places are looking at sv_caps, so for now
292adee6784SGordon Ross * set the SMB1 capabilities too. Later we should use the
293adee6784SGordon Ross * sv2_capabilities for SMB 2+.
294adee6784SGordon Ross */
295adee6784SGordon Ross sp->sv_caps = (SMB_CAP_UNICODE |
296adee6784SGordon Ross SMB_CAP_LARGE_FILES |
297adee6784SGordon Ross SMB_CAP_STATUS32 |
298adee6784SGordon Ross SMB_CAP_LARGE_READX |
299adee6784SGordon Ross SMB_CAP_LARGE_WRITEX |
300adee6784SGordon Ross SMB_CAP_EXT_SECURITY);
301adee6784SGordon Ross if (sp->sv2_capabilities & SMB2_CAP_DFS)
302adee6784SGordon Ross sp->sv_caps |= SMB_CAP_DFS;
303adee6784SGordon Ross
304adee6784SGordon Ross /*
305adee6784SGordon Ross * A few sanity checks on what we received,
306adee6784SGordon Ross * becuse we will send these in ssnsetup.
307adee6784SGordon Ross *
308adee6784SGordon Ross * Maximum outstanding requests (we care),
309adee6784SGordon Ross * and Max. VCs (we only use one). Also,
310adee6784SGordon Ross * MaxBufferSize lower limit per spec.
311adee6784SGordon Ross */
312adee6784SGordon Ross if (sp->sv2_maxread < 0x8000) {
313adee6784SGordon Ross SMBSDEBUG("maxread too small\n");
314adee6784SGordon Ross err = ENOTSUP;
315adee6784SGordon Ross goto errout;
316adee6784SGordon Ross }
317adee6784SGordon Ross if (sp->sv2_maxwrite < 0x8000) {
318adee6784SGordon Ross SMBSDEBUG("maxwrite too small\n");
319adee6784SGordon Ross err = ENOTSUP;
320adee6784SGordon Ross goto errout;
321adee6784SGordon Ross }
322adee6784SGordon Ross if (sp->sv2_maxtransact < 0x4000) {
323adee6784SGordon Ross SMBSDEBUG("maxtransact too small\n");
324adee6784SGordon Ross err = ENOTSUP;
325adee6784SGordon Ross goto errout;
326adee6784SGordon Ross }
327adee6784SGordon Ross
328adee6784SGordon Ross /* Here too, fill SMB1 fields */
329adee6784SGordon Ross vcp->vc_rxmax = sp->sv2_maxread;
330adee6784SGordon Ross vcp->vc_wxmax = sp->sv2_maxwrite;
331adee6784SGordon Ross vcp->vc_txmax = sp->sv2_maxtransact;
332adee6784SGordon Ross
333adee6784SGordon Ross smb_rq_done(rqp);
334adee6784SGordon Ross return (0);
335adee6784SGordon Ross
336adee6784SGordon Ross errout:
337adee6784SGordon Ross smb_rq_done(rqp);
338adee6784SGordon Ross if (err == 0)
339adee6784SGordon Ross err = EBADRPC;
340adee6784SGordon Ross return (err);
341adee6784SGordon Ross }
342adee6784SGordon Ross
343adee6784SGordon Ross int
smb2_smb_ssnsetup(struct smb_vc * vcp,struct smb_cred * scred)344adee6784SGordon Ross smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
345adee6784SGordon Ross {
346adee6784SGordon Ross // smb_sopt_t *sv = &vcp->vc_sopt;
347adee6784SGordon Ross smbioc_ssn_work_t *wk = &vcp->vc_work;
348adee6784SGordon Ross struct smb_rq *rqp = NULL;
349adee6784SGordon Ross struct mbchain *mbp = NULL;
350adee6784SGordon Ross struct mdchain *mdp = NULL;
351adee6784SGordon Ross char *sb;
352adee6784SGordon Ross int err, ret;
353adee6784SGordon Ross uint16_t sblen;
354adee6784SGordon Ross uint16_t length = 0;
355adee6784SGordon Ross uint16_t session_flags;
356adee6784SGordon Ross uint16_t sec_buf_off;
357adee6784SGordon Ross uint16_t sec_buf_len;
358adee6784SGordon Ross uint8_t security_mode;
359adee6784SGordon Ross
360adee6784SGordon Ross /*
361adee6784SGordon Ross * Compute security mode
362adee6784SGordon Ross */
363adee6784SGordon Ross if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
364adee6784SGordon Ross security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
365adee6784SGordon Ross } else {
366adee6784SGordon Ross security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
367adee6784SGordon Ross }
368adee6784SGordon Ross
369adee6784SGordon Ross sb = wk->wk_u_auth_wbuf.lp_ptr;
370adee6784SGordon Ross sblen = (uint16_t)wk->wk_u_auth_wlen;
371adee6784SGordon Ross
372adee6784SGordon Ross err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp);
373adee6784SGordon Ross if (err != 0) {
374adee6784SGordon Ross ret = err;
375adee6784SGordon Ross goto out;
376adee6784SGordon Ross }
377adee6784SGordon Ross
378adee6784SGordon Ross /*
379adee6784SGordon Ross * Always ask for some credits. The server usually will
380adee6784SGordon Ross * only grant these credits once we've authenticated.
381adee6784SGordon Ross */
382adee6784SGordon Ross rqp->sr2_creditsrequested = smb2_ss_req_credits;
383adee6784SGordon Ross
384adee6784SGordon Ross /*
385adee6784SGordon Ross * Build the SMB Session Setup request.
386adee6784SGordon Ross */
387adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
388adee6784SGordon Ross
389adee6784SGordon Ross mb_put_uint16le(mbp, 25); /* Struct size */
390adee6784SGordon Ross mb_put_uint8(mbp, 0); /* VcNumber */
391adee6784SGordon Ross mb_put_uint8(mbp, security_mode);
392adee6784SGordon Ross mb_put_uint32le(mbp, smb2_clnt_caps); /* Capabilities */
393adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Channel - always 0 */
394adee6784SGordon Ross
395adee6784SGordon Ross /*
396adee6784SGordon Ross * Security buffer offset and length. Normally would use
397adee6784SGordon Ross * ptr = mb_reserve() and fill in later, but since only a
398adee6784SGordon Ross * small amount of fixed-size stuff follows (12 bytes)
399adee6784SGordon Ross * we can just compute the offset now.
400adee6784SGordon Ross */
401adee6784SGordon Ross mb_put_uint16le(mbp, mbp->mb_count + 12);
402adee6784SGordon Ross mb_put_uint16le(mbp, sblen);
403adee6784SGordon Ross mb_put_uint64le(mbp, vcp->vc2_prev_session_id);
404adee6784SGordon Ross err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
405adee6784SGordon Ross if (err != 0) {
406adee6784SGordon Ross ret = err;
407adee6784SGordon Ross goto out;
408adee6784SGordon Ross }
409adee6784SGordon Ross
410adee6784SGordon Ross /*
411adee6784SGordon Ross * Run the request. The return value here should be the
412adee6784SGordon Ross * return from this function, unless we fail decoding.
413adee6784SGordon Ross * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
414adee6784SGordon Ross * the caller expects EINPROGRESS for that case.
415adee6784SGordon Ross */
416adee6784SGordon Ross ret = smb2_rq_internal(rqp, smb2_timo_logon);
417adee6784SGordon Ross if (ret != 0)
418adee6784SGordon Ross goto out;
419adee6784SGordon Ross switch (rqp->sr_error) {
420adee6784SGordon Ross case NT_STATUS_SUCCESS:
421adee6784SGordon Ross break;
422adee6784SGordon Ross case NT_STATUS_MORE_PROCESSING_REQUIRED:
423adee6784SGordon Ross /* Keep going, but return... */
424adee6784SGordon Ross ret = EINPROGRESS;
425adee6784SGordon Ross break;
426adee6784SGordon Ross default:
427adee6784SGordon Ross ret = EAUTH;
428adee6784SGordon Ross goto out;
429adee6784SGordon Ross }
430adee6784SGordon Ross
431adee6784SGordon Ross /*
432adee6784SGordon Ross * After the first Session Setup Response,
433adee6784SGordon Ross * save the session ID.
434adee6784SGordon Ross */
435adee6784SGordon Ross if (vcp->vc2_session_id == 0)
436adee6784SGordon Ross vcp->vc2_session_id = rqp->sr2_rspsessionid;
437adee6784SGordon Ross
438adee6784SGordon Ross /*
439adee6784SGordon Ross * Decode the session setup response
440adee6784SGordon Ross */
441adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
442adee6784SGordon Ross
443adee6784SGordon Ross md_get_uint16le(mdp, &length); /* Struct size */
444adee6784SGordon Ross if (length != 9) {
445adee6784SGordon Ross ret = EBADRPC;
446adee6784SGordon Ross goto out;
447adee6784SGordon Ross }
448adee6784SGordon Ross
449adee6784SGordon Ross md_get_uint16le(mdp, &session_flags);
450adee6784SGordon Ross md_get_uint16le(mdp, &sec_buf_off);
451adee6784SGordon Ross err = md_get_uint16le(mdp, &sec_buf_len);
452adee6784SGordon Ross if (err != 0) {
453adee6784SGordon Ross ret = err;
454adee6784SGordon Ross goto out;
455adee6784SGordon Ross }
456adee6784SGordon Ross
457adee6784SGordon Ross /*
458adee6784SGordon Ross * Security buffer offset is from the beginning of SMB 2 Header
459adee6784SGordon Ross * Calculate how much further we have to go to get to it.
460adee6784SGordon Ross * Current offset is: SMB2_HDRLEN + 8
461adee6784SGordon Ross */
462adee6784SGordon Ross if (sec_buf_len != 0) {
463adee6784SGordon Ross int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8);
464adee6784SGordon Ross if (skip < 0) {
465adee6784SGordon Ross ret = EBADRPC;
466adee6784SGordon Ross goto out;
467adee6784SGordon Ross }
468adee6784SGordon Ross if (skip > 0) {
469adee6784SGordon Ross md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
470adee6784SGordon Ross }
471adee6784SGordon Ross
472adee6784SGordon Ross /*
473adee6784SGordon Ross * Copy the security blob out to user space.
474adee6784SGordon Ross * Buffer addr,size in vc_auth_rbuf,rlen
475adee6784SGordon Ross */
476adee6784SGordon Ross if (wk->wk_u_auth_rlen < sec_buf_len) {
477adee6784SGordon Ross SMBSDEBUG("vc_auth_rbuf too small");
478adee6784SGordon Ross /* Give caller required size. */
479adee6784SGordon Ross wk->wk_u_auth_rlen = sec_buf_len;
480adee6784SGordon Ross ret = EMSGSIZE;
481adee6784SGordon Ross goto out;
482adee6784SGordon Ross }
483adee6784SGordon Ross wk->wk_u_auth_rlen = sec_buf_len;
484adee6784SGordon Ross err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
485*686670eaSGordon Ross sec_buf_len, MB_MUSER);
486adee6784SGordon Ross if (err != 0) {
487adee6784SGordon Ross ret = err;
488adee6784SGordon Ross goto out;
489adee6784SGordon Ross }
490adee6784SGordon Ross }
491adee6784SGordon Ross
492adee6784SGordon Ross out:
493adee6784SGordon Ross if (err != 0 && err != EINPROGRESS) {
494adee6784SGordon Ross /* Session ID no longer valid. */
495adee6784SGordon Ross vcp->vc2_session_id = 0;
496adee6784SGordon Ross }
497adee6784SGordon Ross if (rqp)
498adee6784SGordon Ross smb_rq_done(rqp);
499adee6784SGordon Ross
500adee6784SGordon Ross return (ret);
501adee6784SGordon Ross }
502adee6784SGordon Ross
503adee6784SGordon Ross int
smb2_smb_logoff(struct smb_vc * vcp,struct smb_cred * scred)504adee6784SGordon Ross smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
505adee6784SGordon Ross {
506adee6784SGordon Ross struct smb_rq *rqp;
507adee6784SGordon Ross struct mbchain *mbp;
508adee6784SGordon Ross int error;
509adee6784SGordon Ross
510adee6784SGordon Ross if (vcp->vc2_session_id == 0)
511adee6784SGordon Ross return (0);
512adee6784SGordon Ross
513adee6784SGordon Ross error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp);
514adee6784SGordon Ross if (error)
515adee6784SGordon Ross return (error);
516adee6784SGordon Ross
517adee6784SGordon Ross /*
518adee6784SGordon Ross * Fill in Logoff part
519adee6784SGordon Ross */
520adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
521adee6784SGordon Ross mb_put_uint16le(mbp, 4); /* Struct size */
522adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Reserved */
523adee6784SGordon Ross
524adee6784SGordon Ross /*
525adee6784SGordon Ross * Run this with a relatively short timeout. (5 sec.)
526adee6784SGordon Ross * We don't really care about the result here.
527adee6784SGordon Ross * Also, don't reconnect for this, of course!
528adee6784SGordon Ross */
529adee6784SGordon Ross rqp->sr_flags |= SMBR_NORECONNECT;
530adee6784SGordon Ross error = smb2_rq_internal(rqp, 5);
531adee6784SGordon Ross smb_rq_done(rqp);
532adee6784SGordon Ross return (error);
533adee6784SGordon Ross }
534adee6784SGordon Ross
535adee6784SGordon Ross int
smb2_smb_treeconnect(struct smb_share * ssp,struct smb_cred * scred)536adee6784SGordon Ross smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
537adee6784SGordon Ross {
538adee6784SGordon Ross struct smb_vc *vcp;
539adee6784SGordon Ross struct smb_rq *rqp = NULL;
540adee6784SGordon Ross struct mbchain *mbp;
541adee6784SGordon Ross struct mdchain *mdp;
542adee6784SGordon Ross char *unc_name = NULL;
543adee6784SGordon Ross int error, unc_len;
544adee6784SGordon Ross uint16_t plen, *plenp;
545adee6784SGordon Ross uint16_t options = 0;
546adee6784SGordon Ross uint_t cnt0;
547adee6784SGordon Ross uint32_t net_stype;
548adee6784SGordon Ross uint16_t structure_size = 0;
549adee6784SGordon Ross uint8_t smb2stype;
550adee6784SGordon Ross
551adee6784SGordon Ross vcp = SSTOVC(ssp);
552adee6784SGordon Ross
553adee6784SGordon Ross /*
554adee6784SGordon Ross * Make this a "VC-level" request, so it will have
555adee6784SGordon Ross * rqp->sr_share == NULL, and smb_iod_sendrq()
556adee6784SGordon Ross * will send it with TID = SMB_TID_UNKNOWN
557adee6784SGordon Ross *
558adee6784SGordon Ross * This also serves to bypass the wait for
559adee6784SGordon Ross * share state changes, which this call is
560adee6784SGordon Ross * trying to carry out.
561adee6784SGordon Ross */
562adee6784SGordon Ross error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp);
563adee6784SGordon Ross if (error)
564adee6784SGordon Ross return (error);
565adee6784SGordon Ross
566adee6784SGordon Ross /*
567adee6784SGordon Ross * Build the UNC name, i.e. "//server/share"
568adee6784SGordon Ross * but with backslashes of course.
569adee6784SGordon Ross * size math: three slashes, one null.
570adee6784SGordon Ross */
571adee6784SGordon Ross unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
572adee6784SGordon Ross unc_name = kmem_alloc(unc_len, KM_SLEEP);
573adee6784SGordon Ross (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
574adee6784SGordon Ross vcp->vc_srvname, ssp->ss_name);
575adee6784SGordon Ross SMBSDEBUG("unc_name: \"%s\"", unc_name);
576adee6784SGordon Ross
577adee6784SGordon Ross /*
578adee6784SGordon Ross * Build the request.
579adee6784SGordon Ross */
580adee6784SGordon Ross mbp = &rqp->sr_rq;
581adee6784SGordon Ross
582adee6784SGordon Ross mb_put_uint16le(mbp, 9); /* Struct size */
583adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Reserved */
584adee6784SGordon Ross mb_put_uint16le(mbp, 72); /* Path Offset */
585adee6784SGordon Ross
586adee6784SGordon Ross /*
587adee6784SGordon Ross * Fill in path length after we put the string, so we know
588adee6784SGordon Ross * the length after conversion from UTF-8 to UCS-2.
589adee6784SGordon Ross */
590adee6784SGordon Ross plenp = mb_reserve(mbp, 2);
591adee6784SGordon Ross cnt0 = mbp->mb_count;
592adee6784SGordon Ross
593adee6784SGordon Ross /* UNC resource name (without the null) */
594adee6784SGordon Ross error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1,
595adee6784SGordon Ross SMB_CS_NONE, NULL);
596adee6784SGordon Ross if (error)
597adee6784SGordon Ross goto out;
598adee6784SGordon Ross
599adee6784SGordon Ross /* Now go back and fill in the path length. */
600adee6784SGordon Ross plen = (uint16_t)(mbp->mb_count - cnt0);
601adee6784SGordon Ross *plenp = htoles(plen);
602adee6784SGordon Ross
603adee6784SGordon Ross /*
604adee6784SGordon Ross * Run the request.
605adee6784SGordon Ross *
606adee6784SGordon Ross * Using NOINTR_RECV because we don't want to risk
607adee6784SGordon Ross * missing a successful tree connect response,
608adee6784SGordon Ross * which would "leak" Tree IDs.
609adee6784SGordon Ross */
610adee6784SGordon Ross rqp->sr_flags |= SMBR_NOINTR_RECV;
611adee6784SGordon Ross error = smb2_rq_simple(rqp);
612adee6784SGordon Ross SMBSDEBUG("%d\n", error);
613adee6784SGordon Ross if (error) {
614adee6784SGordon Ross /*
615adee6784SGordon Ross * If we get the server name wrong, i.e. due to
616adee6784SGordon Ross * mis-configured name services, this will be
617adee6784SGordon Ross * NT_STATUS_DUPLICATE_NAME. Log this error.
618adee6784SGordon Ross */
619adee6784SGordon Ross SMBERROR("(%s) failed, status=0x%x",
620adee6784SGordon Ross unc_name, rqp->sr_error);
621adee6784SGordon Ross goto out;
622adee6784SGordon Ross }
623adee6784SGordon Ross
624adee6784SGordon Ross /*
625adee6784SGordon Ross * Parse the tree connect response
626adee6784SGordon Ross */
627adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
628adee6784SGordon Ross
629adee6784SGordon Ross /* Check structure size is 16 */
630adee6784SGordon Ross md_get_uint16le(mdp, &structure_size);
631adee6784SGordon Ross if (structure_size != 16) {
632adee6784SGordon Ross error = EBADRPC;
633adee6784SGordon Ross goto out;
634adee6784SGordon Ross }
635adee6784SGordon Ross
636adee6784SGordon Ross md_get_uint8(mdp, &smb2stype);
637adee6784SGordon Ross md_get_uint8(mdp, NULL); /* reserved */
638adee6784SGordon Ross md_get_uint32le(mdp, &ssp->ss2_share_flags);
639adee6784SGordon Ross md_get_uint32le(mdp, &ssp->ss2_share_caps);
640adee6784SGordon Ross error = md_get_uint32le(mdp, NULL); /* maxAccessRights */
641adee6784SGordon Ross if (error)
642adee6784SGordon Ross goto out;
643adee6784SGordon Ross
644adee6784SGordon Ross /*
645adee6784SGordon Ross * Convert SMB2 share type to NetShareEnum share type
646adee6784SGordon Ross */
647adee6784SGordon Ross switch (smb2stype) {
648adee6784SGordon Ross case SMB2_SHARE_TYPE_DISK:
649adee6784SGordon Ross net_stype = STYPE_DISKTREE;
650adee6784SGordon Ross break;
651adee6784SGordon Ross case SMB2_SHARE_TYPE_PIPE:
652adee6784SGordon Ross net_stype = STYPE_IPC;
653adee6784SGordon Ross break;
654adee6784SGordon Ross case SMB2_SHARE_TYPE_PRINT:
655adee6784SGordon Ross net_stype = STYPE_PRINTQ;
656adee6784SGordon Ross break;
657adee6784SGordon Ross default:
658adee6784SGordon Ross net_stype = STYPE_UNKNOWN;
659adee6784SGordon Ross break;
660adee6784SGordon Ross }
661adee6784SGordon Ross ssp->ss_type = net_stype;
662adee6784SGordon Ross
663adee6784SGordon Ross /*
664adee6784SGordon Ross * Map SMB 2/3 capabilities to SMB 1 options,
665adee6784SGordon Ross * for common code that looks there.
666adee6784SGordon Ross */
667adee6784SGordon Ross if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS)
668adee6784SGordon Ross options |= SMB_SHARE_IS_IN_DFS;
669adee6784SGordon Ross
670adee6784SGordon Ross /* Update share state */
671adee6784SGordon Ross SMB_SS_LOCK(ssp);
672adee6784SGordon Ross ssp->ss2_tree_id = rqp->sr2_rsptreeid;
673adee6784SGordon Ross ssp->ss_vcgenid = vcp->vc_genid;
674adee6784SGordon Ross ssp->ss_options = options;
675adee6784SGordon Ross ssp->ss_flags |= SMBS_CONNECTED;
676adee6784SGordon Ross SMB_SS_UNLOCK(ssp);
677adee6784SGordon Ross
678adee6784SGordon Ross out:
679adee6784SGordon Ross if (unc_name)
680adee6784SGordon Ross kmem_free(unc_name, unc_len);
681adee6784SGordon Ross smb_rq_done(rqp);
682adee6784SGordon Ross return (error);
683adee6784SGordon Ross }
684adee6784SGordon Ross
685adee6784SGordon Ross int
smb2_smb_treedisconnect(struct smb_share * ssp,struct smb_cred * scred)686adee6784SGordon Ross smb2_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
687adee6784SGordon Ross {
688adee6784SGordon Ross struct smb_vc *vcp;
689adee6784SGordon Ross struct smb_rq *rqp;
690adee6784SGordon Ross struct mbchain *mbp;
691adee6784SGordon Ross int error;
692adee6784SGordon Ross
693adee6784SGordon Ross if (ssp->ss2_tree_id == SMB2_TID_UNKNOWN)
694adee6784SGordon Ross return (0);
695adee6784SGordon Ross
696adee6784SGordon Ross /*
697adee6784SGordon Ross * Build this as a "VC-level" request, so it will
698adee6784SGordon Ross * avoid testing the _GONE flag on the share,
699adee6784SGordon Ross * which has already been set at this point.
700adee6784SGordon Ross * Add the share pointer "by hand" below, so
701adee6784SGordon Ross * smb_iod_sendrq will plug in the TID.
702adee6784SGordon Ross */
703adee6784SGordon Ross vcp = SSTOVC(ssp);
704adee6784SGordon Ross error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_DISCONNECT, scred, &rqp);
705adee6784SGordon Ross if (error)
706adee6784SGordon Ross return (error);
707adee6784SGordon Ross rqp->sr_share = ssp; /* See "by hand" above. */
708adee6784SGordon Ross
709adee6784SGordon Ross /*
710adee6784SGordon Ross * Fill in SMB2 Tree Disconnect part
711adee6784SGordon Ross */
712adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
713adee6784SGordon Ross mb_put_uint16le(mbp, 4); /* Struct size */
714adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Reserved */
715adee6784SGordon Ross
716adee6784SGordon Ross /*
717adee6784SGordon Ross * Run this with a relatively short timeout. (5 sec.)
718adee6784SGordon Ross * We don't really care about the result here, but we
719adee6784SGordon Ross * do need to make sure we send this out, or we could
720adee6784SGordon Ross * "leak" active tree IDs on interrupt or timeout.
721adee6784SGordon Ross * The NOINTR_SEND flag makes this request immune to
722adee6784SGordon Ross * interrupt or timeout until the send is done.
723adee6784SGordon Ross * Also, don't reconnect for this, of course!
724adee6784SGordon Ross */
725adee6784SGordon Ross rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
726adee6784SGordon Ross error = smb2_rq_simple_timed(rqp, 5);
727adee6784SGordon Ross
728adee6784SGordon Ross smb_rq_done(rqp);
729adee6784SGordon Ross
730adee6784SGordon Ross /* Whether we get an error or not... */
731adee6784SGordon Ross ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
732adee6784SGordon Ross
733adee6784SGordon Ross return (error);
734adee6784SGordon Ross }
735adee6784SGordon Ross
736adee6784SGordon Ross /*
737adee6784SGordon Ross * Put the name, first skipping a leading slash.
738adee6784SGordon Ross */
739adee6784SGordon Ross static int
put_name_skip_slash(struct mbchain * mbp,struct mbchain * name_mbp)740adee6784SGordon Ross put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp)
741adee6784SGordon Ross {
742adee6784SGordon Ross mblk_t *m;
743adee6784SGordon Ross
744adee6784SGordon Ross if (name_mbp == NULL)
745adee6784SGordon Ross return (0);
746adee6784SGordon Ross m = name_mbp->mb_top;
747adee6784SGordon Ross if (m == NULL)
748adee6784SGordon Ross return (0);
749adee6784SGordon Ross
750adee6784SGordon Ross /* Use a dup of the message to leave the passed one untouched. */
751adee6784SGordon Ross m = dupmsg(m);
752adee6784SGordon Ross if (m == NULL)
753adee6784SGordon Ross return (ENOSR);
754adee6784SGordon Ross
755adee6784SGordon Ross if (MBLKL(m) >= 2 &&
756adee6784SGordon Ross m->b_rptr[0] == '\\' &&
757adee6784SGordon Ross m->b_rptr[1] == '\0')
758adee6784SGordon Ross m->b_rptr += 2;
759adee6784SGordon Ross
760adee6784SGordon Ross return (mb_put_mbuf(mbp, m));
761adee6784SGordon Ross }
762adee6784SGordon Ross
763adee6784SGordon Ross /*
764adee6784SGordon Ross * Modern create/open of file or directory.
765adee6784SGordon Ross *
766adee6784SGordon Ross * The passed name is a full path relative to the share root.
767adee6784SGordon Ross * Callers prepare paths with a leading slash (backslash)
768adee6784SGordon Ross * because that's what SMB1 expected. SMB2 does not allow the
769adee6784SGordon Ross * leading slash here. To make life simpler for callers skip a
770adee6784SGordon Ross * leading slash here. That allows callers use use common logic
771adee6784SGordon Ross * for building paths without needing to know if the connection
772adee6784SGordon Ross * is using SMB1 or SMB2 (just build paths with a leading slash).
773adee6784SGordon Ross */
774adee6784SGordon Ross int
smb2_smb_ntcreate(struct smb_share * ssp,struct mbchain * name_mb,struct mbchain * cctx_in,struct mdchain * cctx_out,uint32_t cr_flags,uint32_t req_acc,uint32_t efa,uint32_t share_acc,uint32_t open_disp,uint32_t createopt,uint32_t impersonate,struct smb_cred * scrp,smb2fid_t * fidp,uint32_t * cr_act_p,struct smbfattr * fap)775adee6784SGordon Ross smb2_smb_ntcreate(
776adee6784SGordon Ross struct smb_share *ssp,
777adee6784SGordon Ross struct mbchain *name_mb,
778adee6784SGordon Ross struct mbchain *cctx_in,
779adee6784SGordon Ross struct mdchain *cctx_out,
780adee6784SGordon Ross uint32_t cr_flags, /* create flags */
781adee6784SGordon Ross uint32_t req_acc, /* requested access */
782adee6784SGordon Ross uint32_t efa, /* ext. file attrs (DOS attr +) */
783adee6784SGordon Ross uint32_t share_acc,
784adee6784SGordon Ross uint32_t open_disp, /* open disposition */
785adee6784SGordon Ross uint32_t createopt, /* NTCREATEX_OPTIONS_ */
786adee6784SGordon Ross uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */
787adee6784SGordon Ross struct smb_cred *scrp,
788adee6784SGordon Ross smb2fid_t *fidp, /* returned FID */
789adee6784SGordon Ross uint32_t *cr_act_p, /* optional create action */
790adee6784SGordon Ross struct smbfattr *fap) /* optional attributes */
791adee6784SGordon Ross {
792adee6784SGordon Ross struct smbfattr fa;
793adee6784SGordon Ross struct smb_rq *rqp;
794adee6784SGordon Ross struct mbchain *mbp;
795adee6784SGordon Ross struct mdchain *mdp;
796adee6784SGordon Ross uint16_t *name_offp;
797adee6784SGordon Ross uint16_t *name_lenp;
798adee6784SGordon Ross uint32_t *cctx_offp;
799adee6784SGordon Ross uint32_t *cctx_lenp;
800adee6784SGordon Ross uint32_t rcc_off, rcc_len;
801adee6784SGordon Ross smb2fid_t smb2_fid;
802adee6784SGordon Ross uint64_t llongint;
803adee6784SGordon Ross uint32_t longint, createact;
804adee6784SGordon Ross uint_t off, len;
805adee6784SGordon Ross int error;
806adee6784SGordon Ross uint16_t StructSize = 57; // [MS-SMB2]
807adee6784SGordon Ross
808adee6784SGordon Ross bzero(&fa, sizeof (fa));
809adee6784SGordon Ross
810adee6784SGordon Ross error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp);
811adee6784SGordon Ross if (error)
812adee6784SGordon Ross return (error);
813adee6784SGordon Ross
814adee6784SGordon Ross /*
815adee6784SGordon Ross * Todo: Assemble creat contexts (if needed)
816adee6784SGordon Ross * into an mbchain.
817adee6784SGordon Ross */
818adee6784SGordon Ross
819adee6784SGordon Ross /*
820adee6784SGordon Ross * Build the SMB 2/3 Create Request
821adee6784SGordon Ross */
822adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
823adee6784SGordon Ross mb_put_uint16le(mbp, StructSize);
824adee6784SGordon Ross mb_put_uint8(mbp, 0); /* Security flags */
825adee6784SGordon Ross mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE); /* Oplock level */
826*686670eaSGordon Ross mb_put_uint32le(mbp, impersonate); /* Impersonation Level */
827adee6784SGordon Ross mb_put_uint64le(mbp, cr_flags);
828adee6784SGordon Ross mb_put_uint64le(mbp, 0); /* Reserved */
829adee6784SGordon Ross mb_put_uint32le(mbp, req_acc);
830adee6784SGordon Ross mb_put_uint32le(mbp, efa); /* File attributes */
831adee6784SGordon Ross mb_put_uint32le(mbp, share_acc); /* Share access */
832adee6784SGordon Ross mb_put_uint32le(mbp, open_disp); /* Create disposition */
833adee6784SGordon Ross mb_put_uint32le(mbp, createopt); /* Create options */
834adee6784SGordon Ross
835adee6784SGordon Ross name_offp = mb_reserve(mbp, 2); /* Name offset */
836adee6784SGordon Ross name_lenp = mb_reserve(mbp, 2); /* Name len */
837adee6784SGordon Ross
838adee6784SGordon Ross cctx_offp = mb_reserve(mbp, 4); /* Context offset */
839adee6784SGordon Ross cctx_lenp = mb_reserve(mbp, 4); /* Context len */
840adee6784SGordon Ross
841adee6784SGordon Ross /*
842adee6784SGordon Ross * Put the file name, which is provided in an mbchain.
843adee6784SGordon Ross * If there's a leading slash, skip it (see above).
844adee6784SGordon Ross */
845adee6784SGordon Ross off = mbp->mb_count;
846adee6784SGordon Ross *name_offp = htoles((uint16_t)off);
847adee6784SGordon Ross error = put_name_skip_slash(mbp, name_mb);
848adee6784SGordon Ross if (error)
849adee6784SGordon Ross goto out;
850adee6784SGordon Ross len = mbp->mb_count - off;
851adee6784SGordon Ross *name_lenp = htoles((uint16_t)len);
852adee6784SGordon Ross
853adee6784SGordon Ross /*
854adee6784SGordon Ross * Now the create contexts (if provided)
855adee6784SGordon Ross */
856adee6784SGordon Ross if (cctx_in != NULL) {
857adee6784SGordon Ross off = mbp->mb_count;
858adee6784SGordon Ross *cctx_offp = htolel((uint32_t)off);
859adee6784SGordon Ross mb_put_mbchain(mbp, cctx_in);
860adee6784SGordon Ross len = mbp->mb_count - off;
861adee6784SGordon Ross *cctx_lenp = htolel((uint32_t)len);
862adee6784SGordon Ross } else {
863adee6784SGordon Ross *cctx_offp = 0;
864adee6784SGordon Ross *cctx_lenp = 0;
865adee6784SGordon Ross }
866adee6784SGordon Ross
867adee6784SGordon Ross /*
868adee6784SGordon Ross * If we didn't put any variable-sized data, we'll have
869adee6784SGordon Ross * put exactly 56 bytes of data, and we need to pad out
870adee6784SGordon Ross * this request to the 57 bytes StructSize indicated.
871adee6784SGordon Ross */
872adee6784SGordon Ross if (mbp->mb_count < (StructSize + SMB2_HDRLEN))
873adee6784SGordon Ross mb_put_uint8(mbp, 0);
874adee6784SGordon Ross
875adee6784SGordon Ross /*
876adee6784SGordon Ross * Don't want to risk missing a successful
877adee6784SGordon Ross * open response, or we could "leak" FIDs.
878adee6784SGordon Ross */
879adee6784SGordon Ross rqp->sr_flags |= SMBR_NOINTR_RECV;
880adee6784SGordon Ross error = smb2_rq_simple_timed(rqp, smb2_timo_open);
881adee6784SGordon Ross if (error)
882adee6784SGordon Ross goto out;
883adee6784SGordon Ross
884adee6784SGordon Ross /*
885adee6784SGordon Ross * Parse SMB 2/3 Create Response
886adee6784SGordon Ross */
887adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
888adee6784SGordon Ross
889adee6784SGordon Ross /* Check structure size is 89 */
890adee6784SGordon Ross error = md_get_uint16le(mdp, &StructSize);
891adee6784SGordon Ross if (StructSize != 89) {
892adee6784SGordon Ross error = EBADRPC;
893adee6784SGordon Ross goto out;
894adee6784SGordon Ross }
895adee6784SGordon Ross
896adee6784SGordon Ross md_get_uint8(mdp, NULL); /* oplock lvl granted */
897adee6784SGordon Ross md_get_uint8(mdp, NULL); /* mbz */
898adee6784SGordon Ross md_get_uint32le(mdp, &createact); /* create_action */
899adee6784SGordon Ross md_get_uint64le(mdp, &llongint); /* creation time */
900adee6784SGordon Ross smb_time_NT2local(llongint, &fa.fa_createtime);
901adee6784SGordon Ross md_get_uint64le(mdp, &llongint); /* access time */
902adee6784SGordon Ross smb_time_NT2local(llongint, &fa.fa_atime);
903adee6784SGordon Ross md_get_uint64le(mdp, &llongint); /* write time */
904adee6784SGordon Ross smb_time_NT2local(llongint, &fa.fa_mtime);
905adee6784SGordon Ross md_get_uint64le(mdp, &llongint); /* change time */
906adee6784SGordon Ross smb_time_NT2local(llongint, &fa.fa_ctime);
907adee6784SGordon Ross md_get_uint64le(mdp, &llongint); /* allocation size */
908adee6784SGordon Ross fa.fa_allocsz = llongint;
909adee6784SGordon Ross md_get_uint64le(mdp, &llongint); /* EOF position */
910adee6784SGordon Ross fa.fa_size = llongint;
911adee6784SGordon Ross md_get_uint32le(mdp, &longint); /* attributes */
912adee6784SGordon Ross fa.fa_attr = longint;
913adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* reserved */
914adee6784SGordon Ross
915adee6784SGordon Ross /* Get SMB 2/3 File ID and create user fid to return */
916adee6784SGordon Ross md_get_uint64le(mdp, &smb2_fid.fid_persistent);
917adee6784SGordon Ross error = md_get_uint64le(mdp, &smb2_fid.fid_volatile);
918adee6784SGordon Ross if (error)
919adee6784SGordon Ross goto out;
920adee6784SGordon Ross
921adee6784SGordon Ross /* Get Context Offset */
922adee6784SGordon Ross error = md_get_uint32le(mdp, &rcc_off);
923adee6784SGordon Ross if (error)
924adee6784SGordon Ross goto out;
925adee6784SGordon Ross /* Get Context Length */
926adee6784SGordon Ross error = md_get_uint32le(mdp, &rcc_len);
927adee6784SGordon Ross if (error)
928adee6784SGordon Ross goto out;
929adee6784SGordon Ross
930adee6784SGordon Ross /*
931adee6784SGordon Ross * If the caller wants the returned create contexts, parse.
932adee6784SGordon Ross * Context offset is from the beginning of SMB 2/3 Header
933adee6784SGordon Ross * Calculate how much further we have to go to get to it.
934adee6784SGordon Ross * Current offset is: SMB2_HDRLEN + 88
935adee6784SGordon Ross */
936adee6784SGordon Ross if (rcc_len != 0) {
937adee6784SGordon Ross int skip = (int)rcc_off - (SMB2_HDRLEN + 88);
938adee6784SGordon Ross if (skip < 0) {
939adee6784SGordon Ross error = EBADRPC;
940adee6784SGordon Ross goto out;
941adee6784SGordon Ross }
942adee6784SGordon Ross if (skip > 0) {
943adee6784SGordon Ross md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
944adee6784SGordon Ross }
945adee6784SGordon Ross if (cctx_out != NULL) {
946adee6784SGordon Ross mblk_t *m = NULL;
947adee6784SGordon Ross error = md_get_mbuf(mdp, rcc_len, &m);
948adee6784SGordon Ross if (error)
949adee6784SGordon Ross goto out;
950adee6784SGordon Ross md_initm(cctx_out, m);
951adee6784SGordon Ross }
952adee6784SGordon Ross }
953adee6784SGordon Ross
954adee6784SGordon Ross out:
955adee6784SGordon Ross smb_rq_done(rqp);
956adee6784SGordon Ross if (error)
957adee6784SGordon Ross return (error);
958adee6784SGordon Ross
959adee6784SGordon Ross *fidp = smb2_fid;
960adee6784SGordon Ross if (cr_act_p)
961adee6784SGordon Ross *cr_act_p = createact;
962adee6784SGordon Ross if (fap)
963adee6784SGordon Ross *fap = fa; /* struct copy */
964adee6784SGordon Ross
965adee6784SGordon Ross return (0);
966adee6784SGordon Ross }
967adee6784SGordon Ross
968adee6784SGordon Ross int
smb2_smb_close(struct smb_share * ssp,smb2fid_t * fid,struct smb_cred * scrp)969adee6784SGordon Ross smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp)
970adee6784SGordon Ross {
971adee6784SGordon Ross struct smb_rq *rqp;
972adee6784SGordon Ross struct mbchain *mbp;
973adee6784SGordon Ross int error;
974adee6784SGordon Ross
975adee6784SGordon Ross error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp);
976adee6784SGordon Ross if (error)
977adee6784SGordon Ross return (error);
978adee6784SGordon Ross
979adee6784SGordon Ross /*
980adee6784SGordon Ross * Build the SMB 2/3 Close Request
981adee6784SGordon Ross */
982adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
983adee6784SGordon Ross mb_put_uint16le(mbp, 24); /* Struct size */
984adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Flags */
985adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Reserved */
986adee6784SGordon Ross
987adee6784SGordon Ross mb_put_uint64le(mbp, fid->fid_persistent);
988adee6784SGordon Ross mb_put_uint64le(mbp, fid->fid_volatile);
989adee6784SGordon Ross
990adee6784SGordon Ross /* Make sure we send, but only if already connected */
991adee6784SGordon Ross rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
992adee6784SGordon Ross error = smb2_rq_simple(rqp);
993adee6784SGordon Ross smb_rq_done(rqp);
994adee6784SGordon Ross return (error);
995adee6784SGordon Ross }
996adee6784SGordon Ross
997adee6784SGordon Ross int
smb2_smb_ioctl(struct smb_share * ssp,smb2fid_t * fid,struct mbchain * data_in,struct mdchain * data_out,uint32_t * data_out_sz,uint32_t ctl_code,struct smb_cred * scrp)998adee6784SGordon Ross smb2_smb_ioctl(
999adee6784SGordon Ross struct smb_share *ssp,
1000adee6784SGordon Ross smb2fid_t *fid,
1001adee6784SGordon Ross struct mbchain *data_in,
1002adee6784SGordon Ross struct mdchain *data_out,
1003adee6784SGordon Ross uint32_t *data_out_sz, /* max / returned */
1004adee6784SGordon Ross uint32_t ctl_code,
1005adee6784SGordon Ross struct smb_cred *scrp)
1006adee6784SGordon Ross {
1007adee6784SGordon Ross struct smb_rq *rqp;
1008adee6784SGordon Ross struct mbchain *mbp;
1009adee6784SGordon Ross struct mdchain *mdp;
1010adee6784SGordon Ross uint32_t *data_in_offp;
1011adee6784SGordon Ross uint32_t *data_in_lenp;
1012adee6784SGordon Ross uint32_t data_out_off;
1013adee6784SGordon Ross uint32_t data_out_len;
1014adee6784SGordon Ross uint16_t length = 0;
1015adee6784SGordon Ross uint_t off, len;
1016adee6784SGordon Ross int error;
1017adee6784SGordon Ross
1018adee6784SGordon Ross error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp);
1019adee6784SGordon Ross if (error)
1020adee6784SGordon Ross return (error);
1021adee6784SGordon Ross
1022adee6784SGordon Ross /*
1023adee6784SGordon Ross * Build the SMB 2 IOCTL Request
1024adee6784SGordon Ross */
1025adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
1026adee6784SGordon Ross mb_put_uint16le(mbp, 57); /* Struct size */
1027adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Reserved */
1028adee6784SGordon Ross mb_put_uint32le(mbp, ctl_code);
1029adee6784SGordon Ross
1030adee6784SGordon Ross mb_put_uint64le(mbp, fid->fid_persistent);
1031adee6784SGordon Ross mb_put_uint64le(mbp, fid->fid_volatile);
1032adee6784SGordon Ross
1033adee6784SGordon Ross data_in_offp = mb_reserve(mbp, 4);
1034adee6784SGordon Ross data_in_lenp = mb_reserve(mbp, 4);
1035adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Max input resp */
1036adee6784SGordon Ross
1037adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Output offset */
1038adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Output count */
1039adee6784SGordon Ross mb_put_uint32le(mbp, *data_out_sz);
1040adee6784SGordon Ross
1041adee6784SGordon Ross mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */
1042adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Reserved2 */
1043adee6784SGordon Ross
1044adee6784SGordon Ross /*
1045adee6784SGordon Ross * Now data_in (if provided)
1046adee6784SGordon Ross */
1047adee6784SGordon Ross if (data_in != NULL) {
1048adee6784SGordon Ross off = mbp->mb_count;
1049adee6784SGordon Ross *data_in_offp = htolel((uint32_t)off);
1050adee6784SGordon Ross mb_put_mbchain(mbp, data_in);
1051adee6784SGordon Ross len = mbp->mb_count - off;
1052adee6784SGordon Ross *data_in_lenp = htolel((uint32_t)len);
1053adee6784SGordon Ross } else {
1054adee6784SGordon Ross *data_in_offp = 0;
1055adee6784SGordon Ross *data_in_lenp = 0;
1056adee6784SGordon Ross }
1057adee6784SGordon Ross
1058adee6784SGordon Ross /*
1059adee6784SGordon Ross * Run the request
1060adee6784SGordon Ross */
1061adee6784SGordon Ross error = smb2_rq_simple_timed(rqp, smb2_timo_default);
1062adee6784SGordon Ross if (error)
1063adee6784SGordon Ross goto out;
1064adee6784SGordon Ross
1065adee6784SGordon Ross /*
1066adee6784SGordon Ross * Parse SMB 2 Ioctl Response
1067adee6784SGordon Ross */
1068adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
1069adee6784SGordon Ross
1070adee6784SGordon Ross /* Check structure size is 49 */
1071adee6784SGordon Ross md_get_uint16le(mdp, &length);
1072adee6784SGordon Ross if (length != 49) {
1073adee6784SGordon Ross error = EBADRPC;
1074adee6784SGordon Ross goto out;
1075adee6784SGordon Ross }
1076adee6784SGordon Ross md_get_uint16le(mdp, NULL); /* reserved */
1077adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* Get CtlCode */
1078adee6784SGordon Ross md_get_uint64le(mdp, NULL); /* fid_persistent */
1079adee6784SGordon Ross md_get_uint64le(mdp, NULL); /* fid_volatile */
1080adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* Get Input offset */
1081adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* Get Input count */
1082adee6784SGordon Ross
1083adee6784SGordon Ross error = md_get_uint32le(mdp, &data_out_off);
1084adee6784SGordon Ross if (error)
1085adee6784SGordon Ross goto out;
1086adee6784SGordon Ross error = md_get_uint32le(mdp, &data_out_len);
1087adee6784SGordon Ross if (error)
1088adee6784SGordon Ross goto out;
1089adee6784SGordon Ross
1090adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* Flags */
1091adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* reserved */
1092adee6784SGordon Ross
1093adee6784SGordon Ross /*
1094adee6784SGordon Ross * If the caller wants the ioctl output data, parse.
1095adee6784SGordon Ross * Current offset is: SMB2_HDRLEN + 48
1096adee6784SGordon Ross * Always return the received length.
1097adee6784SGordon Ross */
1098adee6784SGordon Ross *data_out_sz = data_out_len;
1099adee6784SGordon Ross if (data_out_len != 0) {
1100adee6784SGordon Ross int skip = (int)data_out_off - (SMB2_HDRLEN + 48);
1101adee6784SGordon Ross if (skip < 0) {
1102adee6784SGordon Ross error = EBADRPC;
1103adee6784SGordon Ross goto out;
1104adee6784SGordon Ross }
1105adee6784SGordon Ross if (skip > 0) {
1106adee6784SGordon Ross md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1107adee6784SGordon Ross }
1108adee6784SGordon Ross if (data_out != NULL) {
1109adee6784SGordon Ross mblk_t *m = NULL;
1110adee6784SGordon Ross error = md_get_mbuf(mdp, data_out_len, &m);
1111adee6784SGordon Ross if (error)
1112adee6784SGordon Ross goto out;
1113adee6784SGordon Ross md_initm(data_out, m);
1114adee6784SGordon Ross }
1115adee6784SGordon Ross }
1116adee6784SGordon Ross
1117adee6784SGordon Ross out:
1118adee6784SGordon Ross smb_rq_done(rqp);
1119adee6784SGordon Ross
1120adee6784SGordon Ross return (error);
1121adee6784SGordon Ross }
1122adee6784SGordon Ross
1123adee6784SGordon Ross int
smb2_smb_read(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1124adee6784SGordon Ross smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
1125adee6784SGordon Ross uio_t *uiop, smb_cred_t *scred, int timo)
1126adee6784SGordon Ross {
1127adee6784SGordon Ross struct smb_share *ssp = FHTOSS(fhp);
1128adee6784SGordon Ross struct smb_rq *rqp;
1129adee6784SGordon Ross struct mbchain *mbp;
1130adee6784SGordon Ross struct mdchain *mdp;
1131adee6784SGordon Ross int error;
1132adee6784SGordon Ross uint64_t off64 = uiop->uio_loffset;
1133adee6784SGordon Ross uint32_t rlen;
1134adee6784SGordon Ross uint16_t length = 0;
1135adee6784SGordon Ross uint8_t data_offset;
1136adee6784SGordon Ross
1137adee6784SGordon Ross error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp);
1138adee6784SGordon Ross if (error)
1139adee6784SGordon Ross return (error);
1140adee6784SGordon Ross
1141adee6784SGordon Ross /*
1142adee6784SGordon Ross * Build the SMB 2 Read Request
1143adee6784SGordon Ross */
1144adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
1145adee6784SGordon Ross mb_put_uint16le(mbp, 49); /* Struct size */
1146adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Padding and Reserved */
1147adee6784SGordon Ross
1148adee6784SGordon Ross mb_put_uint32le(mbp, *lenp); /* Length of read */
1149adee6784SGordon Ross mb_put_uint64le(mbp, off64); /* Offset */
1150adee6784SGordon Ross
1151adee6784SGordon Ross mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1152adee6784SGordon Ross mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1153adee6784SGordon Ross
1154adee6784SGordon Ross mb_put_uint32le(mbp, 1); /* MinCount */
1155adee6784SGordon Ross /* (only indicates blocking) */
1156adee6784SGordon Ross
1157adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Channel */
1158adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Remaining */
1159adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Channel offset/len */
1160adee6784SGordon Ross mb_put_uint8(mbp, 0); /* data "blob" (pad) */
1161adee6784SGordon Ross
1162adee6784SGordon Ross if (timo == 0)
1163adee6784SGordon Ross timo = smb2_timo_read;
1164adee6784SGordon Ross error = smb2_rq_simple_timed(rqp, timo);
1165adee6784SGordon Ross if (error)
1166adee6784SGordon Ross goto out;
1167adee6784SGordon Ross
1168adee6784SGordon Ross /*
1169adee6784SGordon Ross * Parse SMB 2 Read Response
1170adee6784SGordon Ross */
1171adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
1172adee6784SGordon Ross
1173adee6784SGordon Ross /* Check structure size is 17 */
1174adee6784SGordon Ross md_get_uint16le(mdp, &length);
1175adee6784SGordon Ross if (length != 17) {
1176adee6784SGordon Ross error = EBADRPC;
1177adee6784SGordon Ross goto out;
1178adee6784SGordon Ross }
1179adee6784SGordon Ross md_get_uint8(mdp, &data_offset);
1180adee6784SGordon Ross md_get_uint8(mdp, NULL); /* reserved */
1181adee6784SGordon Ross
1182adee6784SGordon Ross /* Get Data Length read */
1183adee6784SGordon Ross error = md_get_uint32le(mdp, &rlen);
1184adee6784SGordon Ross if (error)
1185adee6784SGordon Ross goto out;
1186adee6784SGordon Ross
1187adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* Data Remaining (always 0) */
1188adee6784SGordon Ross md_get_uint32le(mdp, NULL); /* Get Reserved2 (always 0) */
1189adee6784SGordon Ross
1190adee6784SGordon Ross /*
1191adee6784SGordon Ross * Data offset is from the beginning of SMB 2/3 Header
1192adee6784SGordon Ross * Calculate how much further we have to go to get to it.
1193adee6784SGordon Ross */
1194adee6784SGordon Ross if (data_offset < (SMB2_HDRLEN + 16)) {
1195adee6784SGordon Ross error = EBADRPC;
1196adee6784SGordon Ross goto out;
1197adee6784SGordon Ross }
1198adee6784SGordon Ross if (data_offset > (SMB2_HDRLEN + 16)) {
1199adee6784SGordon Ross int skip = data_offset - (SMB2_HDRLEN + 16);
1200adee6784SGordon Ross md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1201adee6784SGordon Ross }
1202adee6784SGordon Ross
1203adee6784SGordon Ross /*
1204adee6784SGordon Ross * Get the data
1205adee6784SGordon Ross */
1206adee6784SGordon Ross if (rlen == 0) {
1207adee6784SGordon Ross *lenp = rlen;
1208adee6784SGordon Ross goto out;
1209adee6784SGordon Ross }
1210adee6784SGordon Ross /* paranoid */
1211adee6784SGordon Ross if (rlen > *lenp) {
1212adee6784SGordon Ross SMBSDEBUG("bad server! rlen %d, len %d\n",
1213adee6784SGordon Ross rlen, *lenp);
1214adee6784SGordon Ross rlen = *lenp;
1215adee6784SGordon Ross }
1216adee6784SGordon Ross
1217adee6784SGordon Ross error = md_get_uio(mdp, uiop, rlen);
1218adee6784SGordon Ross if (error)
1219adee6784SGordon Ross goto out;
1220adee6784SGordon Ross
1221adee6784SGordon Ross /* Success */
1222adee6784SGordon Ross *lenp = rlen;
1223adee6784SGordon Ross
1224adee6784SGordon Ross out:
1225adee6784SGordon Ross smb_rq_done(rqp);
1226adee6784SGordon Ross return (error);
1227adee6784SGordon Ross }
1228adee6784SGordon Ross
1229adee6784SGordon Ross int
smb2_smb_write(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1230adee6784SGordon Ross smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
1231adee6784SGordon Ross uio_t *uiop, smb_cred_t *scred, int timo)
1232adee6784SGordon Ross {
1233adee6784SGordon Ross struct smb_share *ssp = FHTOSS(fhp);
1234adee6784SGordon Ross struct smb_rq *rqp;
1235adee6784SGordon Ross struct mbchain *mbp;
1236adee6784SGordon Ross struct mdchain *mdp;
1237adee6784SGordon Ross int error;
1238adee6784SGordon Ross uint64_t off64 = uiop->uio_loffset;
1239adee6784SGordon Ross uint32_t rlen;
1240adee6784SGordon Ross uint16_t data_offset;
1241adee6784SGordon Ross uint16_t length = 0;
1242adee6784SGordon Ross
1243adee6784SGordon Ross error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp);
1244adee6784SGordon Ross if (error)
1245adee6784SGordon Ross return (error);
1246adee6784SGordon Ross
1247adee6784SGordon Ross /*
1248adee6784SGordon Ross * Build the SMB 2 Write Request
1249adee6784SGordon Ross */
1250adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
1251adee6784SGordon Ross mb_put_uint16le(mbp, 49); /* Struct size */
1252adee6784SGordon Ross data_offset = SMB2_HDRLEN + 48;
1253adee6784SGordon Ross mb_put_uint16le(mbp, data_offset); /* Data Offset */
1254adee6784SGordon Ross mb_put_uint32le(mbp, *lenp); /* Length of write */
1255adee6784SGordon Ross mb_put_uint64le(mbp, off64); /* Offset */
1256adee6784SGordon Ross
1257adee6784SGordon Ross mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1258adee6784SGordon Ross mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1259adee6784SGordon Ross
1260adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Channel */
1261adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Remaining */
1262adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Channel offset/len */
1263adee6784SGordon Ross mb_put_uint32le(mbp, 0); /* Write flags */
1264adee6784SGordon Ross
1265adee6784SGordon Ross error = mb_put_uio(mbp, uiop, *lenp);
1266adee6784SGordon Ross if (error)
1267adee6784SGordon Ross goto out;
1268adee6784SGordon Ross
1269adee6784SGordon Ross if (timo == 0)
1270adee6784SGordon Ross timo = smb2_timo_write;
1271adee6784SGordon Ross error = smb2_rq_simple_timed(rqp, timo);
1272adee6784SGordon Ross if (error)
1273adee6784SGordon Ross goto out;
1274adee6784SGordon Ross
1275adee6784SGordon Ross /*
1276adee6784SGordon Ross * Parse SMB 2/3 Write Response
1277adee6784SGordon Ross */
1278adee6784SGordon Ross smb_rq_getreply(rqp, &mdp);
1279adee6784SGordon Ross
1280adee6784SGordon Ross /* Check structure size is 17 */
1281adee6784SGordon Ross md_get_uint16le(mdp, &length);
1282adee6784SGordon Ross if (length != 17) {
1283adee6784SGordon Ross error = EBADRPC;
1284adee6784SGordon Ross goto out;
1285adee6784SGordon Ross }
1286adee6784SGordon Ross
1287adee6784SGordon Ross md_get_uint16le(mdp, NULL); /* Get Reserved */
1288adee6784SGordon Ross
1289adee6784SGordon Ross /* Get Data Length written */
1290adee6784SGordon Ross error = md_get_uint32le(mdp, &rlen);
1291adee6784SGordon Ross if (error)
1292adee6784SGordon Ross goto out;
1293adee6784SGordon Ross
1294adee6784SGordon Ross /* Get Data Remaining (always 0) */
1295adee6784SGordon Ross md_get_uint32le(mdp, NULL);
1296adee6784SGordon Ross
1297adee6784SGordon Ross /* Get Reserved2 (always 0) */
1298adee6784SGordon Ross md_get_uint32le(mdp, NULL);
1299adee6784SGordon Ross
1300adee6784SGordon Ross /* Success */
1301adee6784SGordon Ross *lenp = rlen;
1302adee6784SGordon Ross
1303adee6784SGordon Ross out:
1304adee6784SGordon Ross smb_rq_done(rqp);
1305adee6784SGordon Ross return (error);
1306adee6784SGordon Ross }
1307adee6784SGordon Ross
1308adee6784SGordon Ross /*
1309adee6784SGordon Ross * Note: the IOD calls this, so this request must not wait for
1310adee6784SGordon Ross * connection state changes, etc. (uses smb2_rq_internal)
1311adee6784SGordon Ross */
1312adee6784SGordon Ross int
smb2_smb_echo(struct smb_vc * vcp,struct smb_cred * scred,int timo)1313adee6784SGordon Ross smb2_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1314adee6784SGordon Ross {
1315adee6784SGordon Ross struct smb_rq *rqp;
1316adee6784SGordon Ross struct mbchain *mbp;
1317adee6784SGordon Ross int error;
1318adee6784SGordon Ross
1319adee6784SGordon Ross error = smb_rq_alloc(VCTOCP(vcp), SMB2_ECHO, scred, &rqp);
1320adee6784SGordon Ross if (error)
1321adee6784SGordon Ross return (error);
1322adee6784SGordon Ross
1323adee6784SGordon Ross /*
1324adee6784SGordon Ross * Build the SMB 2 Echo Request
1325adee6784SGordon Ross */
1326adee6784SGordon Ross smb_rq_getrequest(rqp, &mbp);
1327adee6784SGordon Ross mb_put_uint16le(mbp, 4); /* Struct size */
1328adee6784SGordon Ross mb_put_uint16le(mbp, 0); /* Reserved */
1329adee6784SGordon Ross
1330adee6784SGordon Ross rqp->sr_flags |= SMBR_NORECONNECT;
1331adee6784SGordon Ross error = smb2_rq_internal(rqp, timo);
1332adee6784SGordon Ross
1333adee6784SGordon Ross smb_rq_done(rqp);
1334adee6784SGordon Ross return (error);
1335adee6784SGordon Ross }
1336