xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_write_raw.c (revision 13138:89c014c50a5f)
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * SMB: write_raw
27  * 5.27       WRITE_RAW: Write Raw Bytes
28  *
29  * The Write Block Raw protocol is used to maximize the performance of
30  * writing a large block of data from the client to the server.  The Write
31  * Block Raw command's scope includes files, Named Pipes, and spooled
32  * output (can be used in place COM_WRITE_PRINT_FILE ).
33  *
34  *  Client Request              Description
35  *  ==========================  =========================================
36  *
37  *  UCHAR WordCount;            Count of parameter words = 12
38  *  USHORT Fid;                 File handle
39  *  USHORT Count;               Total bytes, including this buffer
40  *  USHORT Reserved;
41  *  ULONG Offset;               Offset in file to begin write
42  *  ULONG Timeout;
43  *  USHORT WriteMode;           Write mode:
44  *                              bit 0 - complete write to disk and send
45  *                              final result response
46  *                              bit 1 - return Remaining (pipe/dev)
47  *                              (see WriteAndX for #defines)
48  *  ULONG Reserved2;
49  *  USHORT DataLength;          Number of data bytes this buffer
50  *  USHORT DataOffset;          Offset (from header start) to data
51  *  USHORT ByteCount;           Count of data bytes
52  *  UCHAR Pad[];                Pad to SHORT or LONG
53  *  UCHAR Data[];               Data (# = DataLength)
54  *
55  *  First Server Response          Description
56  *  ============================== =====================================
57  *
58  *  UCHAR WordCount;               Count of parameter words = 1
59  *  USHORT Remaining;              Bytes remaining to be read if pipe
60  *  USHORT ByteCount;              Count of data bytes = 0
61  *
62  *  Final Server Response              Description
63  *  ================================== =================================
64  *
65  *  UCHAR Command (in SMB header)      SMB_COM_WRITE_COMPLETE
66  *
67  *  UCHAR WordCount;                   Count of parameter words = 1
68  *  USHORT Count;                      Total number of bytes written
69  *  USHORT ByteCount;                  Count of data bytes = 0
70  *
71  * The first response format will be that of the final server response in
72  * the case where the server gets an error while writing the data sent
73  * along with the request.  Thus Count is the number of bytes which did get
74  * written any time an error is returned.  If an error occurs after the
75  * first response has been sent allowing the client to send the remaining
76  * data, the final response should not be sent unless write through is set.
77  * Rather the server should return this "write behind" error on the next
78  * access to the Fid.
79  *
80  * The client must guarantee that there is (and will be) no other request
81  * on the connection for the duration of this request.  The server will
82  * reserve enough resources to receive the data and respond with a response
83  * SMB as defined above.  The client then sends the raw data in one send.
84  * Thus the server is able to receive up to 65,535 bytes of data directly
85  * into the server buffer.  The amount of data transferred is expected to
86  * be larger than the negotiated buffer size for this protocol.
87  *
88  * The reason that no other requests can be active on the connection for
89  * the duration of the request is that if other receives are present on the
90  * connection, there is normally no way to guarantee that the data will be
91  * received into the correct server buffer, rather the data may fill one
92  * (or more) of the other buffers.  Also if the client is sending other
93  * requests on the connection, a request may land in the buffer that the
94  * server has allocated for the this SMB's data.
95  *
96  * Whether or not SMB_COM_WRITE_RAW is supported is returned in the
97  * response to SMB_COM_NEGOTIATE.  SMB_COM_WRITE_RAW is not supported for
98  * connectionless clients.
99  *
100  * When write through is not specified ((WriteMode & 01) == 0) this SMB is
101  * assumed to be a form of write behind.  The transport layer guarantees
102  * delivery of all secondary requests from the client.  Thus no "got the
103  * data you sent" SMB is needed.  If an error should occur at the server
104  * end, all bytes must be received and thrown away.  If an error occurs
105  * while writing data to disk such as disk full, the next access of the
106  * file handle (another write, close, read, etc.) will return the fact that
107  * the error occurred.
108  *
109  * If write through is specified ((WriteMode & 01) != 0), the server will
110  * receive the data, write it to disk and then send a final response
111  * indicating the result of the write.  The total number of bytes written
112  * is also returned in this response in the Count field.
113  *
114  * The flow for the SMB_COM_WRITE_RAW SMB is:
115  *
116  * client -----> SMB_COM_WRITE_RAW request (optional data) >-------> server
117  * client <------------------< OK send (more) data <---------------- server
118  * client  ----------------------> raw data >----------------------> server
119  * client  <---< data on disk or error (write through only) <------- server
120  *
121  * This protocol is set up such that the SMB_COM_WRITE_RAW request may also
122  * carry data.  This is an optimization in that up to the server's buffer
123  * size (MaxCount from SMB_COM_NEGOTIATE response), minus the size of the
124  * SMB_COM_WRITE_RAW SMB request, may be sent along with the request.  Thus
125  * if the server is busy and unable to support the raw write of the
126  * remaining data, the data sent along with the request has been delivered
127  * and need not be sent again.  The server will write any data sent in the
128  * request (and wait for it to be on the disk or device if write through is
129  * set), prior to sending the response.
130  *
131  * The specific responses error class ERRSRV, error codes ERRusempx and
132  * ERRusestd, indicate that the server is temporarily out of the resources
133  *
134  * needed to support the raw write of the remaining data, but that any data
135  * sent along with the request has been successfully written.  The client
136  * should then write the remaining data using a different type of SMB write
137  * request, or delay and retry using SMB_COM_WRITE_RAW.  If a write error
138  * occurs writing the initial data, it will be returned and the write raw
139  * request is implicitly denied.
140  *
141  * The return field Remaining is returned for named pipes only.  It is used
142  * to return the number of bytes currently available in the pipe.  This
143  * information can then be used by the client to know when a subsequent
144  * (non blocking) read of the pipe may return some data.  Of course when
145  * the read request is actually received by the server there may be more or
146  * less actual data in the pipe (more data has been written to the pipe /
147  * device or another reader drained it).  If the information is currently
148  * not available or the request is NOT for a pipe or the server does not
149  * support this feature, a -1 value should be returned.
150  *
151  * If the negotiated dialect is NT LM 0.12 or later, and the response to
152  * the SMB_COM_NEGOTIATE SMB has CAP_LARGE_FILES set in the Capabilities
153  * field, an additional request format is allowed which accommodates very
154  * large files having 64 bit offsets:
155  *
156  *  Client Request                     Description
157  *  ================================== =================================
158  *   UCHAR WordCount;                   Count of parameter words = 14
159  *   USHORT Fid;                       File handle
160  *   USHORT Count;                     Total bytes, including this
161  *                                      buffer
162  *   USHORT Reserved;
163  *   ULONG Offset;                     Offset in file to begin write
164  *   ULONG Timeout;
165  *   USHORT WriteMode;                 Write mode:
166  *                                      bit 0 - complete write to disk
167  *                                      and send final result response
168  *                                      bit 1 - return Remaining
169  *                                      (pipe/dev)
170  *   ULONG Reserved2;
171  *   USHORT DataLength;                Number of data bytes this buffer
172  *   USHORT DataOffset;                Offset (from header start) to
173  *                                      data
174  *   ULONG OffsetHigh;                 Upper 32 bits of offset
175  *   USHORT ByteCount;                  Count of data bytes
176  *   UCHAR Pad[];                       Pad to SHORT or LONG
177  *   UCHAR Data[];                     Data (# = DataLength)
178  *
179  * In this case the final offset in the file is formed by combining
180  * OffsetHigh and Offset, the resulting offset must not be negative.
181  */
182 
183 #include <sys/sdt.h>
184 #include <smbsrv/smb_kproto.h>
185 #include <smbsrv/smb_fsops.h>
186 #include <smbsrv/netbios.h>
187 
188 extern uint32_t smb_keep_alive;
189 
190 static int smb_transfer_write_raw_data(smb_request_t *, smb_rw_param_t *);
191 
192 smb_sdrc_t
smb_pre_write_raw(smb_request_t * sr)193 smb_pre_write_raw(smb_request_t *sr)
194 {
195 	smb_rw_param_t *param;
196 	uint32_t off_low;
197 	uint32_t timeout;
198 	uint32_t off_high;
199 	uint16_t datalen;
200 	uint16_t total;
201 	int rc;
202 
203 	param = smb_srm_zalloc(sr, sizeof (smb_rw_param_t));
204 	sr->arg.rw = param;
205 	param->rw_magic = SMB_RW_MAGIC;
206 
207 	if (sr->smb_wct == 12) {
208 		rc = smbsr_decode_vwv(sr, "ww2.llw4.ww", &sr->smb_fid, &total,
209 		    &off_low, &timeout, &param->rw_mode, &datalen,
210 		    &param->rw_dsoff);
211 
212 		param->rw_offset = (uint64_t)off_low;
213 		param->rw_dsoff -= 59;
214 	} else {
215 		rc = smbsr_decode_vwv(sr, "ww2.llw4.wwl", &sr->smb_fid, &total,
216 		    &off_low, &timeout, &param->rw_mode, &datalen,
217 		    &param->rw_dsoff, &off_high);
218 
219 		param->rw_offset = ((uint64_t)off_high << 32) | off_low;
220 		param->rw_dsoff -= 63;
221 	}
222 
223 	param->rw_count = (uint32_t)datalen;
224 	param->rw_total = (uint32_t)total;
225 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
226 
227 	DTRACE_SMB_2(op__WriteRaw__start, smb_request_t *, sr,
228 	    smb_rw_param_t *, sr->arg.rw);
229 
230 	smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
231 
232 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
233 }
234 
235 void
smb_post_write_raw(smb_request_t * sr)236 smb_post_write_raw(smb_request_t *sr)
237 {
238 	DTRACE_SMB_2(op__WriteRaw__done, smb_request_t *, sr,
239 	    smb_rw_param_t *, sr->arg.rw);
240 
241 	smb_rwx_rwexit(&sr->session->s_lock);
242 }
243 
244 smb_sdrc_t
smb_com_write_raw(struct smb_request * sr)245 smb_com_write_raw(struct smb_request *sr)
246 {
247 	smb_rw_param_t		*param = sr->arg.rw;
248 	int			rc = 0;
249 	int			session_send_rc = 0;
250 	uint16_t		addl_xfer_count;
251 	offset_t		addl_xfer_offset;
252 	struct mbuf_chain	reply;
253 	smb_error_t		err;
254 
255 	if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE)
256 		return (SDRC_DROP_VC);
257 
258 	if (!smb_raw_mode) {
259 		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
260 		    ERROR_NOT_SUPPORTED);
261 		return (SDRC_ERROR);
262 	}
263 
264 	smbsr_lookup_file(sr);
265 	if (sr->fid_ofile == NULL) {
266 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
267 		return (SDRC_ERROR);
268 	}
269 
270 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
271 
272 	/*
273 	 * Send response if there is additional data to transfer.
274 	 * This will prompt the client to send the remaining data.
275 	 */
276 	addl_xfer_count = param->rw_total - param->rw_count;
277 	addl_xfer_offset = param->rw_count;
278 
279 	if (addl_xfer_count != 0) {
280 		MBC_INIT(&reply, MLEN);
281 		(void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT "bww",
282 		    sr->first_smb_com,
283 		    sr->smb_rcls,
284 		    sr->smb_reh,
285 		    sr->smb_err,
286 		    sr->smb_flg | SMB_FLAGS_REPLY,
287 		    sr->smb_flg2,
288 		    sr->smb_pid_high,
289 		    sr->smb_sig,
290 		    sr->smb_tid,
291 		    sr->smb_pid,
292 		    sr->smb_uid,
293 		    sr->smb_mid, 1, -1, 0);
294 
295 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
296 			smb_sign_reply(sr, &reply);
297 
298 		session_send_rc = smb_session_send(sr->session, 0, &reply);
299 
300 		/*
301 		 * If the response failed, force write-through and
302 		 * complete the write before dealing with the error.
303 		 */
304 		if (session_send_rc != 0)
305 			param->rw_mode = SMB_WRMODE_WRITE_THRU;
306 	}
307 
308 	/*
309 	 * While the response is in flight (and the data begins to arrive)
310 	 * write out the first data segment.
311 	 */
312 	if (smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
313 	    &param->rw_vdb) != 0)
314 		return (SDRC_ERROR);
315 
316 	if (param->rw_count > 0)
317 		rc = smb_common_write(sr, param);
318 
319 	if (session_send_rc != 0) {
320 		sr->smb_rcls = ERRSRV;
321 		sr->smb_err  = ERRusestd;
322 		goto write_raw_transfer_failed;
323 	}
324 
325 	/*
326 	 * If we have more data to read then go get it
327 	 */
328 	if (addl_xfer_count > 0) {
329 		/*
330 		 * This is the only place where a worker thread should
331 		 * directly read from the session socket.  If the data
332 		 * is read successfully then the buffer (sr->sr_raw_data_buf)
333 		 * will need to be freed after the data is written.
334 		 */
335 		param->rw_offset += addl_xfer_offset;
336 		param->rw_vdb.vdb_uio.uio_loffset = param->rw_offset;
337 		param->rw_vdb.vdb_iovec[0].iov_len = addl_xfer_count;
338 		param->rw_vdb.vdb_uio.uio_resid = addl_xfer_count;
339 		if (smb_transfer_write_raw_data(sr, param) != 0)
340 			goto write_raw_transfer_failed;
341 	}
342 
343 	/*
344 	 * Wake up session daemon since we now have all of our data and
345 	 * it's safe for the session daemon to resume processing SMB's.
346 	 */
347 	sr->session->s_write_raw_status = 0;
348 	sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
349 
350 	/*
351 	 * If we didn't write all the data from the first segment then
352 	 * there's not much point in continuing (we still wanted to
353 	 * read any additional data above since we don't necessarily
354 	 * want to drop the connection and we need to read through
355 	 * to the next SMB).
356 	 */
357 	if (rc != 0)
358 		goto notify_write_raw_complete;
359 
360 	/*
361 	 * Write any additional data
362 	 */
363 	if (addl_xfer_count > 0) {
364 		rc = smb_common_write(sr, param);
365 		addl_xfer_offset += param->rw_count;
366 	}
367 
368 	/*
369 	 * If we were called in "Write-behind" mode and the transfer was
370 	 * successful then we don't need to send any further response.
371 	 * If we were called in "Write-Through" mode or if the transfer
372 	 * failed we need to send a completion notification.  The "count"
373 	 * value will indicate whether the transfer was successful.
374 	 */
375 	if ((rc != 0) || SMB_WRMODE_IS_STABLE(param->rw_mode))
376 		goto notify_write_raw_complete;
377 
378 	(void) smb_session_send(sr->session, SESSION_KEEP_ALIVE, NULL);
379 	return (SDRC_NO_REPLY);
380 
381 write_raw_transfer_failed:
382 	/*
383 	 * Raw data transfer failed, wake up session daemon
384 	 */
385 	sr->session->s_write_raw_status = 20;
386 	sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
387 
388 notify_write_raw_complete:
389 	/*
390 	 * If we had an error fill in the appropriate error code
391 	 */
392 	if (rc != 0) {
393 		smbsr_map_errno(rc, &err);
394 		smbsr_set_error(sr, &err);
395 	}
396 
397 	sr->first_smb_com = SMB_COM_WRITE_COMPLETE;
398 	rc = smbsr_encode_result(sr, 1, 0, "bww", 1, addl_xfer_offset, 0);
399 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
400 }
401 
402 /*
403  * smb_handle_write_raw
404  *
405  * Called from smb_session_daemon() when the SMB command is SMB_COM_WRITE_RAW.
406  * Dispatches the command to the worker thread and waits until the worker
407  * has completed processing the command.
408  *
409  * Returns 0 for success, non-zero for failure
410  */
411 int
smb_handle_write_raw(smb_session_t * session,smb_request_t * sr)412 smb_handle_write_raw(smb_session_t *session, smb_request_t *sr)
413 {
414 	int	drop_reason = 0;
415 
416 	/*
417 	 * Set flag to indicate that we are waiting for raw data.  The
418 	 * worker thread will actually retrieve the raw data directly
419 	 * from the socket.  This should be the only case when a worker
420 	 * thread reads from the session socket.  When the data is read
421 	 * the worker will clear the flag.
422 	 */
423 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
424 	switch (session->s_state) {
425 	case SMB_SESSION_STATE_NEGOTIATED:
426 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
427 		session->s_state = SMB_SESSION_STATE_WRITE_RAW_ACTIVE;
428 		smb_rwx_rwexit(&session->s_lock);
429 		smb_srqueue_waitq_enter(session->s_srqueue);
430 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
431 		(void) taskq_dispatch(session->s_server->sv_worker_pool,
432 		    smb_session_worker, sr, TQ_SLEEP);
433 		smb_rwx_rwenter(&session->s_lock, RW_READER);
434 		while (session->s_state == SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
435 			(void) smb_rwx_rwwait(&session->s_lock, -1);
436 		}
437 		drop_reason = session->s_write_raw_status;
438 		break;
439 	default:
440 		drop_reason = 21;
441 		break;
442 	}
443 	smb_rwx_rwexit(&session->s_lock);
444 	return (drop_reason);
445 }
446 
447 /*
448  * smb_transfer_write_raw_data
449  *
450  * Handles the second transfer phase of SMB_COM_WRITE_RAW.  smb_com_write_raw()
451  * will process the parameters and data from the SMB and send the initial
452  * SMB response.  This function reads the remaining data from the socket
453  * as it arrives from the client.
454  *
455  * Clients may send KEEP_ALIVE messages (when using NBT) between the first
456  * and second parts of write raw requests.  The only session transport
457  * types accepted here are SESSION_MESSAGE or SESSION_KEEP_ALIVE.
458  *
459  * Returns 0 for success, non-zero for failure
460  */
461 int
smb_transfer_write_raw_data(smb_request_t * sr,smb_rw_param_t * param)462 smb_transfer_write_raw_data(smb_request_t *sr, smb_rw_param_t *param)
463 {
464 	smb_session_t *session = sr->session;
465 	smb_xprt_t hdr;
466 	void *pbuf;
467 
468 	do {
469 		if (smb_session_xprt_gethdr(session, &hdr) != 0)
470 			return (-1);
471 
472 		if ((hdr.xh_type == SESSION_MESSAGE) ||
473 		    (hdr.xh_type == SESSION_KEEP_ALIVE)) {
474 			session->keep_alive = smb_keep_alive;
475 		} else {
476 			return (-1);
477 		}
478 	} while (hdr.xh_type == SESSION_KEEP_ALIVE);
479 
480 	if (hdr.xh_length < param->rw_vdb.vdb_uio.uio_resid)
481 		return (-1); /* Less data than we were expecting. */
482 
483 	pbuf = smb_srm_alloc(sr, hdr.xh_length);
484 	if (smb_sorecv(session->sock, pbuf, hdr.xh_length) != 0)
485 		return (-1);
486 
487 	param->rw_vdb.vdb_iovec[0].iov_base = pbuf;
488 	param->rw_vdb.vdb_uio.uio_iovcnt = 1;
489 	param->rw_vdb.vdb_uio.uio_segflg = UIO_SYSSPACE;
490 	param->rw_vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
491 	return (0);
492 }
493