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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 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 39 /* 40 * smb_nt_transact_create 41 * 42 * This command is used to create or open a file or directory, when EAs 43 * or an SD must be applied to the file. The request parameter block 44 * encoding, data block encoding and output parameter block encoding are 45 * described in CIFS section 4.2.2. 46 * 47 * The format of the command is SmbNtTransact but it is basically the same 48 * as SmbNtCreateAndx with the option to supply extended attributes or a 49 * security descriptor. For information not defined in CIFS section 4.2.2 50 * see section 4.2.1 (NT_CREATE_ANDX). 51 */ 52 smb_sdrc_t 53 smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) 54 { 55 struct open_param *op = &sr->arg.open; 56 uint8_t SecurityFlags; 57 uint32_t EaLength; 58 uint32_t ImpersonationLevel; 59 uint32_t NameLength; 60 uint32_t sd_len; 61 uint32_t status; 62 smb_sd_t sd; 63 int rc; 64 65 bzero(op, sizeof (sr->arg.open)); 66 67 rc = smb_mbc_decodef(&xa->req_param_mb, "%lllqllllllllb", 68 sr, 69 &op->nt_flags, 70 &op->rootdirfid, 71 &op->desired_access, 72 &op->dsize, 73 &op->dattr, 74 &op->share_access, 75 &op->create_disposition, 76 &op->create_options, 77 &sd_len, 78 &EaLength, 79 &NameLength, 80 &ImpersonationLevel, 81 &SecurityFlags); 82 83 if (rc == 0) { 84 if (NameLength == 0) { 85 op->fqi.fq_path.pn_path = "\\"; 86 } else if (NameLength >= MAXPATHLEN) { 87 smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND, 88 ERRDOS, ERROR_PATH_NOT_FOUND); 89 rc = -1; 90 } else { 91 rc = smb_mbc_decodef(&xa->req_param_mb, "%#u", 92 sr, NameLength, &op->fqi.fq_path.pn_path); 93 } 94 } 95 96 op->op_oplock_level = SMB_OPLOCK_NONE; 97 if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) { 98 if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH) 99 op->op_oplock_level = SMB_OPLOCK_BATCH; 100 else 101 op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; 102 } 103 104 if (sd_len) { 105 status = smb_decode_sd(&xa->req_data_mb, &sd); 106 if (status != NT_STATUS_SUCCESS) { 107 smbsr_error(sr, status, 0, 0); 108 return (SDRC_ERROR); 109 } 110 op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP); 111 *op->sd = sd; 112 } else { 113 op->sd = NULL; 114 } 115 116 DTRACE_SMB_2(op__NtTransactCreate__start, smb_request_t *, sr, 117 struct open_param *, op); 118 119 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 120 } 121 122 void 123 smb_post_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) 124 { 125 smb_sd_t *sd = sr->arg.open.sd; 126 127 DTRACE_SMB_2(op__NtTransactCreate__done, smb_request_t *, sr, 128 smb_xa_t *, xa); 129 130 if (sd) { 131 smb_sd_term(sd); 132 kmem_free(sd, sizeof (smb_sd_t)); 133 } 134 135 if (sr->arg.open.dir != NULL) 136 smb_ofile_release(sr->arg.open.dir); 137 } 138 139 smb_sdrc_t 140 smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) 141 { 142 struct open_param *op = &sr->arg.open; 143 uint8_t DirFlag; 144 smb_attr_t attr; 145 smb_ofile_t *of; 146 uint32_t status; 147 int rc; 148 149 if ((op->create_options & FILE_DELETE_ON_CLOSE) && 150 !(op->desired_access & DELETE)) { 151 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 152 ERRDOS, ERRbadaccess); 153 return (SDRC_ERROR); 154 } 155 156 if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { 157 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 158 ERRDOS, ERRbadaccess); 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.fq_dnode = sr->tid_tree->t_snode; 176 } else { 177 op->dir = smb_ofile_lookup_by_fid(sr, (uint16_t)op->rootdirfid); 178 if (op->dir == NULL) { 179 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 180 ERRDOS, ERRbadfid); 181 return (SDRC_ERROR); 182 } 183 op->fqi.fq_dnode = op->dir->f_node; 184 } 185 186 op->op_oplock_levelII = B_TRUE; 187 188 status = smb_common_open(sr); 189 if (status != NT_STATUS_SUCCESS) { 190 smbsr_status(sr, status, 0, 0); 191 return (SDRC_ERROR); 192 } 193 194 /* 195 * NB: after the above smb_common_open() success, 196 * we have a handle allocated (sr->fid_ofile). 197 * If we don't return success, we must close it. 198 */ 199 of = sr->fid_ofile; 200 201 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 202 case STYPE_DISKTREE: 203 case STYPE_PRINTQ: 204 if (op->create_options & FILE_DELETE_ON_CLOSE) 205 smb_ofile_set_delete_on_close(of); 206 207 DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0; 208 bzero(&attr, sizeof (attr)); 209 attr.sa_mask = SMB_AT_ALL; 210 rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr); 211 if (rc != 0) { 212 smbsr_errno(sr, rc); 213 goto errout; 214 } 215 216 rc = smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb", 217 op->op_oplock_level, 218 sr->smb_fid, 219 op->action_taken, 220 0, /* EaErrorOffset */ 221 &attr.sa_crtime, 222 &attr.sa_vattr.va_atime, 223 &attr.sa_vattr.va_mtime, 224 &attr.sa_vattr.va_ctime, 225 op->dattr & FILE_ATTRIBUTE_MASK, 226 attr.sa_allocsz, 227 attr.sa_vattr.va_size, 228 op->ftype, 229 op->devstate, 230 DirFlag); 231 break; 232 233 case STYPE_IPC: 234 bzero(&attr, sizeof (smb_attr_t)); 235 rc = smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb", 236 0, 237 sr->smb_fid, 238 op->action_taken, 239 0, /* EaErrorOffset */ 240 &attr.sa_crtime, 241 &attr.sa_vattr.va_atime, 242 &attr.sa_vattr.va_mtime, 243 &attr.sa_vattr.va_ctime, 244 op->dattr, 245 0x1000LL, 246 0LL, 247 op->ftype, 248 op->devstate, 249 0); 250 break; 251 252 default: 253 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, 254 ERRDOS, ERROR_INVALID_FUNCTION); 255 goto errout; 256 } 257 return (SDRC_SUCCESS); 258 259 errout: 260 smb_ofile_close(of, 0); 261 return (SDRC_ERROR); 262 } 263