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