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 2009 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 ImpersonationLevel; 64 uint32_t NameLength; 65 uint32_t sd_len; 66 uint32_t status; 67 smb_sd_t sd; 68 int rc; 69 70 bzero(op, sizeof (sr->arg.open)); 71 72 rc = smb_mbc_decodef(&xa->req_param_mb, "%lllqllllllllb", 73 sr, 74 &op->nt_flags, 75 &op->rootdirfid, 76 &op->desired_access, 77 &op->dsize, 78 &op->dattr, 79 &op->share_access, 80 &op->create_disposition, 81 &op->create_options, 82 &sd_len, 83 &EaLength, 84 &NameLength, 85 &ImpersonationLevel, 86 &SecurityFlags); 87 88 if (rc == 0) { 89 if (NameLength == 0) { 90 op->fqi.fq_path.pn_path = "\\"; 91 } else if (NameLength >= MAXPATHLEN) { 92 smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND, 93 ERRDOS, ERROR_PATH_NOT_FOUND); 94 rc = -1; 95 } else { 96 rc = smb_mbc_decodef(&xa->req_param_mb, "%#u", 97 sr, NameLength, &op->fqi.fq_path.pn_path); 98 } 99 } 100 101 op->op_oplock_level = SMB_OPLOCK_NONE; 102 if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) { 103 if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH) 104 op->op_oplock_level = SMB_OPLOCK_BATCH; 105 else 106 op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; 107 } 108 109 if (sd_len) { 110 status = smb_decode_sd(xa, &sd); 111 if (status != NT_STATUS_SUCCESS) { 112 smbsr_error(sr, status, 0, 0); 113 return (SDRC_ERROR); 114 } 115 op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP); 116 *op->sd = sd; 117 } else { 118 op->sd = NULL; 119 } 120 121 DTRACE_SMB_2(op__NtTransactCreate__start, smb_request_t *, sr, 122 struct open_param *, op); 123 124 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 125 } 126 127 void 128 smb_post_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) 129 { 130 smb_sd_t *sd = sr->arg.open.sd; 131 132 DTRACE_SMB_2(op__NtTransactCreate__done, smb_request_t *, sr, 133 smb_xa_t *, xa); 134 135 if (sd) { 136 smb_sd_term(sd); 137 kmem_free(sd, sizeof (smb_sd_t)); 138 } 139 } 140 141 smb_sdrc_t 142 smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) 143 { 144 struct open_param *op = &sr->arg.open; 145 uint8_t OplockLevel; 146 uint8_t DirFlag; 147 smb_attr_t attr; 148 smb_node_t *node; 149 uint32_t status; 150 151 if ((op->create_options & FILE_DELETE_ON_CLOSE) && 152 !(op->desired_access & DELETE)) { 153 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 154 ERRDOS, ERRbadaccess); 155 return (SDRC_ERROR); 156 } 157 158 if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { 159 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 160 ERRDOS, ERRbadaccess); 161 return (SDRC_ERROR); 162 } 163 164 if (op->dattr & FILE_FLAG_WRITE_THROUGH) 165 op->create_options |= FILE_WRITE_THROUGH; 166 167 if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE) 168 op->create_options |= FILE_DELETE_ON_CLOSE; 169 170 if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS) 171 op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT; 172 173 if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) 174 sr->user_cr = smb_user_getprivcred(sr->uid_user); 175 176 if (op->rootdirfid == 0) { 177 op->fqi.fq_dnode = sr->tid_tree->t_snode; 178 } else { 179 sr->smb_fid = (ushort_t)op->rootdirfid; 180 smbsr_lookup_file(sr); 181 if (sr->fid_ofile == NULL) { 182 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 183 ERRDOS, ERRbadfid); 184 return (SDRC_ERROR); 185 } 186 187 op->fqi.fq_dnode = sr->fid_ofile->f_node; 188 smbsr_disconnect_file(sr); 189 } 190 191 status = smb_common_open(sr); 192 193 if (status != NT_STATUS_SUCCESS) 194 return (SDRC_ERROR); 195 196 if (STYPE_ISDSK(sr->tid_tree->t_res_type)) { 197 switch (op->op_oplock_level) { 198 case SMB_OPLOCK_EXCLUSIVE: 199 OplockLevel = 1; 200 break; 201 case SMB_OPLOCK_BATCH: 202 OplockLevel = 2; 203 break; 204 case SMB_OPLOCK_LEVEL_II: 205 OplockLevel = 3; 206 break; 207 case SMB_OPLOCK_NONE: 208 default: 209 OplockLevel = 0; 210 break; 211 } 212 213 if (op->create_options & FILE_DELETE_ON_CLOSE) 214 smb_ofile_set_delete_on_close(sr->fid_ofile); 215 216 node = sr->fid_ofile->f_node; 217 DirFlag = smb_node_is_dir(node) ? 1 : 0; 218 if (smb_node_getattr(sr, node, &attr) != 0) { 219 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 220 ERRDOS, ERROR_INTERNAL_ERROR); 221 return (SDRC_ERROR); 222 } 223 224 (void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb", 225 OplockLevel, 226 sr->smb_fid, 227 op->action_taken, 228 0, /* EaErrorOffset */ 229 &attr.sa_crtime, 230 &attr.sa_vattr.va_atime, 231 &attr.sa_vattr.va_mtime, 232 &attr.sa_vattr.va_ctime, 233 op->dattr & FILE_ATTRIBUTE_MASK, 234 attr.sa_vattr.va_size, 235 attr.sa_vattr.va_size, 236 op->ftype, 237 op->devstate, 238 DirFlag); 239 } else { 240 /* Named PIPE */ 241 bzero(&attr, sizeof (smb_attr_t)); 242 (void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb", 243 0, 244 sr->smb_fid, 245 op->action_taken, 246 0, /* EaErrorOffset */ 247 &attr.sa_crtime, 248 &attr.sa_vattr.va_atime, 249 &attr.sa_vattr.va_mtime, 250 &attr.sa_vattr.va_ctime, 251 op->dattr, 252 0x1000LL, 253 0LL, 254 op->ftype, 255 op->devstate, 256 0); 257 } 258 259 return (SDRC_SUCCESS); 260 } 261