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