xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_open_andx.c (revision 3f318a288186db82aae78875c429f248622cf19f)
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 #pragma ident	"@(#)smb_open_andx.c	1.8	08/08/07 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 smb_sdrc_t
227 smb_pre_open(smb_request_t *sr)
228 {
229 	struct open_param *op = &sr->arg.open;
230 	int rc;
231 
232 	bzero(op, sizeof (sr->arg.open));
233 
234 	rc = smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.srch_attr);
235 	if (rc == 0)
236 		rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.path);
237 
238 	DTRACE_SMB_2(op__Open__start, smb_request_t *, sr,
239 	    struct open_param *, op);
240 
241 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
242 }
243 
244 void
245 smb_post_open(smb_request_t *sr)
246 {
247 	DTRACE_SMB_1(op__Open__done, smb_request_t *, sr);
248 }
249 
250 smb_sdrc_t
251 smb_com_open(smb_request_t *sr)
252 {
253 	struct open_param *op = &sr->arg.open;
254 	smb_node_t *node;
255 	uint16_t file_attr;
256 	int rc;
257 
258 	op->desired_access = smb_omode_to_amask(op->omode);
259 	op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
260 
261 	if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
262 	    (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
263 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
264 		    ERRDOS, ERROR_INVALID_PARAMETER);
265 		return (SDRC_ERROR);
266 	}
267 
268 	op->dsize = 0; /* Don't set spurious size */
269 	op->crtime.tv_sec = op->crtime.tv_nsec = 0;
270 	op->create_disposition = FILE_OPEN;
271 	op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
272 	    ? FILE_WRITE_THROUGH : 0;
273 
274 	if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
275 		if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
276 			op->my_flags = MYF_BATCH_OPLOCK;
277 		} else {
278 			op->my_flags = MYF_EXCLUSIVE_OPLOCK;
279 		}
280 	}
281 
282 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
283 		return (SDRC_ERROR);
284 
285 	if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
286 		sr->smb_flg &=
287 		    ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
288 	}
289 
290 	if (op->dsize > UINT_MAX) {
291 		smbsr_error(sr, 0, ERRDOS, ERRbadfunc);
292 		return (SDRC_ERROR);
293 	}
294 
295 	file_attr = op->dattr  & FILE_ATTRIBUTE_MASK;
296 	node = sr->fid_ofile->f_node;
297 
298 	rc = smbsr_encode_result(sr, 7, 0, "bwwllww",
299 	    7,
300 	    sr->smb_fid,
301 	    file_attr,
302 	    smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec),
303 	    (uint32_t)op->dsize,
304 	    op->omode & SMB_DA_ACCESS_MASK,
305 	    (uint16_t)0);	/* bcc */
306 
307 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
308 }
309 
310 smb_sdrc_t
311 smb_pre_open_andx(smb_request_t *sr)
312 {
313 	struct open_param *op = &sr->arg.open;
314 	uint16_t flags;
315 	uint32_t creation_time;
316 	uint16_t file_attr;
317 	uint16_t ofun;
318 	int rc;
319 
320 	bzero(op, sizeof (sr->arg.open));
321 
322 	rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
323 	    &sr->andx_off, &flags, &op->omode, &op->fqi.srch_attr,
324 	    &file_attr, &creation_time, &ofun, &op->dsize, &op->timeo);
325 
326 	if (rc == 0) {
327 		rc = smbsr_decode_data(sr, "%u", sr, &op->fqi.path);
328 
329 		op->dattr = file_attr;
330 
331 		if (flags & 2)
332 			op->my_flags = MYF_EXCLUSIVE_OPLOCK;
333 		else if (flags & 4)
334 			op->my_flags = MYF_BATCH_OPLOCK;
335 
336 		if ((creation_time != 0) && (creation_time != UINT_MAX))
337 			op->crtime.tv_sec = smb_local2gmt(sr, creation_time);
338 		op->crtime.tv_nsec = 0;
339 
340 		op->create_disposition = smb_ofun_to_crdisposition(ofun);
341 	}
342 
343 	DTRACE_SMB_2(op__OpenX__start, smb_request_t *, sr,
344 	    struct open_param *, op);
345 
346 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
347 }
348 
349 void
350 smb_post_open_andx(smb_request_t *sr)
351 {
352 	DTRACE_SMB_1(op__OpenX__done, smb_request_t *, sr);
353 }
354 
355 smb_sdrc_t
356 smb_com_open_andx(smb_request_t *sr)
357 {
358 	struct open_param	*op = &sr->arg.open;
359 	uint16_t		file_attr;
360 	uint16_t		granted_access;
361 	int rc;
362 
363 	op->desired_access = smb_omode_to_amask(op->omode);
364 	op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
365 
366 	if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
367 	    (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
368 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
369 		    ERRDOS, ERROR_INVALID_PARAMETER);
370 		return (SDRC_ERROR);
371 	}
372 
373 	if (op->create_disposition == ((uint32_t)SMB_INVALID_CRDISPOSITION)) {
374 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_PARAMETER);
375 		return (SDRC_ERROR);
376 	}
377 
378 	op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
379 	    ? FILE_WRITE_THROUGH : 0;
380 
381 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
382 		return (SDRC_ERROR);
383 
384 	if (op->dsize > UINT_MAX) {
385 		smbsr_error(sr, 0, ERRDOS, ERRbadfunc);
386 		return (SDRC_ERROR);
387 	}
388 
389 	if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) {
390 		op->action_taken |= SMB_OACT_LOCK;
391 	} else {
392 		op->action_taken &= ~SMB_OACT_LOCK;
393 	}
394 
395 	granted_access = (SMB_TREE_IS_READONLY(sr))
396 	    ? SMB_DA_ACCESS_READ : op->omode & SMB_DA_ACCESS_MASK;
397 
398 	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
399 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
400 		smb_node_t *node = sr->fid_ofile->f_node;
401 		rc = smbsr_encode_result(sr, 15, 0,
402 		    "bb.wwwllwwwwl2.w",
403 		    15,
404 		    sr->andx_com, VAR_BCC,
405 		    sr->smb_fid,
406 		    file_attr,
407 		    smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec),
408 		    (uint32_t)op->dsize,
409 		    granted_access, op->ftype,
410 		    op->devstate,
411 		    op->action_taken, op->fileid,
412 		    0);
413 	} else {
414 		rc = smbsr_encode_result(sr, 15, 0,
415 		    "bb.wwwllwwwwl2.w",
416 		    15,
417 		    sr->andx_com, VAR_BCC,
418 		    sr->smb_fid,
419 		    file_attr,
420 		    0L,
421 		    0L,
422 		    granted_access, op->ftype,
423 		    op->devstate,
424 		    op->action_taken, op->fileid,
425 		    0);
426 	}
427 
428 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
429 }
430