xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_open_andx.c (revision 3bd40d9837ed643779c04bcc9d85d24be281ef29)
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  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
26 #include <smbsrv/smb_kproto.h>
27 #include <smbsrv/smb_vops.h>
28 
29 int smb_open_dsize_check = 0;
30 
31 /*
32  *  Client Request                     Description
33  *  ================================== =================================
34  *
35  *  UCHAR WordCount;                   Count of parameter words = 15
36  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
37  *                                      none
38  *  UCHAR AndXReserved;                Reserved (must be 0)
39  *  USHORT AndXOffset;                 Offset to next command WordCount
40  *  USHORT Flags;                      Additional information: bit set-
41  *                                      0 - return additional info
42  *                                      1 - exclusive oplock requested
43  *                                      2 - batch oplock requested
44  *  USHORT DesiredAccess;              File open mode
45  *  USHORT SearchAttributes;
46  *  USHORT FileAttributes;
47  *  UTIME CreationTime;                Creation timestamp for file if it
48  *                                      gets created
49  *  USHORT OpenFunction;               Action to take if file exists
50  *  ULONG AllocationSize;              Bytes to reserve on create or
51  *                                      truncate
52  *  ULONG Reserved[2];                 Must be 0
53  *  USHORT ByteCount;                  Count of data bytes;    min = 1
54  *  UCHAR BufferFormat                 0x04
55  *  STRING FileName;
56  *
57  *  Server Response                    Description
58  *  ================================== =================================
59  *
60  *  UCHAR WordCount;                   Count of parameter words = 15
61  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
62  *                                      none
63  *  UCHAR AndXReserved;                Reserved (must be 0)
64  *  USHORT AndXOffset;                 Offset to next command WordCount
65  *  USHORT Fid;                        File handle
66  *  USHORT FileAttributes;
67  *  UTIME LastWriteTime;
68  *  ULONG DataSize;                    Current file size
69  *  USHORT GrantedAccess;              Access permissions actually
70  *                                      allowed
71  *  USHORT FileType;                   Type of file opened
72  *  USHORT DeviceState;                State of the named pipe
73  *  USHORT Action;                     Action taken
74  *  ULONG ServerFid;                   Server unique file id
75  *  USHORT Reserved;                   Reserved (must be 0)
76  *  USHORT ByteCount;                  Count of data bytes = 0
77  *
78  * DesiredAccess describes the access the client desires for the file (see
79  * section 3.6 -  Access Mode Encoding).
80  *
81  * OpenFunction specifies the action to be taken depending on whether or
82  * not the file exists (see section 3.8 -  Open Function Encoding).  Action
83  *
84  * in the response specifies the action as a result of the Open request
85  * (see section 3.9 -  Open Action Encoding).
86  *
87  * SearchAttributes indicates the attributes that the file must have to be
88  * found while searching to see if it exists.  The encoding of this field
89  * is described in the "File Attribute Encoding" section elsewhere in this
90  * document.  If SearchAttributes is zero then only normal files are
91  * returned.  If the system file, hidden or directory attributes are
92  * specified then the search is inclusive -- both the specified type(s) of
93  * files and normal files are returned.
94  *
95  * FileType returns the kind of resource actually opened:
96  *
97  *  Name                       Value  Description
98  *  ========================== ====== ==================================
99  *
100  *  FileTypeDisk               0      Disk file or directory as defined
101  *                                     in the attribute field
102  *  FileTypeByteModePipe       1      Named pipe in byte mode
103  *  FileTypeMessageModePipe    2      Named pipe in message mode
104  *  FileTypePrinter            3      Spooled printer
105  *  FileTypeUnknown            0xFFFF Unrecognized resource type
106  *
107  * If bit0 of Flags is clear, the FileAttributes, LastWriteTime, DataSize,
108  * FileType, and DeviceState have indeterminate values in the response.
109  *
110  * This SMB can request an oplock on the opened file.  Oplocks are fully
111  * described in the "Oplocks" section elsewhere in this document, and there
112  * is also discussion of oplocks in the SMB_COM_LOCKING_ANDX SMB
113  * description.  Bit1 and bit2 of the Flags field are used to request
114  * oplocks during open.
115  *
116  * The following SMBs may follow SMB_COM_OPEN_ANDX:
117  *
118  *    SMB_COM_READ    SMB_COM_READ_ANDX
119  *    SMB_COM_IOCTL
120  */
121 
122 /*
123  * This message is sent to obtain a file handle for a data file.  This
124  * returned Fid is used in subsequent client requests such as read, write,
125  * close, etc.
126  *
127  * Client Request                     Description
128  * ================================== =================================
129  *
130  * UCHAR WordCount;                   Count of parameter words = 2
131  * USHORT DesiredAccess;              Mode - read/write/share
132  * USHORT SearchAttributes;
133  * USHORT ByteCount;                  Count of data bytes;    min = 2
134  * UCHAR BufferFormat;                0x04
135  * STRING FileName[];                 File name
136  *
137  * FileName is the fully qualified file name, relative to the root of the
138  * share specified in the Tid field of the SMB header.  If Tid in the SMB
139  * header refers to a print share, this SMB creates a new file which will
140  * be spooled to the printer when closed.  In this case, FileName is
141  * ignored.
142  *
143  * SearchAttributes specifies the type of file desired.  The encoding is
144  * described in the "File Attribute Encoding" section.
145  *
146  * DesiredAccess controls the mode under which the file is opened, and the
147  * file will be opened only if the client has the appropriate permissions.
148  * The encoding of DesiredAccess is discussed in the section entitled
149  * "Access Mode Encoding".
150  *
151  * Server Response                    Description
152  * ================================== =================================
153  *
154  * UCHAR WordCount;                   Count of parameter words = 7
155  * USHORT Fid;                        File handle
156  * USHORT FileAttributes;             Attributes of opened file
157  * UTIME LastWriteTime;               Time file was last written
158  * ULONG DataSize;                    File size
159  * USHORT GrantedAccess;              Access allowed
160  * USHORT ByteCount;                  Count of data bytes = 0
161  *
162  * Fid is the handle value which should be used for subsequent file
163  * operations.
164  *
165  * FileAttributes specifies the type of file obtained.  The encoding is
166  * described in the "File Attribute Encoding" section.
167  *
168  * GrantedAccess indicates the access permissions actually allowed, and may
169  * have one of the following values:
170  *
171  *    0  read-only
172  *    1  write-only
173  *    2 read/write
174  *
175  * File Handles (Fids) are scoped per client.  A Pid may reference any Fid
176  * established by itself or any other Pid on the client (so far as the
177  * server is concerned).  The actual accesses allowed through the Fid
178  * depends on the open and deny modes specified when the file was opened
179  * (see below).
180  *
181  * The MS-DOS compatibility mode of file open provides exclusion at the
182  * client level.  A file open in compatibility mode may be opened (also in
183  * compatibility mode) any number of times for any combination of reading
184  * and writing (subject to the user's permissions) by any Pid on the same
185  * client.  If the first client has the file open for writing, then the
186  * file may not be opened in any way by any other client.  If the first
187  * client has the file open only for reading, then other clients may open
188  * the file, in compatibility mode, for reading..  The above
189  * notwithstanding, if the filename has an extension of .EXE, .DLL, .SYM,
190  * or .COM other clients are permitted to open the file regardless of
191  * read/write open modes of other compatibility mode opens.  However, once
192  * multiple clients have the file open for reading, no client is permitted
193  * to open the file for writing and no other client may open the file in
194  * any mode other than compatibility mode.
195  *
196  * The other file exclusion modes (Deny read/write, Deny write, Deny read,
197  * Deny none) provide exclusion at the file level.  A file opened in any
198  * "Deny" mode may be opened again only for the accesses allowed by the
199  * Deny mode (subject to the user's permissions).  This is true regardless
200  * of the identity of the second opener -a different client, a Pid from the
201  * same client, or the Pid that already has the file open.  For example, if
202  * a file is open in "Deny write" mode a second open may only obtain read
203  * permission to the file.
204  *
205  * Although Fids are available to all Pids on a client, Pids other than the
206  * owner may not have the full access rights specified in the open mode by
207  * the Fid's creator.  If the open creating the Fid specified a deny mode,
208  * then any Pid using the Fid, other than the creating Pid, will have only
209  * those access rights determined by "anding" the open mode rights and the
210  * deny mode rights, i.e., the deny mode is checked on all file accesses.
211  * For example, if a file is opened for Read/Write in Deny write mode, then
212  * other clients may only read the file and cannot write; if a file is
213  * opened for Read in Deny read mode, then the other clients can neither
214  * read nor write the file.
215  */
216 
217 smb_sdrc_t
218 smb_pre_open(smb_request_t *sr)
219 {
220 	struct open_param *op = &sr->arg.open;
221 	int rc;
222 
223 	bzero(op, sizeof (sr->arg.open));
224 
225 	rc = smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.fq_sattr);
226 	if (rc == 0)
227 		rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path);
228 
229 	DTRACE_SMB_2(op__Open__start, smb_request_t *, sr,
230 	    struct open_param *, op);
231 
232 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
233 }
234 
235 void
236 smb_post_open(smb_request_t *sr)
237 {
238 	DTRACE_SMB_1(op__Open__done, smb_request_t *, sr);
239 }
240 
241 smb_sdrc_t
242 smb_com_open(smb_request_t *sr)
243 {
244 	struct open_param *op = &sr->arg.open;
245 	smb_ofile_t *of;
246 	smb_attr_t attr;
247 	uint32_t status;
248 	uint16_t file_attr;
249 	int rc;
250 
251 	op->desired_access = smb_omode_to_amask(op->omode);
252 	op->share_access = smb_denymode_to_sharemode(op->omode,
253 	    op->fqi.fq_path.pn_path);
254 	op->crtime.tv_sec = op->crtime.tv_nsec = 0;
255 	op->create_disposition = FILE_OPEN;
256 	op->create_options = FILE_NON_DIRECTORY_FILE;
257 	if (op->omode & SMB_DA_WRITE_THROUGH)
258 		op->create_options |= FILE_WRITE_THROUGH;
259 
260 	if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
261 		if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
262 			op->op_oplock_level = SMB_OPLOCK_BATCH;
263 		else
264 			op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
265 	} else {
266 		op->op_oplock_level = SMB_OPLOCK_NONE;
267 	}
268 	op->op_oplock_levelII = B_FALSE;
269 
270 	if (smb_open_dsize_check && op->dsize > UINT_MAX) {
271 		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
272 		return (SDRC_ERROR);
273 	}
274 
275 	status = smb_common_open(sr);
276 	if (status != NT_STATUS_SUCCESS) {
277 		smbsr_status(sr, status, 0, 0);
278 		return (SDRC_ERROR);
279 	}
280 
281 	/*
282 	 * NB: after the above smb_common_open() success,
283 	 * we have a handle allocated (sr->fid_ofile).
284 	 * If we don't return success, we must close it.
285 	 */
286 	of = sr->fid_ofile;
287 
288 	if (op->op_oplock_level == SMB_OPLOCK_NONE) {
289 		sr->smb_flg &=
290 		    ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
291 	}
292 
293 	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
294 	bzero(&attr, sizeof (attr));
295 	attr.sa_mask = SMB_AT_MTIME;
296 	rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr);
297 	if (rc != 0) {
298 		smbsr_errno(sr, rc);
299 		goto errout;
300 	}
301 
302 	rc = smbsr_encode_result(sr, 7, 0, "bwwllww",
303 	    7,
304 	    sr->smb_fid,
305 	    file_attr,
306 	    smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
307 	    (uint32_t)op->dsize,
308 	    op->omode,
309 	    (uint16_t)0);	/* bcc */
310 
311 	if (rc == 0)
312 		return (SDRC_SUCCESS);
313 
314 errout:
315 	smb_ofile_close(of, 0);
316 	return (SDRC_ERROR);
317 }
318 
319 /*
320  * smb_pre_open_andx
321  * For compatibility with windows servers, the search attributes
322  * specified in the request are ignored.
323  */
324 smb_sdrc_t
325 smb_pre_open_andx(smb_request_t *sr)
326 {
327 	struct open_param *op = &sr->arg.open;
328 	uint16_t flags;
329 	uint32_t alloc_size;
330 	uint32_t creation_time;
331 	uint16_t file_attr, sattr;
332 	int rc;
333 
334 	bzero(op, sizeof (sr->arg.open));
335 
336 	rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
337 	    &sr->andx_off, &flags, &op->omode, &sattr,
338 	    &file_attr, &creation_time, &op->ofun, &alloc_size, &op->timeo);
339 
340 	if (rc == 0) {
341 		rc = smbsr_decode_data(sr, "%u", sr, &op->fqi.fq_path.pn_path);
342 
343 		op->dattr = file_attr;
344 		op->dsize = alloc_size;
345 
346 		if (flags & 2)
347 			op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
348 		else if (flags & 4)
349 			op->op_oplock_level = SMB_OPLOCK_BATCH;
350 		else
351 			op->op_oplock_level = SMB_OPLOCK_NONE;
352 
353 		if ((creation_time != 0) && (creation_time != UINT_MAX))
354 			op->crtime.tv_sec =
355 			    smb_time_local_to_gmt(sr, creation_time);
356 		op->crtime.tv_nsec = 0;
357 
358 		op->create_disposition = smb_ofun_to_crdisposition(op->ofun);
359 	}
360 
361 	DTRACE_SMB_2(op__OpenX__start, smb_request_t *, sr,
362 	    struct open_param *, op);
363 
364 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
365 }
366 
367 void
368 smb_post_open_andx(smb_request_t *sr)
369 {
370 	DTRACE_SMB_1(op__OpenX__done, smb_request_t *, sr);
371 }
372 
373 smb_sdrc_t
374 smb_com_open_andx(smb_request_t *sr)
375 {
376 	struct open_param	*op = &sr->arg.open;
377 	smb_ofile_t		*of;
378 	uint32_t		status;
379 	uint16_t		file_attr;
380 	smb_attr_t		attr;
381 	int rc;
382 
383 	op->desired_access = smb_omode_to_amask(op->omode);
384 	op->share_access = smb_denymode_to_sharemode(op->omode,
385 	    op->fqi.fq_path.pn_path);
386 
387 	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
388 		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
389 		return (SDRC_ERROR);
390 	}
391 
392 	op->create_options = FILE_NON_DIRECTORY_FILE;
393 	if (op->omode & SMB_DA_WRITE_THROUGH)
394 		op->create_options |= FILE_WRITE_THROUGH;
395 
396 	op->op_oplock_levelII = B_FALSE;
397 
398 	if (smb_open_dsize_check && op->dsize > UINT_MAX) {
399 		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
400 		return (SDRC_ERROR);
401 	}
402 
403 	status = smb_common_open(sr);
404 	if (status != NT_STATUS_SUCCESS) {
405 		smbsr_status(sr, status, 0, 0);
406 		return (SDRC_ERROR);
407 	}
408 
409 	/*
410 	 * NB: after the above smb_common_open() success,
411 	 * we have a handle allocated (sr->fid_ofile).
412 	 * If we don't return success, we must close it.
413 	 */
414 	of = sr->fid_ofile;
415 
416 	if (op->op_oplock_level != SMB_OPLOCK_NONE)
417 		op->action_taken |= SMB_OACT_LOCK;
418 	else
419 		op->action_taken &= ~SMB_OACT_LOCK;
420 
421 	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
422 	bzero(&attr, sizeof (attr));
423 
424 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
425 	case STYPE_DISKTREE:
426 	case STYPE_PRINTQ:
427 		attr.sa_mask = SMB_AT_MTIME;
428 		rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr);
429 		if (rc != 0) {
430 			smbsr_errno(sr, rc);
431 			goto errout;
432 		}
433 
434 		rc = smbsr_encode_result(sr, 15, 0,
435 		    "bb.wwwllwwwwl2.w",
436 		    15,
437 		    sr->andx_com, VAR_BCC,
438 		    sr->smb_fid,
439 		    file_attr,
440 		    smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
441 		    (uint32_t)op->dsize,
442 		    op->omode, op->ftype,
443 		    op->devstate,
444 		    op->action_taken, op->fileid,
445 		    0);
446 		break;
447 
448 	case STYPE_IPC:
449 		rc = smbsr_encode_result(sr, 15, 0,
450 		    "bb.wwwllwwwwl2.w",
451 		    15,
452 		    sr->andx_com, VAR_BCC,
453 		    sr->smb_fid,
454 		    file_attr,
455 		    0L,
456 		    0L,
457 		    op->omode, op->ftype,
458 		    op->devstate,
459 		    op->action_taken, op->fileid,
460 		    0);
461 		break;
462 
463 	default:
464 		smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
465 		    ERRDOS, ERROR_INVALID_FUNCTION);
466 		goto errout;
467 	}
468 
469 	if (rc == 0)
470 		return (SDRC_SUCCESS);
471 
472 errout:
473 	smb_ofile_close(of, 0);
474 	return (SDRC_ERROR);
475 }
476 
477 smb_sdrc_t
478 smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
479 {
480 	struct open_param *op = &sr->arg.open;
481 	uint32_t	creation_time;
482 	uint32_t	alloc_size;
483 	uint32_t	ea_list_size;
484 	uint16_t	flags;
485 	uint16_t	file_attr;
486 	uint32_t	status;
487 	int		rc;
488 
489 	bzero(op, sizeof (sr->arg.open));
490 
491 	rc = smb_mbc_decodef(&xa->req_param_mb, "%wwwwlwl10.u",
492 	    sr, &flags, &op->omode, &op->fqi.fq_sattr, &file_attr,
493 	    &creation_time, &op->ofun, &alloc_size, &op->fqi.fq_path.pn_path);
494 	if (rc != 0)
495 		return (SDRC_ERROR);
496 
497 	/*
498 	 * The data part of this transaction may contain an EA list.
499 	 * See: SMB_FEA_LIST ExtendedAttributeList
500 	 *
501 	 * If we find a non-empty EA list payload, return the special
502 	 * error that tells the caller this FS does not suport EAs.
503 	 *
504 	 * Note: the first word is the size of the whole data segment,
505 	 * INCLUDING the size of that length word.  That means if
506 	 * the length word specifies a size less than four, it's
507 	 * invalid (and probably a client trying something fishy).
508 	 */
509 	rc = smb_mbc_decodef(&xa->req_data_mb, "l", &ea_list_size);
510 	if (rc == 0 && ea_list_size > 4) {
511 		smbsr_status(sr, NT_STATUS_EAS_NOT_SUPPORTED, 0, 0);
512 		return (SDRC_ERROR);
513 	}
514 
515 	if ((creation_time != 0) && (creation_time != UINT_MAX))
516 		op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time);
517 	op->crtime.tv_nsec = 0;
518 
519 	op->dattr = file_attr;
520 	op->dsize = alloc_size;
521 	op->create_options = FILE_NON_DIRECTORY_FILE;
522 
523 	op->desired_access = smb_omode_to_amask(op->omode);
524 	op->share_access = smb_denymode_to_sharemode(op->omode,
525 	    op->fqi.fq_path.pn_path);
526 
527 	op->create_disposition = smb_ofun_to_crdisposition(op->ofun);
528 	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION)
529 		op->create_disposition = FILE_CREATE;
530 
531 	if (op->omode & SMB_DA_WRITE_THROUGH)
532 		op->create_options |= FILE_WRITE_THROUGH;
533 
534 	if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
535 		if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
536 			op->op_oplock_level = SMB_OPLOCK_BATCH;
537 		else
538 			op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
539 	} else {
540 		op->op_oplock_level = SMB_OPLOCK_NONE;
541 	}
542 	op->op_oplock_levelII = B_FALSE;
543 
544 	status = smb_common_open(sr);
545 	if (status != NT_STATUS_SUCCESS) {
546 		smbsr_status(sr, status, 0, 0);
547 		return (SDRC_ERROR);
548 	}
549 
550 	if (op->op_oplock_level != SMB_OPLOCK_NONE)
551 		op->action_taken |= SMB_OACT_LOCK;
552 	else
553 		op->action_taken &= ~SMB_OACT_LOCK;
554 
555 	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
556 
557 	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
558 		op->dsize = 0;
559 
560 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwllwwwwlwl",
561 	    sr->smb_fid,
562 	    file_attr,
563 	    (uint32_t)0,	/* creation time */
564 	    (uint32_t)op->dsize,
565 	    op->omode,
566 	    op->ftype,
567 	    op->devstate,
568 	    op->action_taken,
569 	    op->fileid,
570 	    (uint16_t)0,	/* EA error offset */
571 	    (uint32_t)0);	/* EA list length */
572 
573 	return (SDRC_SUCCESS);
574 }
575