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 /* 29 * This command is used to create or open a file or directory, when EAs 30 * or an SD must be applied to the file. The functionality is similar 31 * to SmbNtCreateAndx with the option to supply extended attributes or 32 * a security descriptor. 33 * 34 * Note: we don't decode the extended attributes because we don't 35 * support them at this time. 36 */ 37 38 #include <smbsrv/smb_incl.h> 39 #include <smbsrv/smb_fsops.h> 40 #include <smbsrv/smb_vops.h> 41 42 /* 43 * smb_nt_transact_create 44 * 45 * This command is used to create or open a file or directory, when EAs 46 * or an SD must be applied to the file. The request parameter block 47 * encoding, data block encoding and output parameter block encoding are 48 * described in CIFS section 4.2.2. 49 * 50 * The format of the command is SmbNtTransact but it is basically the same 51 * as SmbNtCreateAndx with the option to supply extended attributes or a 52 * security descriptor. For information not defined in CIFS section 4.2.2 53 * see section 4.2.1 (NT_CREATE_ANDX). 54 */ 55 int 56 smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa) 57 { 58 struct open_param *op = &sr->arg.open; 59 uint8_t OplockLevel; 60 uint8_t DirFlag; 61 uint8_t SecurityFlags; 62 uint32_t ExtFileAttributes; 63 uint32_t sd_len; 64 uint32_t EaLength; 65 uint32_t Flags; 66 uint32_t ImpersonationLevel; 67 uint32_t RootDirFid; 68 uint32_t NameLength; 69 smb_attr_t new_attr; 70 smb_node_t *node; 71 DWORD status; 72 int rc; 73 74 rc = smb_decode_mbc(&xa->req_param_mb, "%lllqllllllllb", 75 sr, 76 &Flags, 77 &RootDirFid, 78 &op->desired_access, 79 &op->dsize, 80 &ExtFileAttributes, 81 &op->share_access, 82 &op->create_disposition, 83 &op->create_options, 84 &sd_len, 85 &EaLength, 86 &NameLength, 87 &ImpersonationLevel, 88 &SecurityFlags); 89 90 if (rc != 0) { 91 smbsr_decode_error(sr); 92 /* NOTREACHED */ 93 } 94 95 /* 96 * If name length is zero, interpret as "\". 97 */ 98 if (NameLength == 0) { 99 op->fqi.path = "\\"; 100 } else { 101 rc = smb_decode_mbc(&xa->req_param_mb, "%#u", 102 sr, NameLength, &op->fqi.path); 103 if (rc != 0) { 104 smbsr_decode_error(sr); 105 /* NOTREACHED */ 106 } 107 } 108 109 if ((op->create_options & FILE_DELETE_ON_CLOSE) && 110 !(op->desired_access & DELETE)) { 111 smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER); 112 /* NOTREACHED */ 113 } 114 115 if (sd_len >= sizeof (smb_sdbuf_t)) { 116 /* ignore security setting for files on Unix volumes */ 117 op->sd_buf = kmem_alloc(sd_len, KM_SLEEP); 118 119 if ((smb_decode_mbc(&xa->req_data_mb, "#c", sd_len, 120 (char *)op->sd_buf)) != 0) { 121 kmem_free(op->sd_buf, sd_len); 122 smbsr_raise_nt_error(sr, NT_STATUS_BUFFER_TOO_SMALL); 123 /* NOTREACHED */ 124 } 125 } else { 126 op->sd_buf = 0; 127 } 128 129 op->fqi.srch_attr = 0; 130 op->omode = 0; 131 132 op->utime.tv_sec = op->utime.tv_nsec = 0; 133 op->my_flags = 0; 134 135 op->dattr = ExtFileAttributes; 136 137 if (Flags) { 138 if (Flags & NT_CREATE_FLAG_REQUEST_OPLOCK) { 139 if (Flags & NT_CREATE_FLAG_REQUEST_OPBATCH) { 140 op->my_flags = MYF_BATCH_OPLOCK; 141 } else { 142 op->my_flags = MYF_EXCLUSIVE_OPLOCK; 143 } 144 } 145 if (Flags & NT_CREATE_FLAG_OPEN_TARGET_DIR) 146 op->my_flags |= MYF_MUST_BE_DIRECTORY; 147 } 148 149 if (ExtFileAttributes & FILE_FLAG_WRITE_THROUGH) 150 op->create_options |= FILE_WRITE_THROUGH; 151 152 if (ExtFileAttributes & FILE_FLAG_DELETE_ON_CLOSE) 153 op->create_options |= FILE_DELETE_ON_CLOSE; 154 155 if (RootDirFid == 0) { 156 op->fqi.dir_snode = sr->tid_tree->t_snode; 157 } else { 158 sr->smb_fid = (ushort_t)RootDirFid; 159 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, 160 sr->smb_fid); 161 /* 162 * XXX: ASSERT() for now but we should understand if the test 163 * of the return value is missing because it cannot happen. 164 */ 165 ASSERT(sr->fid_ofile != NULL); 166 op->fqi.dir_snode = sr->fid_ofile->f_node; 167 smbsr_disconnect_file(sr); 168 } 169 170 status = smb_open_subr(sr); 171 if (op->sd_buf) 172 kmem_free(op->sd_buf, sd_len); 173 174 if (status != NT_STATUS_SUCCESS) { 175 if (status == NT_STATUS_SHARING_VIOLATION) 176 smbsr_raise_cifs_error(sr, 177 NT_STATUS_SHARING_VIOLATION, 178 ERRDOS, ERROR_SHARING_VIOLATION); 179 else 180 smbsr_raise_nt_error(sr, status); 181 182 /* NOTREACHED */ 183 } 184 185 if (STYPE_ISDSK(sr->tid_tree->t_res_type)) { 186 switch (MYF_OPLOCK_TYPE(op->my_flags)) { 187 case MYF_EXCLUSIVE_OPLOCK : 188 OplockLevel = 1; 189 break; 190 case MYF_BATCH_OPLOCK : 191 OplockLevel = 2; 192 break; 193 case MYF_LEVEL_II_OPLOCK : 194 OplockLevel = 3; 195 break; 196 case MYF_OPLOCK_NONE : 197 default: 198 OplockLevel = 0; 199 break; 200 } 201 202 if (op->create_options & FILE_DELETE_ON_CLOSE) 203 smb_preset_delete_on_close(sr->fid_ofile); 204 205 /* 206 * Set up the directory flag and ensure that 207 * we don't return a stale file size. 208 */ 209 node = sr->fid_ofile->f_node; 210 if (node->attr.sa_vattr.va_type == VDIR) { 211 DirFlag = 1; 212 new_attr.sa_vattr.va_size = 0; 213 } else { 214 DirFlag = 0; 215 new_attr.sa_mask = SMB_AT_SIZE; 216 (void) smb_fsop_getattr(sr, kcred, node, &new_attr); 217 node->attr.sa_vattr.va_size = new_attr.sa_vattr.va_size; 218 } 219 220 (void) smb_encode_mbc(&xa->rep_param_mb, "b.wllTTTTlqqwwb", 221 OplockLevel, 222 sr->smb_fid, 223 op->action_taken, 224 0, /* EaErrorOffset */ 225 &node->attr.sa_crtime, 226 &node->attr.sa_vattr.va_atime, 227 &node->attr.sa_vattr.va_mtime, 228 &node->attr.sa_vattr.va_ctime, 229 op->dattr & FILE_ATTRIBUTE_MASK, 230 new_attr.sa_vattr.va_size, 231 new_attr.sa_vattr.va_size, 232 op->ftype, 233 op->devstate, 234 DirFlag); 235 } else { 236 /* Named PIPE */ 237 (void) smb_encode_mbc(&xa->rep_param_mb, "b.wllTTTTlqqwwb", 238 0, 239 sr->smb_fid, 240 op->action_taken, 241 0, /* EaErrorOffset */ 242 0LL, 243 0LL, 244 0LL, 245 0LL, 246 op->dattr, 247 0x1000LL, 248 0LL, 249 op->ftype, 250 op->devstate, 251 0); 252 } 253 254 return (SDRC_NORMAL_REPLY); 255 } 256