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