xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_open_andx.c (revision 6030:6bebab7d43d5)
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	"%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 smb_sdrc_t
227 smb_com_open(struct smb_request *sr)
228 {
229 	struct open_param *op = &sr->arg.open;
230 	uint16_t file_attr;
231 	int rc;
232 
233 	bzero(op, sizeof (sr->arg.open));
234 	if (smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.srch_attr) != 0)
235 		return (SDRC_ERROR_REPLY);
236 
237 	if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0)
238 		return (SDRC_ERROR_REPLY);
239 
240 	op->desired_access = smb_omode_to_amask(op->omode);
241 	op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
242 
243 	if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
244 	    (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
245 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
246 		    ERRDOS, ERROR_INVALID_PARAMETER);
247 		return (SDRC_ERROR_REPLY);
248 	}
249 
250 	op->dsize = 0; /* Don't set spurious size */
251 	op->utime.tv_sec = op->utime.tv_nsec = 0;
252 	op->create_disposition = FILE_OPEN;
253 	op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
254 	    ? FILE_WRITE_THROUGH : 0;
255 
256 	if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
257 		if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
258 			op->my_flags = MYF_BATCH_OPLOCK;
259 		} else {
260 			op->my_flags = MYF_EXCLUSIVE_OPLOCK;
261 		}
262 	}
263 
264 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
265 		return (SDRC_ERROR_REPLY);
266 
267 	if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
268 		sr->smb_flg &=
269 		    ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
270 	}
271 
272 	if (op->dsize > UINT_MAX) {
273 		smbsr_error(sr, 0, ERRDOS, ERRbadfunc);
274 		return (SDRC_ERROR_REPLY);
275 	}
276 
277 	file_attr = op->dattr  & FILE_ATTRIBUTE_MASK;
278 
279 	rc = smbsr_encode_result(sr, 7, 0, "bwwllww",
280 	    7,
281 	    sr->smb_fid,
282 	    file_attr,
283 	    smb_gmt_to_local_time(op->utime.tv_sec),
284 	    (uint32_t)op->dsize,
285 	    op->omode & SMB_DA_ACCESS_MASK,
286 	    (uint16_t)0);	/* bcc */
287 
288 	return ((rc == 0) ? SDRC_NORMAL_REPLY : SDRC_ERROR_REPLY);
289 }
290 
291 smb_sdrc_t
292 smb_com_open_andx(struct smb_request *sr)
293 {
294 	struct open_param	*op = &sr->arg.open;
295 	uint16_t		flags;
296 	uint32_t		CreationTime;
297 	uint16_t		granted_access;
298 	uint16_t		ofun;
299 	uint16_t		file_attr;
300 	int rc;
301 
302 	bzero(op, sizeof (sr->arg.open));
303 	op->dsize = 0;
304 	rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
305 	    &sr->andx_off, &flags, &op->omode, &op->fqi.srch_attr,
306 	    &file_attr, &CreationTime, &ofun, &op->dsize, &op->timeo);
307 	if (rc != 0)
308 		return (SDRC_ERROR_REPLY);
309 
310 	if (smbsr_decode_data(sr, "%u", sr, &op->fqi.path) != 0)
311 		return (SDRC_ERROR_REPLY);
312 
313 	op->desired_access = smb_omode_to_amask(op->omode);
314 	op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
315 
316 	if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
317 	    (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
318 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
319 		    ERRDOS, ERROR_INVALID_PARAMETER);
320 		return (SDRC_ERROR_REPLY);
321 	}
322 
323 	op->dattr = file_attr;
324 	op->create_disposition = smb_ofun_to_crdisposition(ofun);
325 	if (op->create_disposition == ((uint32_t)SMB_INVALID_CRDISPOSITION)) {
326 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_PARAMETER);
327 		return (SDRC_ERROR_REPLY);
328 	}
329 
330 	op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
331 	    ? FILE_WRITE_THROUGH : 0;
332 
333 	if (flags & 2)
334 		op->my_flags = MYF_EXCLUSIVE_OPLOCK;
335 	else if (flags & 4)
336 		op->my_flags = MYF_BATCH_OPLOCK;
337 
338 	if ((CreationTime != 0) && (CreationTime != UINT_MAX))
339 		op->utime.tv_sec = smb_local_time_to_gmt(CreationTime);
340 	op->utime.tv_nsec = 0;
341 
342 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
343 		return (SDRC_ERROR_REPLY);
344 
345 	if (op->dsize > UINT_MAX) {
346 		smbsr_error(sr, 0, ERRDOS, ERRbadfunc);
347 		return (SDRC_ERROR_REPLY);
348 	}
349 
350 	if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) {
351 		op->action_taken |= SMB_OACT_LOCK;
352 	} else {
353 		op->action_taken &= ~SMB_OACT_LOCK;
354 	}
355 
356 	granted_access = (sr->tid_tree->t_access == SMB_TREE_READ_ONLY)
357 	    ? SMB_DA_ACCESS_READ : op->omode & SMB_DA_ACCESS_MASK;
358 
359 	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
360 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
361 		smb_node_t *node = sr->fid_ofile->f_node;
362 		rc = smbsr_encode_result(sr, 15, 0,
363 		    "b b.w w wll www wl 2. w",
364 		    15,
365 		    sr->andx_com, VAR_BCC,
366 		    sr->smb_fid,
367 		    file_attr,
368 		    smb_gmt_to_local_time(node->attr.sa_vattr.va_mtime.tv_sec),
369 		    (uint32_t)op->dsize,
370 		    granted_access, op->ftype,
371 		    op->devstate,
372 		    op->action_taken, op->fileid,
373 		    0);
374 	} else {
375 		rc = smbsr_encode_result(sr, 15, 0,
376 		    "b b.w w wll www wl 2. w",
377 		    15,
378 		    sr->andx_com, VAR_BCC,
379 		    sr->smb_fid,
380 		    file_attr,
381 		    0L,
382 		    0L,
383 		    granted_access, op->ftype,
384 		    op->devstate,
385 		    op->action_taken, op->fileid,
386 		    0);
387 	}
388 
389 	return ((rc == 0) ? SDRC_NORMAL_REPLY : SDRC_ERROR_REPLY);
390 }
391