1*da6c28aaSamw /* 2*da6c28aaSamw * CDDL HEADER START 3*da6c28aaSamw * 4*da6c28aaSamw * The contents of this file are subject to the terms of the 5*da6c28aaSamw * Common Development and Distribution License (the "License"). 6*da6c28aaSamw * You may not use this file except in compliance with the License. 7*da6c28aaSamw * 8*da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10*da6c28aaSamw * See the License for the specific language governing permissions 11*da6c28aaSamw * and limitations under the License. 12*da6c28aaSamw * 13*da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14*da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16*da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17*da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18*da6c28aaSamw * 19*da6c28aaSamw * CDDL HEADER END 20*da6c28aaSamw */ 21*da6c28aaSamw /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*da6c28aaSamw * Use is subject to license terms. 24*da6c28aaSamw */ 25*da6c28aaSamw 26*da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27*da6c28aaSamw 28*da6c28aaSamw /* 29*da6c28aaSamw * This module provides the common open functionality to the various 30*da6c28aaSamw * open and create SMB interface functions. 31*da6c28aaSamw */ 32*da6c28aaSamw 33*da6c28aaSamw #include <smbsrv/smb_incl.h> 34*da6c28aaSamw #include <smbsrv/smb_fsops.h> 35*da6c28aaSamw #include <smbsrv/mlsvc.h> 36*da6c28aaSamw #include <smbsrv/nterror.h> 37*da6c28aaSamw #include <smbsrv/ntstatus.h> 38*da6c28aaSamw #include <smbsrv/smbinfo.h> 39*da6c28aaSamw #include <sys/fcntl.h> 40*da6c28aaSamw 41*da6c28aaSamw extern uint32_t smb_is_executable(char *path); 42*da6c28aaSamw 43*da6c28aaSamw #define DENY_READ(share_access) ((share_access & FILE_SHARE_READ) == 0) 44*da6c28aaSamw 45*da6c28aaSamw #define DENY_WRITE(share_access) ((share_access & FILE_SHARE_WRITE) == 0) 46*da6c28aaSamw 47*da6c28aaSamw #define DENY_DELETE(share_access) ((share_access & FILE_SHARE_DELETE) == 0) 48*da6c28aaSamw 49*da6c28aaSamw #define DENY_RW(share_access) \ 50*da6c28aaSamw ((share_access & (FILE_SHARE_READ | FILE_SHARE_WRITE)) == 0) 51*da6c28aaSamw 52*da6c28aaSamw #define DENY_ALL(share_access) (share_access == 0) 53*da6c28aaSamw 54*da6c28aaSamw #define DENY_NONE(share_access) (share_access == FILE_SHARE_ALL) 55*da6c28aaSamw 56*da6c28aaSamw /* 57*da6c28aaSamw * The default stability mode is to perform the write-through 58*da6c28aaSamw * behaviour requested by the client. 59*da6c28aaSamw */ 60*da6c28aaSamw int smb_stable_mode = 0; 61*da6c28aaSamw 62*da6c28aaSamw 63*da6c28aaSamw /* 64*da6c28aaSamw * This macro is used to delete a newly created object 65*da6c28aaSamw * if any error happens after creation of object. 66*da6c28aaSamw */ 67*da6c28aaSamw #define SMB_DEL_NEWOBJ(obj) \ 68*da6c28aaSamw if (created) { \ 69*da6c28aaSamw if (is_dir) \ 70*da6c28aaSamw (void) smb_fsop_rmdir(sr, sr->user_cr, \ 71*da6c28aaSamw obj.dir_snode, obj.last_comp, 0); \ 72*da6c28aaSamw else \ 73*da6c28aaSamw (void) smb_fsop_remove(sr, sr->user_cr, \ 74*da6c28aaSamw obj.dir_snode, obj.last_comp, 0); \ 75*da6c28aaSamw } 76*da6c28aaSamw 77*da6c28aaSamw /* 78*da6c28aaSamw * smb_set_stability 79*da6c28aaSamw * 80*da6c28aaSamw * Set the default stability mode. Normal (mode is zero) means perform 81*da6c28aaSamw * the write-through behaviour requested by the client. Synchronous 82*da6c28aaSamw * (mode is non-zero) means journal everything regardless of the write 83*da6c28aaSamw * through behaviour requested by the client. 84*da6c28aaSamw */ 85*da6c28aaSamw void 86*da6c28aaSamw smb_set_stability(int mode) 87*da6c28aaSamw { 88*da6c28aaSamw smb_stable_mode = mode; 89*da6c28aaSamw } 90*da6c28aaSamw 91*da6c28aaSamw /* 92*da6c28aaSamw * smb_access_generic_to_file 93*da6c28aaSamw * 94*da6c28aaSamw * Search MSDN for IoCreateFile to see following mapping. 95*da6c28aaSamw * 96*da6c28aaSamw * GENERIC_READ STANDARD_RIGHTS_READ, FILE_READ_DATA, 97*da6c28aaSamw * FILE_READ_ATTRIBUTES and FILE_READ_EA 98*da6c28aaSamw * 99*da6c28aaSamw * GENERIC_WRITE STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA, 100*da6c28aaSamw * FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA 101*da6c28aaSamw * 102*da6c28aaSamw * GENERIC_EXECUTE STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE. 103*da6c28aaSamw */ 104*da6c28aaSamw uint32_t 105*da6c28aaSamw smb_access_generic_to_file(uint32_t desired_access) 106*da6c28aaSamw { 107*da6c28aaSamw uint32_t access = 0; 108*da6c28aaSamw 109*da6c28aaSamw if (desired_access & GENERIC_ALL) 110*da6c28aaSamw return (FILE_ALL_ACCESS & ~SYNCHRONIZE); 111*da6c28aaSamw 112*da6c28aaSamw if (desired_access & GENERIC_EXECUTE) { 113*da6c28aaSamw desired_access &= ~GENERIC_EXECUTE; 114*da6c28aaSamw access |= (STANDARD_RIGHTS_EXECUTE | 115*da6c28aaSamw SYNCHRONIZE | FILE_EXECUTE); 116*da6c28aaSamw } 117*da6c28aaSamw 118*da6c28aaSamw if (desired_access & GENERIC_WRITE) { 119*da6c28aaSamw desired_access &= ~GENERIC_WRITE; 120*da6c28aaSamw access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE); 121*da6c28aaSamw } 122*da6c28aaSamw 123*da6c28aaSamw if (desired_access & GENERIC_READ) { 124*da6c28aaSamw desired_access &= ~GENERIC_READ; 125*da6c28aaSamw access |= FILE_GENERIC_READ; 126*da6c28aaSamw } 127*da6c28aaSamw 128*da6c28aaSamw return (access | desired_access); 129*da6c28aaSamw } 130*da6c28aaSamw 131*da6c28aaSamw /* 132*da6c28aaSamw * smb_omode_to_amask 133*da6c28aaSamw * 134*da6c28aaSamw * This function converts open modes used by Open and Open AndX 135*da6c28aaSamw * commands to desired access bits used by NT Create AndX command. 136*da6c28aaSamw */ 137*da6c28aaSamw uint32_t 138*da6c28aaSamw smb_omode_to_amask(uint32_t desired_access) 139*da6c28aaSamw { 140*da6c28aaSamw switch (desired_access & SMB_DA_ACCESS_MASK) { 141*da6c28aaSamw case SMB_DA_ACCESS_READ: 142*da6c28aaSamw return (FILE_GENERIC_READ); 143*da6c28aaSamw 144*da6c28aaSamw case SMB_DA_ACCESS_WRITE: 145*da6c28aaSamw return (FILE_GENERIC_WRITE); 146*da6c28aaSamw 147*da6c28aaSamw case SMB_DA_ACCESS_READ_WRITE: 148*da6c28aaSamw return (FILE_GENERIC_READ | FILE_GENERIC_WRITE); 149*da6c28aaSamw 150*da6c28aaSamw case SMB_DA_ACCESS_EXECUTE: 151*da6c28aaSamw return (FILE_GENERIC_EXECUTE); 152*da6c28aaSamw } 153*da6c28aaSamw 154*da6c28aaSamw /* invalid open mode */ 155*da6c28aaSamw return ((uint32_t)SMB_INVALID_AMASK); 156*da6c28aaSamw } 157*da6c28aaSamw 158*da6c28aaSamw /* 159*da6c28aaSamw * smb_denymode_to_sharemode 160*da6c28aaSamw * 161*da6c28aaSamw * This function converts deny modes used by Open and Open AndX 162*da6c28aaSamw * commands to share access bits used by NT Create AndX command. 163*da6c28aaSamw */ 164*da6c28aaSamw uint32_t 165*da6c28aaSamw smb_denymode_to_sharemode(uint32_t desired_access, char *fname) 166*da6c28aaSamw { 167*da6c28aaSamw switch (desired_access & SMB_DA_SHARE_MASK) { 168*da6c28aaSamw case SMB_DA_SHARE_COMPATIBILITY: 169*da6c28aaSamw if (smb_is_executable(fname)) 170*da6c28aaSamw return (FILE_SHARE_READ | FILE_SHARE_WRITE); 171*da6c28aaSamw else { 172*da6c28aaSamw if ((desired_access & 173*da6c28aaSamw SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ) 174*da6c28aaSamw return (FILE_SHARE_READ); 175*da6c28aaSamw else 176*da6c28aaSamw return (FILE_SHARE_NONE); 177*da6c28aaSamw } 178*da6c28aaSamw 179*da6c28aaSamw case SMB_DA_SHARE_EXCLUSIVE: 180*da6c28aaSamw return (FILE_SHARE_NONE); 181*da6c28aaSamw 182*da6c28aaSamw case SMB_DA_SHARE_DENY_WRITE: 183*da6c28aaSamw return (FILE_SHARE_READ); 184*da6c28aaSamw 185*da6c28aaSamw case SMB_DA_SHARE_DENY_READ: 186*da6c28aaSamw return (FILE_SHARE_WRITE); 187*da6c28aaSamw 188*da6c28aaSamw case SMB_DA_SHARE_DENY_NONE: 189*da6c28aaSamw return (FILE_SHARE_READ | FILE_SHARE_WRITE); 190*da6c28aaSamw } 191*da6c28aaSamw 192*da6c28aaSamw /* invalid deny mode */ 193*da6c28aaSamw return ((uint32_t)SMB_INVALID_SHAREMODE); 194*da6c28aaSamw } 195*da6c28aaSamw 196*da6c28aaSamw /* 197*da6c28aaSamw * smb_ofun_to_crdisposition 198*da6c28aaSamw * 199*da6c28aaSamw * This function converts open function values used by Open and Open AndX 200*da6c28aaSamw * commands to create disposition values used by NT Create AndX command. 201*da6c28aaSamw */ 202*da6c28aaSamw uint32_t 203*da6c28aaSamw smb_ofun_to_crdisposition(uint16_t ofun) 204*da6c28aaSamw { 205*da6c28aaSamw static int ofun_cr_map[3][2] = 206*da6c28aaSamw { 207*da6c28aaSamw { -1, FILE_CREATE }, 208*da6c28aaSamw { FILE_OPEN, FILE_OPEN_IF }, 209*da6c28aaSamw { FILE_OVERWRITE, FILE_OVERWRITE_IF } 210*da6c28aaSamw }; 211*da6c28aaSamw 212*da6c28aaSamw int row = ofun & SMB_OFUN_OPEN_MASK; 213*da6c28aaSamw int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4; 214*da6c28aaSamw 215*da6c28aaSamw if (row == 3) 216*da6c28aaSamw return ((uint32_t)SMB_INVALID_CRDISPOSITION); 217*da6c28aaSamw 218*da6c28aaSamw return (ofun_cr_map[row][col]); 219*da6c28aaSamw } 220*da6c28aaSamw 221*da6c28aaSamw /* 222*da6c28aaSamw * smb_open_share_check 223*da6c28aaSamw * 224*da6c28aaSamw * check file sharing rules for current open request 225*da6c28aaSamw * against the given existing open. 226*da6c28aaSamw * 227*da6c28aaSamw * Returns NT_STATUS_SHARING_VIOLATION if there is any 228*da6c28aaSamw * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 229*da6c28aaSamw */ 230*da6c28aaSamw uint32_t 231*da6c28aaSamw smb_open_share_check(struct smb_request *sr, 232*da6c28aaSamw struct smb_node *node, 233*da6c28aaSamw struct smb_ofile *open) 234*da6c28aaSamw { 235*da6c28aaSamw uint32_t desired_access; 236*da6c28aaSamw uint32_t share_access; 237*da6c28aaSamw 238*da6c28aaSamw desired_access = sr->arg.open.desired_access; 239*da6c28aaSamw share_access = sr->arg.open.share_access; 240*da6c28aaSamw 241*da6c28aaSamw /* 242*da6c28aaSamw * As far as I can tell share modes are not relevant to 243*da6c28aaSamw * directories. The check for exclusive access (Deny RW) 244*da6c28aaSamw * remains because I don't know whether or not it was here 245*da6c28aaSamw * for a reason. 246*da6c28aaSamw */ 247*da6c28aaSamw if (node->attr.sa_vattr.va_type == VDIR) { 248*da6c28aaSamw if (DENY_RW(open->f_share_access) && 249*da6c28aaSamw (node->n_orig_uid != crgetuid(sr->user_cr))) { 250*da6c28aaSamw return (NT_STATUS_SHARING_VIOLATION); 251*da6c28aaSamw } 252*da6c28aaSamw 253*da6c28aaSamw return (NT_STATUS_SUCCESS); 254*da6c28aaSamw } 255*da6c28aaSamw 256*da6c28aaSamw /* if it's just meta data */ 257*da6c28aaSamw if ((open->f_granted_access & FILE_DATA_ALL) == 0) 258*da6c28aaSamw return (NT_STATUS_SUCCESS); 259*da6c28aaSamw 260*da6c28aaSamw /* 261*da6c28aaSamw * Check requested share access against the 262*da6c28aaSamw * open granted (desired) access 263*da6c28aaSamw */ 264*da6c28aaSamw if (DENY_DELETE(share_access) && (open->f_granted_access & DELETE)) 265*da6c28aaSamw return (NT_STATUS_SHARING_VIOLATION); 266*da6c28aaSamw 267*da6c28aaSamw if (DENY_READ(share_access) && 268*da6c28aaSamw (open->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) 269*da6c28aaSamw return (NT_STATUS_SHARING_VIOLATION); 270*da6c28aaSamw 271*da6c28aaSamw if (DENY_WRITE(share_access) && 272*da6c28aaSamw (open->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) 273*da6c28aaSamw return (NT_STATUS_SHARING_VIOLATION); 274*da6c28aaSamw 275*da6c28aaSamw /* check requested desired access against the open share access */ 276*da6c28aaSamw if (DENY_DELETE(open->f_share_access) && (desired_access & DELETE)) 277*da6c28aaSamw return (NT_STATUS_SHARING_VIOLATION); 278*da6c28aaSamw 279*da6c28aaSamw if (DENY_READ(open->f_share_access) && 280*da6c28aaSamw (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) 281*da6c28aaSamw return (NT_STATUS_SHARING_VIOLATION); 282*da6c28aaSamw 283*da6c28aaSamw if (DENY_WRITE(open->f_share_access) && 284*da6c28aaSamw (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) 285*da6c28aaSamw return (NT_STATUS_SHARING_VIOLATION); 286*da6c28aaSamw 287*da6c28aaSamw return (NT_STATUS_SUCCESS); 288*da6c28aaSamw } 289*da6c28aaSamw 290*da6c28aaSamw /* 291*da6c28aaSamw * smb_file_share_check 292*da6c28aaSamw * 293*da6c28aaSamw * check file sharing rules for current open request 294*da6c28aaSamw * against all existing opens for a file. 295*da6c28aaSamw * 296*da6c28aaSamw * Returns NT_STATUS_SHARING_VIOLATION if there is any 297*da6c28aaSamw * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 298*da6c28aaSamw */ 299*da6c28aaSamw uint32_t 300*da6c28aaSamw smb_file_share_check(struct smb_request *sr, struct smb_node *node) 301*da6c28aaSamw { 302*da6c28aaSamw struct smb_ofile *open; 303*da6c28aaSamw uint32_t status; 304*da6c28aaSamw 305*da6c28aaSamw if (node == 0 || node->n_refcnt <= 1) 306*da6c28aaSamw return (NT_STATUS_SUCCESS); 307*da6c28aaSamw 308*da6c28aaSamw /* if it's just meta data */ 309*da6c28aaSamw if ((sr->arg.open.desired_access & FILE_DATA_ALL) == 0) 310*da6c28aaSamw return (NT_STATUS_SUCCESS); 311*da6c28aaSamw 312*da6c28aaSamw smb_llist_enter(&node->n_ofile_list, RW_READER); 313*da6c28aaSamw open = smb_llist_head(&node->n_ofile_list); 314*da6c28aaSamw while (open) { 315*da6c28aaSamw status = smb_open_share_check(sr, node, open); 316*da6c28aaSamw if (status == NT_STATUS_SHARING_VIOLATION) { 317*da6c28aaSamw smb_llist_exit(&node->n_ofile_list); 318*da6c28aaSamw return (status); 319*da6c28aaSamw } 320*da6c28aaSamw open = smb_llist_next(&node->n_ofile_list, open); 321*da6c28aaSamw } 322*da6c28aaSamw smb_llist_exit(&node->n_ofile_list); 323*da6c28aaSamw 324*da6c28aaSamw return (NT_STATUS_SUCCESS); 325*da6c28aaSamw } 326*da6c28aaSamw 327*da6c28aaSamw /* 328*da6c28aaSamw * smb_amask_to_amode 329*da6c28aaSamw * Converts specific read/write access rights of access mask to access 330*da6c28aaSamw * mode flags. 331*da6c28aaSamw */ 332*da6c28aaSamw int 333*da6c28aaSamw smb_amask_to_amode(unsigned long amask) 334*da6c28aaSamw { 335*da6c28aaSamw if ((amask & FILE_READ_DATA) && 336*da6c28aaSamw (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA))) 337*da6c28aaSamw return (O_RDWR); 338*da6c28aaSamw 339*da6c28aaSamw if (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 340*da6c28aaSamw return (O_WRONLY); 341*da6c28aaSamw 342*da6c28aaSamw return (O_RDONLY); 343*da6c28aaSamw } 344*da6c28aaSamw 345*da6c28aaSamw /* 346*da6c28aaSamw * smb_open_subr 347*da6c28aaSamw * 348*da6c28aaSamw * Notes on write-through behaviour. It looks like pre-LM0.12 versions 349*da6c28aaSamw * of the protocol specify the write-through mode when a file is opened, 350*da6c28aaSamw * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose, 351*da6c28aaSamw * SmbWriteAndUnlock) don't need to contain a write-through flag. 352*da6c28aaSamw * 353*da6c28aaSamw * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate) 354*da6c28aaSamw * don't indicate which write-through mode to use. Instead the write 355*da6c28aaSamw * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call 356*da6c28aaSamw * basis. 357*da6c28aaSamw * 358*da6c28aaSamw * We don't care which open call was used to get us here, we just need 359*da6c28aaSamw * to ensure that the write-through mode flag is copied from the open 360*da6c28aaSamw * parameters to the node. We test the omode write-through flag in all 361*da6c28aaSamw * write functions. 362*da6c28aaSamw * 363*da6c28aaSamw * This function will return NT status codes but it also raises errors, 364*da6c28aaSamw * in which case it won't return to the caller. Be careful how you 365*da6c28aaSamw * handle things in here. 366*da6c28aaSamw */ 367*da6c28aaSamw uint32_t 368*da6c28aaSamw smb_open_subr(struct smb_request *sr) 369*da6c28aaSamw { 370*da6c28aaSamw int created = 0; 371*da6c28aaSamw struct smb_node *node = 0; 372*da6c28aaSamw struct smb_node *dnode = 0; 373*da6c28aaSamw struct smb_node *cur_node; 374*da6c28aaSamw struct open_param *op = &sr->arg.open; 375*da6c28aaSamw int rc; 376*da6c28aaSamw struct smb_ofile *of; 377*da6c28aaSamw smb_attr_t new_attr; 378*da6c28aaSamw int pathlen; 379*da6c28aaSamw int max_requested = 0; 380*da6c28aaSamw uint32_t max_allowed; 381*da6c28aaSamw unsigned int granted_oplock; 382*da6c28aaSamw uint32_t status = NT_STATUS_SUCCESS; 383*da6c28aaSamw int is_dir; 384*da6c28aaSamw smb_error_t err; 385*da6c28aaSamw int is_stream; 386*da6c28aaSamw int lookup_flags = SMB_FOLLOW_LINKS; 387*da6c28aaSamw uint32_t daccess; 388*da6c28aaSamw 389*da6c28aaSamw is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0; 390*da6c28aaSamw 391*da6c28aaSamw if (is_dir) { 392*da6c28aaSamw /* 393*da6c28aaSamw * The file being created or opened is a directory file. 394*da6c28aaSamw * With this flag, the Disposition parameter must be set to 395*da6c28aaSamw * one of FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF 396*da6c28aaSamw */ 397*da6c28aaSamw if ((op->create_disposition != FILE_CREATE) && 398*da6c28aaSamw (op->create_disposition != FILE_OPEN_IF) && 399*da6c28aaSamw (op->create_disposition != FILE_OPEN)) { 400*da6c28aaSamw smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER, 401*da6c28aaSamw ERRDOS, ERROR_INVALID_ACCESS); 402*da6c28aaSamw /* invalid open mode */ 403*da6c28aaSamw /* NOTREACHED */ 404*da6c28aaSamw } 405*da6c28aaSamw } 406*da6c28aaSamw 407*da6c28aaSamw if (op->desired_access & MAXIMUM_ALLOWED) { 408*da6c28aaSamw max_requested = 1; 409*da6c28aaSamw op->desired_access &= ~MAXIMUM_ALLOWED; 410*da6c28aaSamw } 411*da6c28aaSamw op->desired_access = smb_access_generic_to_file(op->desired_access); 412*da6c28aaSamw 413*da6c28aaSamw if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) { 414*da6c28aaSamw 415*da6c28aaSamw ASSERT(sr->uid_user); 416*da6c28aaSamw cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain, 417*da6c28aaSamw sr->uid_user->u_name, 418*da6c28aaSamw xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES)); 419*da6c28aaSamw 420*da6c28aaSamw smbsr_raise_cifs_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES, 421*da6c28aaSamw ERRDOS, ERROR_TOO_MANY_OPEN_FILES); 422*da6c28aaSamw /* NOTREACHED */ 423*da6c28aaSamw } 424*da6c28aaSamw 425*da6c28aaSamw /* This must be NULL at this point */ 426*da6c28aaSamw sr->fid_ofile = NULL; 427*da6c28aaSamw 428*da6c28aaSamw op->devstate = 0; 429*da6c28aaSamw 430*da6c28aaSamw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 431*da6c28aaSamw case STYPE_DISKTREE: 432*da6c28aaSamw break; 433*da6c28aaSamw 434*da6c28aaSamw case STYPE_IPC: 435*da6c28aaSamw /* 436*da6c28aaSamw * No further processing for IPC, we need to either 437*da6c28aaSamw * raise an exception or return success here. 438*da6c28aaSamw */ 439*da6c28aaSamw if ((rc = smb_rpc_open(sr)) != 0) { 440*da6c28aaSamw smbsr_raise_nt_error(sr, rc); 441*da6c28aaSamw /* NOTREACHED */ 442*da6c28aaSamw } else { 443*da6c28aaSamw return (NT_STATUS_SUCCESS); 444*da6c28aaSamw } 445*da6c28aaSamw break; 446*da6c28aaSamw 447*da6c28aaSamw default: 448*da6c28aaSamw smbsr_raise_error(sr, ERRSRV, ERRinvdevice); 449*da6c28aaSamw /* NOTREACHED */ 450*da6c28aaSamw break; 451*da6c28aaSamw } 452*da6c28aaSamw 453*da6c28aaSamw if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) { 454*da6c28aaSamw smbsr_raise_error(sr, ERRSRV, ERRfilespecs); 455*da6c28aaSamw /* NOTREACHED */ 456*da6c28aaSamw } 457*da6c28aaSamw 458*da6c28aaSamw /* 459*da6c28aaSamw * Some clients pass null file names; NT interprets this as "\". 460*da6c28aaSamw */ 461*da6c28aaSamw if (pathlen == 0) { 462*da6c28aaSamw op->fqi.path = "\\"; 463*da6c28aaSamw pathlen = 1; 464*da6c28aaSamw } 465*da6c28aaSamw 466*da6c28aaSamw op->fqi.srch_attr = op->fqi.srch_attr; 467*da6c28aaSamw 468*da6c28aaSamw if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) { 469*da6c28aaSamw smbsr_raise_cifs_error(sr, status, ERRDOS, ERROR_INVALID_NAME); 470*da6c28aaSamw /* NOTREACHED */ 471*da6c28aaSamw } 472*da6c28aaSamw 473*da6c28aaSamw cur_node = op->fqi.dir_snode ? 474*da6c28aaSamw op->fqi.dir_snode : sr->tid_tree->t_snode; 475*da6c28aaSamw 476*da6c28aaSamw if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path, 477*da6c28aaSamw sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode, 478*da6c28aaSamw op->fqi.last_comp)) { 479*da6c28aaSamw smbsr_raise_errno(sr, rc); 480*da6c28aaSamw /* NOTREACHED */ 481*da6c28aaSamw } 482*da6c28aaSamw 483*da6c28aaSamw /* 484*da6c28aaSamw * If the access mask has only DELETE set (ignore 485*da6c28aaSamw * FILE_READ_ATTRIBUTES), then assume that this 486*da6c28aaSamw * is a request to delete the link (if a link) 487*da6c28aaSamw * and do not follow links. Otherwise, follow 488*da6c28aaSamw * the link to the target. 489*da6c28aaSamw */ 490*da6c28aaSamw 491*da6c28aaSamw daccess = op->desired_access & ~FILE_READ_ATTRIBUTES; 492*da6c28aaSamw 493*da6c28aaSamw if (daccess == DELETE) 494*da6c28aaSamw lookup_flags &= ~SMB_FOLLOW_LINKS; 495*da6c28aaSamw 496*da6c28aaSamw rc = smb_fsop_lookup_name(sr, kcred, lookup_flags, 497*da6c28aaSamw sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp, 498*da6c28aaSamw &op->fqi.last_snode, &op->fqi.last_attr); 499*da6c28aaSamw 500*da6c28aaSamw if (rc == 0) { 501*da6c28aaSamw op->fqi.last_comp_was_found = 1; 502*da6c28aaSamw (void) strcpy(op->fqi.last_comp_od, 503*da6c28aaSamw op->fqi.last_snode->od_name); 504*da6c28aaSamw } else if (rc == ENOENT) { 505*da6c28aaSamw op->fqi.last_comp_was_found = 0; 506*da6c28aaSamw op->fqi.last_snode = NULL; 507*da6c28aaSamw rc = 0; 508*da6c28aaSamw } else { 509*da6c28aaSamw smb_node_release(op->fqi.dir_snode); 510*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 511*da6c28aaSamw smbsr_raise_errno(sr, rc); 512*da6c28aaSamw /* NOTREACHED */ 513*da6c28aaSamw } 514*da6c28aaSamw 515*da6c28aaSamw if (op->fqi.last_comp_was_found) { 516*da6c28aaSamw node = op->fqi.last_snode; 517*da6c28aaSamw dnode = op->fqi.dir_snode; 518*da6c28aaSamw 519*da6c28aaSamw /* 520*da6c28aaSamw * Reject this request if the target is a directory 521*da6c28aaSamw * and the client has specified that it must not be 522*da6c28aaSamw * a directory (required by Lotus Notes). 523*da6c28aaSamw */ 524*da6c28aaSamw if ((op->create_options & FILE_NON_DIRECTORY_FILE) && 525*da6c28aaSamw (op->fqi.last_attr.sa_vattr.va_type == VDIR)) { 526*da6c28aaSamw smb_node_release(node); 527*da6c28aaSamw smb_node_release(dnode); 528*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 529*da6c28aaSamw smbsr_raise_cifs_error(sr, 530*da6c28aaSamw NT_STATUS_FILE_IS_A_DIRECTORY, 531*da6c28aaSamw ERRDOS, ERROR_ACCESS_DENIED); 532*da6c28aaSamw /* NOTREACHED */ 533*da6c28aaSamw } 534*da6c28aaSamw 535*da6c28aaSamw if (op->fqi.last_attr.sa_vattr.va_type == VDIR) { 536*da6c28aaSamw if ((sr->smb_com == SMB_COM_OPEN_ANDX) || 537*da6c28aaSamw (sr->smb_com == SMB_COM_OPEN)) { 538*da6c28aaSamw /* 539*da6c28aaSamw * Directories cannot be opened 540*da6c28aaSamw * with the above commands 541*da6c28aaSamw */ 542*da6c28aaSamw smb_node_release(node); 543*da6c28aaSamw smb_node_release(dnode); 544*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 545*da6c28aaSamw smbsr_raise_cifs_error(sr, 546*da6c28aaSamw NT_STATUS_FILE_IS_A_DIRECTORY, 547*da6c28aaSamw ERRDOS, ERROR_ACCESS_DENIED); 548*da6c28aaSamw /* NOTREACHED */ 549*da6c28aaSamw } 550*da6c28aaSamw } else if (op->my_flags & MYF_MUST_BE_DIRECTORY) { 551*da6c28aaSamw smb_node_release(node); 552*da6c28aaSamw smb_node_release(dnode); 553*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 554*da6c28aaSamw smbsr_raise_cifs_error(sr, NT_STATUS_NOT_A_DIRECTORY, 555*da6c28aaSamw ERRDOS, ERROR_DIRECTORY); 556*da6c28aaSamw /* NOTREACHED */ 557*da6c28aaSamw } 558*da6c28aaSamw 559*da6c28aaSamw /* 560*da6c28aaSamw * No more open should be accepted when "Delete on close" 561*da6c28aaSamw * flag is set. 562*da6c28aaSamw */ 563*da6c28aaSamw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 564*da6c28aaSamw smb_node_release(node); 565*da6c28aaSamw smb_node_release(dnode); 566*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 567*da6c28aaSamw smbsr_raise_cifs_error(sr, NT_STATUS_DELETE_PENDING, 568*da6c28aaSamw ERRDOS, ERROR_ACCESS_DENIED); 569*da6c28aaSamw /* NOTREACHED */ 570*da6c28aaSamw } 571*da6c28aaSamw 572*da6c28aaSamw /* 573*da6c28aaSamw * Specified file already exists so the operation should fail. 574*da6c28aaSamw */ 575*da6c28aaSamw if (op->create_disposition == FILE_CREATE) { 576*da6c28aaSamw smb_node_release(node); 577*da6c28aaSamw smb_node_release(dnode); 578*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 579*da6c28aaSamw smbsr_raise_cifs_error(sr, 580*da6c28aaSamw NT_STATUS_OBJECT_NAME_COLLISION, ERRDOS, 581*da6c28aaSamw ERROR_ALREADY_EXISTS); 582*da6c28aaSamw /* NOTREACHED */ 583*da6c28aaSamw } 584*da6c28aaSamw 585*da6c28aaSamw /* 586*da6c28aaSamw * Windows seems to check read-only access before file 587*da6c28aaSamw * sharing check. 588*da6c28aaSamw */ 589*da6c28aaSamw if (NODE_IS_READONLY(node)) { 590*da6c28aaSamw /* Files data only */ 591*da6c28aaSamw if (node->attr.sa_vattr.va_type != VDIR) { 592*da6c28aaSamw if (op->desired_access & (FILE_WRITE_DATA | 593*da6c28aaSamw FILE_APPEND_DATA)) { 594*da6c28aaSamw smb_node_release(node); 595*da6c28aaSamw smb_node_release(dnode); 596*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 597*da6c28aaSamw smbsr_raise_error(sr, ERRDOS, 598*da6c28aaSamw ERRnoaccess); 599*da6c28aaSamw /* NOTREACHED */ 600*da6c28aaSamw } 601*da6c28aaSamw } 602*da6c28aaSamw } 603*da6c28aaSamw 604*da6c28aaSamw status = smb_file_share_check(sr, node); 605*da6c28aaSamw if (status == NT_STATUS_SHARING_VIOLATION) { 606*da6c28aaSamw smb_node_release(node); 607*da6c28aaSamw smb_node_release(dnode); 608*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 609*da6c28aaSamw return (status); 610*da6c28aaSamw } 611*da6c28aaSamw 612*da6c28aaSamw status = smb_fsop_access(sr, sr->user_cr, node, 613*da6c28aaSamw op->desired_access); 614*da6c28aaSamw 615*da6c28aaSamw if (status != NT_STATUS_SUCCESS) { 616*da6c28aaSamw smb_node_release(node); 617*da6c28aaSamw smb_node_release(dnode); 618*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 619*da6c28aaSamw if (status == NT_STATUS_PRIVILEGE_NOT_HELD) { 620*da6c28aaSamw smbsr_raise_cifs_error(sr, 621*da6c28aaSamw status, 622*da6c28aaSamw ERRDOS, 623*da6c28aaSamw ERROR_PRIVILEGE_NOT_HELD); 624*da6c28aaSamw } else { 625*da6c28aaSamw smbsr_raise_cifs_error(sr, 626*da6c28aaSamw NT_STATUS_ACCESS_DENIED, 627*da6c28aaSamw ERRDOS, 628*da6c28aaSamw ERROR_ACCESS_DENIED); 629*da6c28aaSamw } 630*da6c28aaSamw } 631*da6c28aaSamw 632*da6c28aaSamw /* 633*da6c28aaSamw * Break the oplock before share checks. If another client 634*da6c28aaSamw * has the file open, this will force a flush or close, 635*da6c28aaSamw * which may affect the outcome of any share checking. 636*da6c28aaSamw */ 637*da6c28aaSamw if (OPLOCKS_IN_FORCE(node)) { 638*da6c28aaSamw status = smb_break_oplock(sr, node); 639*da6c28aaSamw 640*da6c28aaSamw if (status != NT_STATUS_SUCCESS) { 641*da6c28aaSamw smb_node_release(node); 642*da6c28aaSamw smb_node_release(dnode); 643*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 644*da6c28aaSamw smbsr_raise_cifs_error(sr, status, 645*da6c28aaSamw ERRDOS, ERROR_VC_DISCONNECTED); 646*da6c28aaSamw /* NOTREACHED */ 647*da6c28aaSamw } 648*da6c28aaSamw } 649*da6c28aaSamw 650*da6c28aaSamw switch (op->create_disposition) { 651*da6c28aaSamw case FILE_SUPERSEDE: 652*da6c28aaSamw case FILE_OVERWRITE_IF: 653*da6c28aaSamw case FILE_OVERWRITE: 654*da6c28aaSamw if (node->attr.sa_vattr.va_type == VDIR) { 655*da6c28aaSamw smb_node_release(node); 656*da6c28aaSamw smb_node_release(dnode); 657*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 658*da6c28aaSamw smbsr_raise_cifs_error(sr, 659*da6c28aaSamw NT_STATUS_ACCESS_DENIED, ERRDOS, 660*da6c28aaSamw ERROR_ACCESS_DENIED); 661*da6c28aaSamw /* NOTREACHED */ 662*da6c28aaSamw } 663*da6c28aaSamw 664*da6c28aaSamw if (node->attr.sa_vattr.va_size != op->dsize) { 665*da6c28aaSamw node->flags &= ~NODE_FLAGS_SET_SIZE; 666*da6c28aaSamw new_attr.sa_vattr.va_size = op->dsize; 667*da6c28aaSamw new_attr.sa_mask = SMB_AT_SIZE; 668*da6c28aaSamw if ((rc = smb_fsop_setattr(sr, sr->user_cr, 669*da6c28aaSamw (&op->fqi)->last_snode, &new_attr, 670*da6c28aaSamw &op->fqi.last_attr)) != 0) { 671*da6c28aaSamw smb_node_release(node); 672*da6c28aaSamw smb_node_release(dnode); 673*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 674*da6c28aaSamw smbsr_raise_errno(sr, rc); 675*da6c28aaSamw /* NOTREACHED */ 676*da6c28aaSamw } 677*da6c28aaSamw 678*da6c28aaSamw } 679*da6c28aaSamw 680*da6c28aaSamw /* 681*da6c28aaSamw * If file is being replaced, 682*da6c28aaSamw * we should remove existing streams 683*da6c28aaSamw */ 684*da6c28aaSamw if (SMB_IS_STREAM(node) == 0) 685*da6c28aaSamw (void) smb_fsop_remove_streams(sr, sr->user_cr, 686*da6c28aaSamw node); 687*da6c28aaSamw 688*da6c28aaSamw op->action_taken = SMB_OACT_TRUNCATED; 689*da6c28aaSamw break; 690*da6c28aaSamw 691*da6c28aaSamw default: 692*da6c28aaSamw /* 693*da6c28aaSamw * FILE_OPEN or FILE_OPEN_IF. 694*da6c28aaSamw */ 695*da6c28aaSamw op->action_taken = SMB_OACT_OPENED; 696*da6c28aaSamw break; 697*da6c28aaSamw } 698*da6c28aaSamw } else { 699*da6c28aaSamw 700*da6c28aaSamw /* Last component was not found. */ 701*da6c28aaSamw dnode = op->fqi.dir_snode; 702*da6c28aaSamw 703*da6c28aaSamw if ((op->create_disposition == FILE_OPEN) || 704*da6c28aaSamw (op->create_disposition == FILE_OVERWRITE)) { 705*da6c28aaSamw smb_node_release(dnode); 706*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 707*da6c28aaSamw 708*da6c28aaSamw is_stream = smb_stream_parse_name(op->fqi.path, 709*da6c28aaSamw NULL, NULL); 710*da6c28aaSamw /* 711*da6c28aaSamw * The requested file not found so the operation should 712*da6c28aaSamw * fail with these two dispositions 713*da6c28aaSamw */ 714*da6c28aaSamw if (is_stream) 715*da6c28aaSamw smbsr_raise_cifs_error(sr, 716*da6c28aaSamw NT_STATUS_OBJECT_NAME_NOT_FOUND, 717*da6c28aaSamw ERRDOS, ERROR_FILE_NOT_FOUND); 718*da6c28aaSamw else 719*da6c28aaSamw smbsr_raise_error(sr, ERRDOS, ERRbadfile); 720*da6c28aaSamw /* NOTREACHED */ 721*da6c28aaSamw } 722*da6c28aaSamw 723*da6c28aaSamw /* 724*da6c28aaSamw * lock the parent dir node in case another create 725*da6c28aaSamw * request to the same parent directory comes in. 726*da6c28aaSamw */ 727*da6c28aaSamw smb_rwx_rwenter(&dnode->n_lock, RW_WRITER); 728*da6c28aaSamw 729*da6c28aaSamw bzero(&new_attr, sizeof (new_attr)); 730*da6c28aaSamw if (is_dir == 0) { 731*da6c28aaSamw new_attr.sa_vattr.va_type = VREG; 732*da6c28aaSamw new_attr.sa_vattr.va_mode = 0666; 733*da6c28aaSamw new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE; 734*da6c28aaSamw rc = smb_fsop_create(sr, sr->user_cr, dnode, 735*da6c28aaSamw op->fqi.last_comp, &new_attr, 736*da6c28aaSamw &op->fqi.last_snode, &op->fqi.last_attr); 737*da6c28aaSamw if (rc != 0) { 738*da6c28aaSamw smb_rwx_rwexit(&dnode->n_lock); 739*da6c28aaSamw smb_node_release(dnode); 740*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 741*da6c28aaSamw smbsr_raise_errno(sr, rc); 742*da6c28aaSamw /* NOTREACHED */ 743*da6c28aaSamw } 744*da6c28aaSamw 745*da6c28aaSamw if (op->dsize) { 746*da6c28aaSamw new_attr.sa_vattr.va_size = op->dsize; 747*da6c28aaSamw new_attr.sa_mask = SMB_AT_SIZE; 748*da6c28aaSamw rc = smb_fsop_setattr(sr, sr->user_cr, 749*da6c28aaSamw op->fqi.last_snode, &new_attr, 750*da6c28aaSamw &op->fqi.last_attr); 751*da6c28aaSamw if (rc != 0) { 752*da6c28aaSamw smb_node_release(op->fqi.last_snode); 753*da6c28aaSamw (void) smb_fsop_remove(sr, sr->user_cr, 754*da6c28aaSamw dnode, op->fqi.last_comp, 0); 755*da6c28aaSamw smb_rwx_rwexit(&dnode->n_lock); 756*da6c28aaSamw smb_node_release(dnode); 757*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 758*da6c28aaSamw smbsr_raise_errno(sr, rc); 759*da6c28aaSamw /* NOTREACHED */ 760*da6c28aaSamw } 761*da6c28aaSamw } 762*da6c28aaSamw 763*da6c28aaSamw } else { 764*da6c28aaSamw op->dattr |= SMB_FA_DIRECTORY; 765*da6c28aaSamw new_attr.sa_vattr.va_type = VDIR; 766*da6c28aaSamw new_attr.sa_vattr.va_mode = 0777; 767*da6c28aaSamw new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE; 768*da6c28aaSamw rc = smb_fsop_mkdir(sr, sr->user_cr, dnode, 769*da6c28aaSamw op->fqi.last_comp, &new_attr, 770*da6c28aaSamw &op->fqi.last_snode, &op->fqi.last_attr); 771*da6c28aaSamw if (rc != 0) { 772*da6c28aaSamw smb_rwx_rwexit(&dnode->n_lock); 773*da6c28aaSamw smb_node_release(dnode); 774*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 775*da6c28aaSamw smbsr_raise_errno(sr, rc); 776*da6c28aaSamw /* NOTREACHED */ 777*da6c28aaSamw } 778*da6c28aaSamw } 779*da6c28aaSamw 780*da6c28aaSamw created = 1; 781*da6c28aaSamw op->action_taken = SMB_OACT_CREATED; 782*da6c28aaSamw } 783*da6c28aaSamw 784*da6c28aaSamw if (node == 0) { 785*da6c28aaSamw node = op->fqi.last_snode; 786*da6c28aaSamw } 787*da6c28aaSamw 788*da6c28aaSamw if ((op->fqi.last_attr.sa_vattr.va_type != VREG) && 789*da6c28aaSamw (op->fqi.last_attr.sa_vattr.va_type != VDIR) && 790*da6c28aaSamw (op->fqi.last_attr.sa_vattr.va_type != VLNK)) { 791*da6c28aaSamw /* not allowed to do this */ 792*da6c28aaSamw SMB_DEL_NEWOBJ(op->fqi); 793*da6c28aaSamw smb_node_release(node); 794*da6c28aaSamw if (created) 795*da6c28aaSamw smb_rwx_rwexit(&dnode->n_lock); 796*da6c28aaSamw smb_node_release(dnode); 797*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 798*da6c28aaSamw smbsr_raise_error(sr, ERRDOS, ERRnoaccess); 799*da6c28aaSamw /* NOTREACHED */ 800*da6c28aaSamw } 801*da6c28aaSamw 802*da6c28aaSamw if (max_requested) { 803*da6c28aaSamw smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed); 804*da6c28aaSamw op->desired_access |= max_allowed; 805*da6c28aaSamw } 806*da6c28aaSamw 807*da6c28aaSamw /* 808*da6c28aaSamw * smb_ofile_open() will copy node to of->node. Hence 809*da6c28aaSamw * the hold on node (i.e. op->fqi.last_snode) will be "transferred" 810*da6c28aaSamw * to the "of" structure. 811*da6c28aaSamw */ 812*da6c28aaSamw 813*da6c28aaSamw of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op->desired_access, 814*da6c28aaSamw op->create_options, op->share_access, SMB_FTYPE_DISK, NULL, 0, 815*da6c28aaSamw &err); 816*da6c28aaSamw 817*da6c28aaSamw if (of == NULL) { 818*da6c28aaSamw SMB_DEL_NEWOBJ(op->fqi); 819*da6c28aaSamw smb_node_release(node); 820*da6c28aaSamw if (created) 821*da6c28aaSamw smb_rwx_rwexit(&dnode->n_lock); 822*da6c28aaSamw smb_node_release(dnode); 823*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 824*da6c28aaSamw smbsr_raise_cifs_error(sr, err.status, err.errcls, err.errcode); 825*da6c28aaSamw /* NOTREACHED */ 826*da6c28aaSamw } 827*da6c28aaSamw 828*da6c28aaSamw /* 829*da6c28aaSamw * Propagate the write-through mode from the open params 830*da6c28aaSamw * to the node: see the notes in the function header. 831*da6c28aaSamw * 832*da6c28aaSamw * IR #102318 Mirroring may force synchronous 833*da6c28aaSamw * writes regardless of what we specify here. 834*da6c28aaSamw */ 835*da6c28aaSamw if (smb_stable_mode || (op->create_options & FILE_WRITE_THROUGH)) 836*da6c28aaSamw node->flags |= NODE_FLAGS_WRITE_THROUGH; 837*da6c28aaSamw 838*da6c28aaSamw op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid; 839*da6c28aaSamw 840*da6c28aaSamw if (op->fqi.last_attr.sa_vattr.va_type == VDIR) { 841*da6c28aaSamw /* We don't oplock directories */ 842*da6c28aaSamw op->my_flags &= ~MYF_OPLOCK_MASK; 843*da6c28aaSamw op->dsize = 0; 844*da6c28aaSamw } else { 845*da6c28aaSamw status = smb_acquire_oplock(sr, of, op->my_flags, 846*da6c28aaSamw &granted_oplock); 847*da6c28aaSamw op->my_flags &= ~MYF_OPLOCK_MASK; 848*da6c28aaSamw 849*da6c28aaSamw if (status != NT_STATUS_SUCCESS) { 850*da6c28aaSamw (void) smb_ofile_close(of, 0); 851*da6c28aaSamw smb_ofile_release(of); 852*da6c28aaSamw if (created) 853*da6c28aaSamw smb_rwx_rwexit(&dnode->n_lock); 854*da6c28aaSamw smb_node_release(dnode); 855*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 856*da6c28aaSamw 857*da6c28aaSamw smbsr_raise_cifs_error(sr, status, 858*da6c28aaSamw ERRDOS, ERROR_SHARING_VIOLATION); 859*da6c28aaSamw /* NOTREACHED */ 860*da6c28aaSamw } 861*da6c28aaSamw 862*da6c28aaSamw op->my_flags |= granted_oplock; 863*da6c28aaSamw op->dsize = op->fqi.last_attr.sa_vattr.va_size; 864*da6c28aaSamw } 865*da6c28aaSamw 866*da6c28aaSamw if (created) { 867*da6c28aaSamw node->flags |= NODE_FLAGS_CREATED; 868*da6c28aaSamw /* 869*da6c28aaSamw * Clients may set the DOS readonly bit on create but they 870*da6c28aaSamw * expect subsequent write operations on the open fid to 871*da6c28aaSamw * succeed. Thus the DOS readonly bit is not set until the 872*da6c28aaSamw * file is closed. The NODE_CREATED_READONLY flag will 873*da6c28aaSamw * inhibit other attempts to open the file with write access 874*da6c28aaSamw * and act as the indicator to set the DOS readonly bit on 875*da6c28aaSamw * close. 876*da6c28aaSamw */ 877*da6c28aaSamw if (op->dattr & SMB_FA_READONLY) { 878*da6c28aaSamw node->flags |= NODE_CREATED_READONLY; 879*da6c28aaSamw op->dattr &= ~SMB_FA_READONLY; 880*da6c28aaSamw } 881*da6c28aaSamw smb_node_set_dosattr(node, op->dattr | SMB_FA_ARCHIVE); 882*da6c28aaSamw if (op->utime.tv_sec == 0 || op->utime.tv_sec == 0xffffffff) 883*da6c28aaSamw (void) microtime(&op->utime); 884*da6c28aaSamw smb_node_set_time(node, NULL, &op->utime, 0, 0, SMB_AT_MTIME); 885*da6c28aaSamw (void) smb_sync_fsattr(sr, sr->user_cr, node); 886*da6c28aaSamw } else { 887*da6c28aaSamw /* 888*da6c28aaSamw * If we reach here, it means that file already exists 889*da6c28aaSamw * and if create disposition is one of: FILE_SUPERSEDE, 890*da6c28aaSamw * FILE_OVERWRITE_IF, or FILE_OVERWRITE it 891*da6c28aaSamw * means that client wants to overwrite (or truncate) 892*da6c28aaSamw * the existing file. So we should overwrite the dos 893*da6c28aaSamw * attributes of destination file with the dos attributes 894*da6c28aaSamw * of source file. 895*da6c28aaSamw */ 896*da6c28aaSamw 897*da6c28aaSamw switch (op->create_disposition) { 898*da6c28aaSamw case FILE_SUPERSEDE: 899*da6c28aaSamw case FILE_OVERWRITE_IF: 900*da6c28aaSamw case FILE_OVERWRITE: 901*da6c28aaSamw smb_node_set_dosattr(node, 902*da6c28aaSamw op->dattr | SMB_FA_ARCHIVE); 903*da6c28aaSamw (void) smb_sync_fsattr(sr, sr->user_cr, node); 904*da6c28aaSamw } 905*da6c28aaSamw op->utime = *smb_node_get_crtime(node); 906*da6c28aaSamw op->dattr = smb_node_get_dosattr(node); 907*da6c28aaSamw } 908*da6c28aaSamw 909*da6c28aaSamw /* 910*da6c28aaSamw * Set up the file type in open_param for the response 911*da6c28aaSamw */ 912*da6c28aaSamw op->ftype = SMB_FTYPE_DISK; 913*da6c28aaSamw sr->smb_fid = of->f_fid; 914*da6c28aaSamw sr->fid_ofile = of; 915*da6c28aaSamw 916*da6c28aaSamw if (created) { 917*da6c28aaSamw smb_rwx_rwexit(&dnode->n_lock); 918*da6c28aaSamw } 919*da6c28aaSamw smb_node_release(dnode); 920*da6c28aaSamw SMB_NULL_FQI_NODES(op->fqi); 921*da6c28aaSamw 922*da6c28aaSamw return (NT_STATUS_SUCCESS); 923*da6c28aaSamw } 924*da6c28aaSamw 925*da6c28aaSamw /* 926*da6c28aaSamw * smb_validate_object_name 927*da6c28aaSamw * 928*da6c28aaSamw * Very basic file name validation. Directory validation is handed off 929*da6c28aaSamw * to smb_validate_dirname. For filenames, we check for names of the 930*da6c28aaSamw * form "AAAn:". Names that contain three characters, a single digit 931*da6c28aaSamw * and a colon (:) are reserved as DOS device names, i.e. "COM1:". 932*da6c28aaSamw * 933*da6c28aaSamw * Returns NT status codes. 934*da6c28aaSamw */ 935*da6c28aaSamw uint32_t 936*da6c28aaSamw smb_validate_object_name(char *path, unsigned int ftype) 937*da6c28aaSamw { 938*da6c28aaSamw char *filename; 939*da6c28aaSamw 940*da6c28aaSamw if (path == 0) 941*da6c28aaSamw return (0); 942*da6c28aaSamw 943*da6c28aaSamw if (ftype) 944*da6c28aaSamw return (smb_validate_dirname(path)); 945*da6c28aaSamw 946*da6c28aaSamw /* 947*da6c28aaSamw * Basename with backslashes. 948*da6c28aaSamw */ 949*da6c28aaSamw if ((filename = strrchr(path, '\\')) != 0) 950*da6c28aaSamw ++filename; 951*da6c28aaSamw else 952*da6c28aaSamw filename = path; 953*da6c28aaSamw 954*da6c28aaSamw if (strlen(filename) == 5 && 955*da6c28aaSamw mts_isdigit(filename[3]) && 956*da6c28aaSamw filename[4] == ':') { 957*da6c28aaSamw return (NT_STATUS_OBJECT_NAME_INVALID); 958*da6c28aaSamw } 959*da6c28aaSamw 960*da6c28aaSamw return (0); 961*da6c28aaSamw } 962*da6c28aaSamw 963*da6c28aaSamw /* 964*da6c28aaSamw * smb_preset_delete_on_close 965*da6c28aaSamw * 966*da6c28aaSamw * Set the DeleteOnClose flag on the smb file. When the file is closed, 967*da6c28aaSamw * the flag will be transferred to the smb node, which will commit the 968*da6c28aaSamw * delete operation and inhibit subsequent open requests. 969*da6c28aaSamw * 970*da6c28aaSamw * When DeleteOnClose is set on an smb_node, the common open code will 971*da6c28aaSamw * reject subsequent open requests for the file. Observation of Windows 972*da6c28aaSamw * 2000 indicates that subsequent opens should be allowed (assuming 973*da6c28aaSamw * there would be no sharing violation) until the file is closed using 974*da6c28aaSamw * the fid on which the DeleteOnClose was requested. 975*da6c28aaSamw */ 976*da6c28aaSamw void 977*da6c28aaSamw smb_preset_delete_on_close(smb_ofile_t *file) 978*da6c28aaSamw { 979*da6c28aaSamw mutex_enter(&file->f_mutex); 980*da6c28aaSamw file->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE; 981*da6c28aaSamw mutex_exit(&file->f_mutex); 982*da6c28aaSamw } 983