xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_open_andx.c (revision 942c5e3c2dd127463517e5cc1694ee94ca45e021)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <smbsrv/smb_vops.h>
29 
30 /*
31  * This module provides the common open functionality to the various
32  * open and create SMB interface functions.
33  */
34 
35 /*
36  *
37  *  Client Request                     Description
38  *  ================================== =================================
39  *
40  *  UCHAR WordCount;                   Count of parameter words = 15
41  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
42  *                                      none
43  *  UCHAR AndXReserved;                Reserved (must be 0)
44  *  USHORT AndXOffset;                 Offset to next command WordCount
45  *  USHORT Flags;                      Additional information: bit set-
46  *                                      0 - return additional info
47  *                                      1 - exclusive oplock requested
48  *                                      2 - batch oplock requested
49  *  USHORT DesiredAccess;              File open mode
50  *  USHORT SearchAttributes;
51  *  USHORT FileAttributes;
52  *  UTIME CreationTime;                Creation timestamp for file if it
53  *                                      gets created
54  *  USHORT OpenFunction;               Action to take if file exists
55  *  ULONG AllocationSize;              Bytes to reserve on create or
56  *                                      truncate
57  *  ULONG Reserved[2];                 Must be 0
58  *  USHORT ByteCount;                  Count of data bytes;    min = 1
59  *  UCHAR BufferFormat                 0x04
60  *  STRING FileName;
61  *
62  *  Server Response                    Description
63  *  ================================== =================================
64  *
65  *  UCHAR WordCount;                   Count of parameter words = 15
66  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
67  *                                      none
68  *  UCHAR AndXReserved;                Reserved (must be 0)
69  *  USHORT AndXOffset;                 Offset to next command WordCount
70  *  USHORT Fid;                        File handle
71  *  USHORT FileAttributes;
72  *  UTIME LastWriteTime;
73  *  ULONG DataSize;                    Current file size
74  *  USHORT GrantedAccess;              Access permissions actually
75  *                                      allowed
76  *  USHORT FileType;                   Type of file opened
77  *  USHORT DeviceState;                State of the named pipe
78  *  USHORT Action;                     Action taken
79  *  ULONG ServerFid;                   Server unique file id
80  *  USHORT Reserved;                   Reserved (must be 0)
81  *  USHORT ByteCount;                  Count of data bytes = 0
82  *
83  * DesiredAccess describes the access the client desires for the file (see
84  * section 3.6 -  Access Mode Encoding).
85  *
86  * OpenFunction specifies the action to be taken depending on whether or
87  * not the file exists (see section 3.8 -  Open Function Encoding).  Action
88  *
89  * in the response specifies the action as a result of the Open request
90  * (see section 3.9 -  Open Action Encoding).
91  *
92  * SearchAttributes indicates the attributes that the file must have to be
93  * found while searching to see if it exists.  The encoding of this field
94  * is described in the "File Attribute Encoding" section elsewhere in this
95  * document.  If SearchAttributes is zero then only normal files are
96  * returned.  If the system file, hidden or directory attributes are
97  * specified then the search is inclusive -- both the specified type(s) of
98  * files and normal files are returned.
99  *
100  * FileType returns the kind of resource actually opened:
101  *
102  *  Name                       Value  Description
103  *  ========================== ====== ==================================
104  *
105  *  FileTypeDisk               0      Disk file or directory as defined
106  *                                     in the attribute field
107  *  FileTypeByteModePipe       1      Named pipe in byte mode
108  *  FileTypeMessageModePipe    2      Named pipe in message mode
109  *  FileTypePrinter            3      Spooled printer
110  *  FileTypeUnknown            0xFFFF Unrecognized resource type
111  *
112  * If bit0 of Flags is clear, the FileAttributes, LastWriteTime, DataSize,
113  * FileType, and DeviceState have indeterminate values in the response.
114  *
115  * This SMB can request an oplock on the opened file.  Oplocks are fully
116  * described in the "Oplocks" section elsewhere in this document, and there
117  * is also discussion of oplocks in the SMB_COM_LOCKING_ANDX SMB
118  * description.  Bit1 and bit2 of the Flags field are used to request
119  * oplocks during open.
120  *
121  * The following SMBs may follow SMB_COM_OPEN_ANDX:
122  *
123  *    SMB_COM_READ    SMB_COM_READ_ANDX
124  *    SMB_COM_IOCTL
125  */
126 
127 #include <smbsrv/smb_incl.h>
128 
129 /*
130  * SMB: open
131  *
132  * This message is sent to obtain a file handle for a data file.  This
133  * returned Fid is used in subsequent client requests such as read, write,
134  * close, etc.
135  *
136  * Client Request                     Description
137  * ================================== =================================
138  *
139  * UCHAR WordCount;                   Count of parameter words = 2
140  * USHORT DesiredAccess;              Mode - read/write/share
141  * USHORT SearchAttributes;
142  * USHORT ByteCount;                  Count of data bytes;    min = 2
143  * UCHAR BufferFormat;                0x04
144  * STRING FileName[];                 File name
145  *
146  * FileName is the fully qualified file name, relative to the root of the
147  * share specified in the Tid field of the SMB header.  If Tid in the SMB
148  * header refers to a print share, this SMB creates a new file which will
149  * be spooled to the printer when closed.  In this case, FileName is
150  * ignored.
151  *
152  * SearchAttributes specifies the type of file desired.  The encoding is
153  * described in the "File Attribute Encoding" section.
154  *
155  * DesiredAccess controls the mode under which the file is opened, and the
156  * file will be opened only if the client has the appropriate permissions.
157  * The encoding of DesiredAccess is discussed in the section entitled
158  * "Access Mode Encoding".
159  *
160  * Server Response                    Description
161  * ================================== =================================
162  *
163  * UCHAR WordCount;                   Count of parameter words = 7
164  * USHORT Fid;                        File handle
165  * USHORT FileAttributes;             Attributes of opened file
166  * UTIME LastWriteTime;               Time file was last written
167  * ULONG DataSize;                    File size
168  * USHORT GrantedAccess;              Access allowed
169  * USHORT ByteCount;                  Count of data bytes = 0
170  *
171  * Fid is the handle value which should be used for subsequent file
172  * operations.
173  *
174  * FileAttributes specifies the type of file obtained.  The encoding is
175  * described in the "File Attribute Encoding" section.
176  *
177  * GrantedAccess indicates the access permissions actually allowed, and may
178  * have one of the following values:
179  *
180  *    0  read-only
181  *    1  write-only
182  *    2 read/write
183  *
184  * File Handles (Fids) are scoped per client.  A Pid may reference any Fid
185  * established by itself or any other Pid on the client (so far as the
186  * server is concerned).  The actual accesses allowed through the Fid
187  * depends on the open and deny modes specified when the file was opened
188  * (see below).
189  *
190  * The MS-DOS compatibility mode of file open provides exclusion at the
191  * client level.  A file open in compatibility mode may be opened (also in
192  * compatibility mode) any number of times for any combination of reading
193  * and writing (subject to the user's permissions) by any Pid on the same
194  * client.  If the first client has the file open for writing, then the
195  * file may not be opened in any way by any other client.  If the first
196  * client has the file open only for reading, then other clients may open
197  * the file, in compatibility mode, for reading..  The above
198  * notwithstanding, if the filename has an extension of .EXE, .DLL, .SYM,
199  * or .COM other clients are permitted to open the file regardless of
200  * read/write open modes of other compatibility mode opens.  However, once
201  * multiple clients have the file open for reading, no client is permitted
202  * to open the file for writing and no other client may open the file in
203  * any mode other than compatibility mode.
204  *
205  * The other file exclusion modes (Deny read/write, Deny write, Deny read,
206  * Deny none) provide exclusion at the file level.  A file opened in any
207  * "Deny" mode may be opened again only for the accesses allowed by the
208  * Deny mode (subject to the user's permissions).  This is true regardless
209  * of the identity of the second opener -a different client, a Pid from the
210  * same client, or the Pid that already has the file open.  For example, if
211  * a file is open in "Deny write" mode a second open may only obtain read
212  * permission to the file.
213  *
214  * Although Fids are available to all Pids on a client, Pids other than the
215  * owner may not have the full access rights specified in the open mode by
216  * the Fid's creator.  If the open creating the Fid specified a deny mode,
217  * then any Pid using the Fid, other than the creating Pid, will have only
218  * those access rights determined by "anding" the open mode rights and the
219  * deny mode rights, i.e., the deny mode is checked on all file accesses.
220  * For example, if a file is opened for Read/Write in Deny write mode, then
221  * other clients may only read the file and cannot write; if a file is
222  * opened for Read in Deny read mode, then the other clients can neither
223  * read nor write the file.
224  */
225 
226 int
227 smb_com_open(struct smb_request *sr)
228 {
229 	struct open_param *op = &sr->arg.open;
230 	uint16_t file_attr;
231 	DWORD status;
232 
233 	bzero(op, sizeof (sr->arg.open));
234 	if (smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.srch_attr) != 0) {
235 		smbsr_decode_error(sr);
236 		/* NOTREACHED */
237 	}
238 
239 	if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
240 		smbsr_decode_error(sr);
241 		/* NOTREACHED */
242 	}
243 	op->desired_access = smb_omode_to_amask(op->omode);
244 	op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
245 
246 	if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
247 	    (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
248 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
249 		    ERRDOS, ERROR_INVALID_PARAMETER);
250 		/* NOTREACHED */
251 	}
252 
253 	op->dsize = 0; /* Don't set spurious size */
254 	op->utime.tv_sec = op->utime.tv_nsec = 0;
255 	op->create_disposition = FILE_OPEN;
256 	op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
257 	    ? FILE_WRITE_THROUGH : 0;
258 
259 	if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
260 		if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
261 			op->my_flags = MYF_BATCH_OPLOCK;
262 		} else {
263 			op->my_flags = MYF_EXCLUSIVE_OPLOCK;
264 		}
265 	}
266 
267 	if ((status = smb_open_subr(sr)) != NT_STATUS_SUCCESS) {
268 		if (status == NT_STATUS_SHARING_VIOLATION)
269 			smbsr_raise_cifs_error(sr,
270 			    NT_STATUS_SHARING_VIOLATION,
271 			    ERRDOS, ERROR_SHARING_VIOLATION);
272 		else
273 			smbsr_raise_nt_error(sr, status);
274 
275 		/* NOTREACHED */
276 	}
277 
278 	if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
279 		sr->smb_flg &=
280 		    ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
281 	}
282 
283 	if (op->dsize > UINT_MAX)
284 		smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
285 
286 	file_attr = op->dattr  & FILE_ATTRIBUTE_MASK;
287 
288 	smbsr_encode_result(sr, 7, 0, "bwwllww",
289 	    7,
290 	    sr->smb_fid,
291 	    file_attr,
292 	    smb_gmt_to_local_time(op->utime.tv_sec),
293 	    (uint32_t)op->dsize,
294 	    op->omode & SMB_DA_ACCESS_MASK,
295 	    (uint16_t)0);	/* bcc */
296 
297 	return (SDRC_NORMAL_REPLY);
298 }
299 
300 int
301 smb_com_open_andx(struct smb_request *sr)
302 {
303 	struct open_param	*op = &sr->arg.open;
304 	uint16_t		flags;
305 	uint32_t		CreationTime;
306 	uint16_t		granted_access;
307 	uint16_t		ofun;
308 	uint16_t		file_attr;
309 	int count;
310 	DWORD status;
311 	int rc;
312 
313 	bzero(op, sizeof (sr->arg.open));
314 	op->dsize = 0;
315 	rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
316 	    &sr->andx_off, &flags, &op->omode, &op->fqi.srch_attr,
317 	    &file_attr, &CreationTime, &ofun, &op->dsize, &op->timeo);
318 	if (rc != 0) {
319 		smbsr_decode_error(sr);
320 		/* NOTREACHED */
321 	}
322 
323 	if (smbsr_decode_data(sr, "%u", sr, &op->fqi.path) != 0) {
324 		smbsr_decode_error(sr);
325 		/* NOTREACHED */
326 	}
327 
328 	op->desired_access = smb_omode_to_amask(op->omode);
329 	op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
330 
331 	if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
332 	    (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
333 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
334 		    ERRDOS, ERROR_INVALID_PARAMETER);
335 		/* NOTREACHED */
336 	}
337 
338 	op->dattr = file_attr;
339 	op->create_disposition = smb_ofun_to_crdisposition(ofun);
340 	if (op->create_disposition == ((uint32_t)SMB_INVALID_CRDISPOSITION)) {
341 		smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_PARAMETER);
342 		/* NOTREACHED */
343 	}
344 
345 	op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
346 	    ? FILE_WRITE_THROUGH : 0;
347 
348 	if (flags & 2)
349 		op->my_flags = MYF_EXCLUSIVE_OPLOCK;
350 	else if (flags & 4)
351 		op->my_flags = MYF_BATCH_OPLOCK;
352 
353 	if ((CreationTime != 0) && (CreationTime != UINT_MAX))
354 		op->utime.tv_sec = smb_local_time_to_gmt(CreationTime);
355 	op->utime.tv_nsec = 0;
356 
357 	status = NT_STATUS_SUCCESS;
358 	/*
359 	 * According to NT, when exclusive share access failed,
360 	 * instead of raising "access deny" error immediately,
361 	 * we should wait for the client holding the exclusive
362 	 * file to close the file. If the wait timed out, we
363 	 * report a sharing violation; otherwise, we grant access.
364 	 * smb_open_subr returns NT_STATUS_SHARING_VIOLATION when
365 	 * it encounters an exclusive share access deny: we wait
366 	 * and retry.
367 	 */
368 	for (count = 0; count <= 4; count++) {
369 		if (count) {
370 			delay(MSEC_TO_TICK(400));
371 		}
372 
373 		if ((status = smb_open_subr(sr)) == NT_STATUS_SUCCESS)
374 			break;
375 	}
376 
377 	if (status != NT_STATUS_SUCCESS) {
378 		if (status == NT_STATUS_SHARING_VIOLATION)
379 			smbsr_raise_cifs_error(sr,
380 			    NT_STATUS_SHARING_VIOLATION,
381 			    ERRDOS, ERROR_SHARING_VIOLATION);
382 		else
383 			smbsr_raise_nt_error(sr, status);
384 
385 		/* NOTREACHED */
386 	}
387 
388 	if (op->dsize > UINT_MAX)
389 		smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
390 
391 	if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) {
392 		op->action_taken |= SMB_OACT_LOCK;
393 	} else {
394 		op->action_taken &= ~SMB_OACT_LOCK;
395 	}
396 
397 	granted_access = (sr->tid_tree->t_access == SMB_TREE_READ_ONLY)
398 	    ? SMB_DA_ACCESS_READ : op->omode & SMB_DA_ACCESS_MASK;
399 
400 	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
401 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
402 		smb_node_t *node = sr->fid_ofile->f_node;
403 		smbsr_encode_result(sr, 15, 0,
404 		    "b b.w w wll www wl 2. w",
405 		    15,
406 		    sr->andx_com, VAR_BCC,
407 		    sr->smb_fid,
408 		    file_attr,
409 		    smb_gmt_to_local_time(node->attr.sa_vattr.va_mtime.tv_sec),
410 		    (uint32_t)op->dsize,
411 		    granted_access, op->ftype,
412 		    op->devstate,
413 		    op->action_taken, op->fileid,
414 		    0);
415 	} else {
416 		smbsr_encode_result(sr, 15, 0,
417 		    "b b.w w wll www wl 2. w",
418 		    15,
419 		    sr->andx_com, VAR_BCC,
420 		    sr->smb_fid,
421 		    file_attr,
422 		    0L,
423 		    0L,
424 		    granted_access, op->ftype,
425 		    op->devstate,
426 		    op->action_taken, op->fileid,
427 		    0);
428 	}
429 
430 	return (SDRC_NORMAL_REPLY);
431 }
432