1*a90cf9f2SGordon Ross /* 2*a90cf9f2SGordon Ross * This file and its contents are supplied under the terms of the 3*a90cf9f2SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0. 4*a90cf9f2SGordon Ross * You may only use this file in accordance with the terms of version 5*a90cf9f2SGordon Ross * 1.0 of the CDDL. 6*a90cf9f2SGordon Ross * 7*a90cf9f2SGordon Ross * A full copy of the text of the CDDL should have accompanied this 8*a90cf9f2SGordon Ross * source. A copy of the CDDL is also available via the Internet at 9*a90cf9f2SGordon Ross * http://www.illumos.org/license/CDDL. 10*a90cf9f2SGordon Ross */ 11*a90cf9f2SGordon Ross 12*a90cf9f2SGordon Ross /* 13*a90cf9f2SGordon Ross * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 14*a90cf9f2SGordon Ross */ 15*a90cf9f2SGordon Ross 16*a90cf9f2SGordon Ross /* 17*a90cf9f2SGordon Ross * Dispatch function for SMB2_CREATE 18*a90cf9f2SGordon Ross * [MS-SMB2] 2.2.13 19*a90cf9f2SGordon Ross */ 20*a90cf9f2SGordon Ross 21*a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h> 22*a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h> 23*a90cf9f2SGordon Ross 24*a90cf9f2SGordon Ross /* 25*a90cf9f2SGordon Ross * Some flags used locally to keep track of which Create Context 26*a90cf9f2SGordon Ross * names have been provided and/or requested. 27*a90cf9f2SGordon Ross */ 28*a90cf9f2SGordon Ross #define CCTX_EA_BUFFER 1 29*a90cf9f2SGordon Ross #define CCTX_SD_BUFFER 2 30*a90cf9f2SGordon Ross #define CCTX_DH_REQUEST 4 31*a90cf9f2SGordon Ross #define CCTX_DH_RECONNECT 8 32*a90cf9f2SGordon Ross #define CCTX_ALLOCATION_SIZE 0x10 33*a90cf9f2SGordon Ross #define CCTX_QUERY_MAX_ACCESS 0x20 34*a90cf9f2SGordon Ross #define CCTX_TIMEWARP_TOKEN 0x40 35*a90cf9f2SGordon Ross #define CCTX_QUERY_ON_DISK_ID 0x80 36*a90cf9f2SGordon Ross #define CCTX_REQUEST_LEASE 0x100 37*a90cf9f2SGordon Ross 38*a90cf9f2SGordon Ross 39*a90cf9f2SGordon Ross typedef struct smb2_create_ctx_elem { 40*a90cf9f2SGordon Ross uint32_t cce_len; 41*a90cf9f2SGordon Ross mbuf_chain_t cce_mbc; 42*a90cf9f2SGordon Ross } smb2_create_ctx_elem_t; 43*a90cf9f2SGordon Ross 44*a90cf9f2SGordon Ross typedef struct smb2_create_ctx { 45*a90cf9f2SGordon Ross uint_t cc_in_flags; /* CCTX_... */ 46*a90cf9f2SGordon Ross uint_t cc_out_flags; /* CCTX_... */ 47*a90cf9f2SGordon Ross /* Elements we may see in the request. */ 48*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_in_ext_attr; 49*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_in_sec_desc; 50*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_in_dh_request; 51*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_in_dh_reconnect; 52*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_in_alloc_size; 53*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_in_time_warp; 54*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_in_req_lease; 55*a90cf9f2SGordon Ross /* Elements we my place in the response */ 56*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_out_max_access; 57*a90cf9f2SGordon Ross smb2_create_ctx_elem_t cc_out_file_id; 58*a90cf9f2SGordon Ross } smb2_create_ctx_t; 59*a90cf9f2SGordon Ross 60*a90cf9f2SGordon Ross static uint32_t smb2_decode_create_ctx( 61*a90cf9f2SGordon Ross mbuf_chain_t *, smb2_create_ctx_t *); 62*a90cf9f2SGordon Ross static uint32_t smb2_encode_create_ctx( 63*a90cf9f2SGordon Ross mbuf_chain_t *, smb2_create_ctx_t *); 64*a90cf9f2SGordon Ross static int smb2_encode_create_ctx_elem( 65*a90cf9f2SGordon Ross mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t); 66*a90cf9f2SGordon Ross static void smb2_free_create_ctx(smb2_create_ctx_t *); 67*a90cf9f2SGordon Ross 68*a90cf9f2SGordon Ross smb_sdrc_t 69*a90cf9f2SGordon Ross smb2_create(smb_request_t *sr) 70*a90cf9f2SGordon Ross { 71*a90cf9f2SGordon Ross smb_attr_t *attr; 72*a90cf9f2SGordon Ross smb2_create_ctx_elem_t *cce; 73*a90cf9f2SGordon Ross smb2_create_ctx_t cctx; 74*a90cf9f2SGordon Ross mbuf_chain_t cc_mbc; 75*a90cf9f2SGordon Ross smb_arg_open_t *op = &sr->arg.open; 76*a90cf9f2SGordon Ross smb_ofile_t *of = NULL; 77*a90cf9f2SGordon Ross uint16_t StructSize; 78*a90cf9f2SGordon Ross uint8_t SecurityFlags; 79*a90cf9f2SGordon Ross uint8_t OplockLevel; 80*a90cf9f2SGordon Ross uint32_t ImpersonationLevel; 81*a90cf9f2SGordon Ross uint64_t SmbCreateFlags; 82*a90cf9f2SGordon Ross uint64_t Reserved4; 83*a90cf9f2SGordon Ross uint16_t NameOffset; 84*a90cf9f2SGordon Ross uint16_t NameLength; 85*a90cf9f2SGordon Ross uint32_t CreateCtxOffset; 86*a90cf9f2SGordon Ross uint32_t CreateCtxLength; 87*a90cf9f2SGordon Ross smb2fid_t smb2fid; 88*a90cf9f2SGordon Ross uint32_t status; 89*a90cf9f2SGordon Ross int skip; 90*a90cf9f2SGordon Ross int rc = 0; 91*a90cf9f2SGordon Ross 92*a90cf9f2SGordon Ross bzero(&cctx, sizeof (cctx)); 93*a90cf9f2SGordon Ross bzero(&cc_mbc, sizeof (cc_mbc)); 94*a90cf9f2SGordon Ross 95*a90cf9f2SGordon Ross /* 96*a90cf9f2SGordon Ross * Paranoia. This will set sr->fid_ofile, so 97*a90cf9f2SGordon Ross * if we already have one, release it now. 98*a90cf9f2SGordon Ross */ 99*a90cf9f2SGordon Ross if (sr->fid_ofile != NULL) { 100*a90cf9f2SGordon Ross smb_ofile_request_complete(sr->fid_ofile); 101*a90cf9f2SGordon Ross smb_ofile_release(sr->fid_ofile); 102*a90cf9f2SGordon Ross sr->fid_ofile = NULL; 103*a90cf9f2SGordon Ross } 104*a90cf9f2SGordon Ross 105*a90cf9f2SGordon Ross /* 106*a90cf9f2SGordon Ross * SMB2 Create request 107*a90cf9f2SGordon Ross */ 108*a90cf9f2SGordon Ross rc = smb_mbc_decodef( 109*a90cf9f2SGordon Ross &sr->smb_data, "wbblqqlllllwwll", 110*a90cf9f2SGordon Ross &StructSize, /* w */ 111*a90cf9f2SGordon Ross &SecurityFlags, /* b */ 112*a90cf9f2SGordon Ross &OplockLevel, /* b */ 113*a90cf9f2SGordon Ross &ImpersonationLevel, /* l */ 114*a90cf9f2SGordon Ross &SmbCreateFlags, /* q */ 115*a90cf9f2SGordon Ross &Reserved4, /* q */ 116*a90cf9f2SGordon Ross &op->desired_access, /* l */ 117*a90cf9f2SGordon Ross &op->dattr, /* l */ 118*a90cf9f2SGordon Ross &op->share_access, /* l */ 119*a90cf9f2SGordon Ross &op->create_disposition, /* l */ 120*a90cf9f2SGordon Ross &op->create_options, /* l */ 121*a90cf9f2SGordon Ross &NameOffset, /* w */ 122*a90cf9f2SGordon Ross &NameLength, /* w */ 123*a90cf9f2SGordon Ross &CreateCtxOffset, /* l */ 124*a90cf9f2SGordon Ross &CreateCtxLength); /* l */ 125*a90cf9f2SGordon Ross if (rc != 0 || StructSize != 57) 126*a90cf9f2SGordon Ross return (SDRC_ERROR); 127*a90cf9f2SGordon Ross 128*a90cf9f2SGordon Ross /* 129*a90cf9f2SGordon Ross * We're normally positioned at the path name now, 130*a90cf9f2SGordon Ross * but there could be some padding before it. 131*a90cf9f2SGordon Ross */ 132*a90cf9f2SGordon Ross skip = (NameOffset + sr->smb2_cmd_hdr) - 133*a90cf9f2SGordon Ross sr->smb_data.chain_offset; 134*a90cf9f2SGordon Ross if (skip < 0) { 135*a90cf9f2SGordon Ross status = NT_STATUS_OBJECT_PATH_INVALID; 136*a90cf9f2SGordon Ross goto errout; 137*a90cf9f2SGordon Ross } 138*a90cf9f2SGordon Ross if (skip > 0) 139*a90cf9f2SGordon Ross (void) smb_mbc_decodef(&sr->smb_data, "#.", skip); 140*a90cf9f2SGordon Ross 141*a90cf9f2SGordon Ross /* 142*a90cf9f2SGordon Ross * Get the path name 143*a90cf9f2SGordon Ross */ 144*a90cf9f2SGordon Ross if (NameLength >= SMB_MAXPATHLEN) { 145*a90cf9f2SGordon Ross status = NT_STATUS_OBJECT_PATH_INVALID; 146*a90cf9f2SGordon Ross goto errout; 147*a90cf9f2SGordon Ross } 148*a90cf9f2SGordon Ross if (NameLength == 0) { 149*a90cf9f2SGordon Ross op->fqi.fq_path.pn_path = "\\"; 150*a90cf9f2SGordon Ross } else { 151*a90cf9f2SGordon Ross rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr, 152*a90cf9f2SGordon Ross NameLength, &op->fqi.fq_path.pn_path); 153*a90cf9f2SGordon Ross if (rc) { 154*a90cf9f2SGordon Ross status = NT_STATUS_OBJECT_PATH_INVALID; 155*a90cf9f2SGordon Ross goto errout; 156*a90cf9f2SGordon Ross } 157*a90cf9f2SGordon Ross } 158*a90cf9f2SGordon Ross op->fqi.fq_dnode = sr->tid_tree->t_snode; 159*a90cf9f2SGordon Ross 160*a90cf9f2SGordon Ross switch (OplockLevel) { 161*a90cf9f2SGordon Ross case SMB2_OPLOCK_LEVEL_NONE: 162*a90cf9f2SGordon Ross op->op_oplock_level = SMB_OPLOCK_NONE; 163*a90cf9f2SGordon Ross break; 164*a90cf9f2SGordon Ross case SMB2_OPLOCK_LEVEL_II: 165*a90cf9f2SGordon Ross op->op_oplock_level = SMB_OPLOCK_LEVEL_II; 166*a90cf9f2SGordon Ross break; 167*a90cf9f2SGordon Ross case SMB2_OPLOCK_LEVEL_EXCLUSIVE: 168*a90cf9f2SGordon Ross op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; 169*a90cf9f2SGordon Ross break; 170*a90cf9f2SGordon Ross case SMB2_OPLOCK_LEVEL_BATCH: 171*a90cf9f2SGordon Ross op->op_oplock_level = SMB_OPLOCK_BATCH; 172*a90cf9f2SGordon Ross break; 173*a90cf9f2SGordon Ross case SMB2_OPLOCK_LEVEL_LEASE: 174*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 175*a90cf9f2SGordon Ross goto errout; 176*a90cf9f2SGordon Ross } 177*a90cf9f2SGordon Ross op->op_oplock_levelII = B_TRUE; 178*a90cf9f2SGordon Ross 179*a90cf9f2SGordon Ross /* 180*a90cf9f2SGordon Ross * ImpersonationLevel (spec. says ignore) 181*a90cf9f2SGordon Ross * SmbCreateFlags (spec. says ignore) 182*a90cf9f2SGordon Ross */ 183*a90cf9f2SGordon Ross 184*a90cf9f2SGordon Ross if ((op->create_options & FILE_DELETE_ON_CLOSE) && 185*a90cf9f2SGordon Ross !(op->desired_access & DELETE)) { 186*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 187*a90cf9f2SGordon Ross goto errout; 188*a90cf9f2SGordon Ross } 189*a90cf9f2SGordon Ross if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { 190*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 191*a90cf9f2SGordon Ross goto errout; 192*a90cf9f2SGordon Ross } 193*a90cf9f2SGordon Ross 194*a90cf9f2SGordon Ross if (op->dattr & FILE_FLAG_WRITE_THROUGH) 195*a90cf9f2SGordon Ross op->create_options |= FILE_WRITE_THROUGH; 196*a90cf9f2SGordon Ross if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE) 197*a90cf9f2SGordon Ross op->create_options |= FILE_DELETE_ON_CLOSE; 198*a90cf9f2SGordon Ross if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS) 199*a90cf9f2SGordon Ross op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT; 200*a90cf9f2SGordon Ross if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) 201*a90cf9f2SGordon Ross sr->user_cr = smb_user_getprivcred(sr->uid_user); 202*a90cf9f2SGordon Ross 203*a90cf9f2SGordon Ross /* 204*a90cf9f2SGordon Ross * If there is a "Create Context" payload, decode it. 205*a90cf9f2SGordon Ross * This may carry things like a security descriptor, 206*a90cf9f2SGordon Ross * extended attributes, etc. to be used in create. 207*a90cf9f2SGordon Ross * 208*a90cf9f2SGordon Ross * The create ctx buffer must start after the headers 209*a90cf9f2SGordon Ross * and file name, and must be 8-byte aligned. 210*a90cf9f2SGordon Ross */ 211*a90cf9f2SGordon Ross if (CreateCtxLength != 0) { 212*a90cf9f2SGordon Ross if ((CreateCtxOffset & 7) != 0 || 213*a90cf9f2SGordon Ross (CreateCtxOffset + sr->smb2_cmd_hdr) < 214*a90cf9f2SGordon Ross sr->smb_data.chain_offset) { 215*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 216*a90cf9f2SGordon Ross goto errout; 217*a90cf9f2SGordon Ross } 218*a90cf9f2SGordon Ross 219*a90cf9f2SGordon Ross rc = MBC_SHADOW_CHAIN(&cc_mbc, &sr->smb_data, 220*a90cf9f2SGordon Ross sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength); 221*a90cf9f2SGordon Ross if (rc) { 222*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 223*a90cf9f2SGordon Ross goto errout; 224*a90cf9f2SGordon Ross } 225*a90cf9f2SGordon Ross status = smb2_decode_create_ctx(&cc_mbc, &cctx); 226*a90cf9f2SGordon Ross if (status) 227*a90cf9f2SGordon Ross goto errout; 228*a90cf9f2SGordon Ross 229*a90cf9f2SGordon Ross if (cctx.cc_in_flags & CCTX_EA_BUFFER) { 230*a90cf9f2SGordon Ross status = NT_STATUS_EAS_NOT_SUPPORTED; 231*a90cf9f2SGordon Ross goto errout; 232*a90cf9f2SGordon Ross } 233*a90cf9f2SGordon Ross 234*a90cf9f2SGordon Ross if (cctx.cc_in_flags & CCTX_SD_BUFFER) { 235*a90cf9f2SGordon Ross smb_sd_t sd; 236*a90cf9f2SGordon Ross cce = &cctx.cc_in_sec_desc; 237*a90cf9f2SGordon Ross status = smb_decode_sd( 238*a90cf9f2SGordon Ross &cce->cce_mbc, &sd); 239*a90cf9f2SGordon Ross if (status) 240*a90cf9f2SGordon Ross goto errout; 241*a90cf9f2SGordon Ross op->sd = kmem_alloc(sizeof (sd), KM_SLEEP); 242*a90cf9f2SGordon Ross *op->sd = sd; 243*a90cf9f2SGordon Ross } 244*a90cf9f2SGordon Ross 245*a90cf9f2SGordon Ross if (cctx.cc_in_flags & CCTX_ALLOCATION_SIZE) { 246*a90cf9f2SGordon Ross cce = &cctx.cc_in_alloc_size; 247*a90cf9f2SGordon Ross rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize); 248*a90cf9f2SGordon Ross if (rc) { 249*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 250*a90cf9f2SGordon Ross goto errout; 251*a90cf9f2SGordon Ross } 252*a90cf9f2SGordon Ross } 253*a90cf9f2SGordon Ross 254*a90cf9f2SGordon Ross /* 255*a90cf9f2SGordon Ross * Support for opening "Previous Versions". 256*a90cf9f2SGordon Ross * [MS-SMB2] 2.2.13.2.7 Data is an NT time. 257*a90cf9f2SGordon Ross */ 258*a90cf9f2SGordon Ross if (cctx.cc_in_flags & CCTX_TIMEWARP_TOKEN) { 259*a90cf9f2SGordon Ross uint64_t timewarp; 260*a90cf9f2SGordon Ross cce = &cctx.cc_in_time_warp; 261*a90cf9f2SGordon Ross status = smb_mbc_decodef(&cce->cce_mbc, 262*a90cf9f2SGordon Ross "q", &timewarp); 263*a90cf9f2SGordon Ross if (status) 264*a90cf9f2SGordon Ross goto errout; 265*a90cf9f2SGordon Ross smb_time_nt_to_unix(timewarp, &op->timewarp); 266*a90cf9f2SGordon Ross op->create_timewarp = B_TRUE; 267*a90cf9f2SGordon Ross } 268*a90cf9f2SGordon Ross } 269*a90cf9f2SGordon Ross 270*a90cf9f2SGordon Ross /* 271*a90cf9f2SGordon Ross * The real open call. Note: this gets attributes into 272*a90cf9f2SGordon Ross * op->fqi.fq_fattr (SMB_AT_ALL). We need those below. 273*a90cf9f2SGordon Ross */ 274*a90cf9f2SGordon Ross status = smb_common_open(sr); 275*a90cf9f2SGordon Ross if (status != NT_STATUS_SUCCESS) 276*a90cf9f2SGordon Ross goto errout; 277*a90cf9f2SGordon Ross attr = &op->fqi.fq_fattr; 278*a90cf9f2SGordon Ross 279*a90cf9f2SGordon Ross /* 280*a90cf9f2SGordon Ross * Convert the negotiate Oplock level back into 281*a90cf9f2SGordon Ross * SMB2 encoding form. 282*a90cf9f2SGordon Ross */ 283*a90cf9f2SGordon Ross switch (op->op_oplock_level) { 284*a90cf9f2SGordon Ross default: 285*a90cf9f2SGordon Ross case SMB_OPLOCK_NONE: 286*a90cf9f2SGordon Ross OplockLevel = SMB2_OPLOCK_LEVEL_NONE; 287*a90cf9f2SGordon Ross break; 288*a90cf9f2SGordon Ross case SMB_OPLOCK_LEVEL_II: 289*a90cf9f2SGordon Ross OplockLevel = SMB2_OPLOCK_LEVEL_II; 290*a90cf9f2SGordon Ross break; 291*a90cf9f2SGordon Ross case SMB_OPLOCK_EXCLUSIVE: 292*a90cf9f2SGordon Ross OplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 293*a90cf9f2SGordon Ross break; 294*a90cf9f2SGordon Ross case SMB_OPLOCK_BATCH: 295*a90cf9f2SGordon Ross OplockLevel = SMB2_OPLOCK_LEVEL_BATCH; 296*a90cf9f2SGordon Ross break; 297*a90cf9f2SGordon Ross } 298*a90cf9f2SGordon Ross 299*a90cf9f2SGordon Ross /* 300*a90cf9f2SGordon Ross * NB: after the above smb_common_open() success, 301*a90cf9f2SGordon Ross * we have a handle allocated (sr->fid_ofile). 302*a90cf9f2SGordon Ross * If we don't return success, we must close it. 303*a90cf9f2SGordon Ross * 304*a90cf9f2SGordon Ross * Using sr->smb_fid as the file handle for now, 305*a90cf9f2SGordon Ross * though it could later be something larger, 306*a90cf9f2SGordon Ross * (16 bytes) similar to an NFSv4 open handle. 307*a90cf9f2SGordon Ross */ 308*a90cf9f2SGordon Ross of = sr->fid_ofile; 309*a90cf9f2SGordon Ross smb2fid.persistent = 0; 310*a90cf9f2SGordon Ross smb2fid.temporal = sr->smb_fid; 311*a90cf9f2SGordon Ross 312*a90cf9f2SGordon Ross switch (sr->tid_tree->t_res_type & STYPE_MASK) { 313*a90cf9f2SGordon Ross case STYPE_DISKTREE: 314*a90cf9f2SGordon Ross case STYPE_PRINTQ: 315*a90cf9f2SGordon Ross if (op->create_options & FILE_DELETE_ON_CLOSE) 316*a90cf9f2SGordon Ross smb_ofile_set_delete_on_close(of); 317*a90cf9f2SGordon Ross break; 318*a90cf9f2SGordon Ross } 319*a90cf9f2SGordon Ross 320*a90cf9f2SGordon Ross /* 321*a90cf9f2SGordon Ross * Build the Create Context to return; first the 322*a90cf9f2SGordon Ross * per-element parts, then the aggregated buffer. 323*a90cf9f2SGordon Ross * 324*a90cf9f2SGordon Ross * No response for these: 325*a90cf9f2SGordon Ross * CCTX_EA_BUFFER 326*a90cf9f2SGordon Ross * CCTX_SD_BUFFER 327*a90cf9f2SGordon Ross * CCTX_ALLOCATION_SIZE 328*a90cf9f2SGordon Ross * CCTX_TIMEWARP_TOKEN 329*a90cf9f2SGordon Ross * 330*a90cf9f2SGordon Ross * We don't handle these yet. 331*a90cf9f2SGordon Ross * CCTX_DH_REQUEST 332*a90cf9f2SGordon Ross * CCTX_DH_RECONNECT 333*a90cf9f2SGordon Ross * CCTX_REQUEST_LEASE 334*a90cf9f2SGordon Ross */ 335*a90cf9f2SGordon Ross if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) { 336*a90cf9f2SGordon Ross cce = &cctx.cc_out_max_access; 337*a90cf9f2SGordon Ross uint32_t MaxAccess = 0; 338*a90cf9f2SGordon Ross if (of->f_node != NULL) { 339*a90cf9f2SGordon Ross smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess); 340*a90cf9f2SGordon Ross } 341*a90cf9f2SGordon Ross MaxAccess |= of->f_granted_access; 342*a90cf9f2SGordon Ross cce->cce_len = 8; 343*a90cf9f2SGordon Ross cce->cce_mbc.max_bytes = 8; 344*a90cf9f2SGordon Ross (void) smb_mbc_encodef(&cce->cce_mbc, 345*a90cf9f2SGordon Ross "ll", 0, MaxAccess); 346*a90cf9f2SGordon Ross cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS; 347*a90cf9f2SGordon Ross } 348*a90cf9f2SGordon Ross if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 && 349*a90cf9f2SGordon Ross of->f_node != NULL) { 350*a90cf9f2SGordon Ross cce = &cctx.cc_out_file_id; 351*a90cf9f2SGordon Ross fsid_t fsid; 352*a90cf9f2SGordon Ross 353*a90cf9f2SGordon Ross fsid = SMB_NODE_FSID(of->f_node); 354*a90cf9f2SGordon Ross 355*a90cf9f2SGordon Ross cce->cce_len = 32; 356*a90cf9f2SGordon Ross cce->cce_mbc.max_bytes = 32; 357*a90cf9f2SGordon Ross (void) smb_mbc_encodef( 358*a90cf9f2SGordon Ross &cce->cce_mbc, "qll.15.", 359*a90cf9f2SGordon Ross op->fileid, /* q */ 360*a90cf9f2SGordon Ross fsid.val[0], /* l */ 361*a90cf9f2SGordon Ross fsid.val[1]); /* l */ 362*a90cf9f2SGordon Ross /* reserved (16 bytes) .15. */ 363*a90cf9f2SGordon Ross cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID; 364*a90cf9f2SGordon Ross } 365*a90cf9f2SGordon Ross if (cctx.cc_out_flags) { 366*a90cf9f2SGordon Ross sr->raw_data.max_bytes = smb2_max_trans; 367*a90cf9f2SGordon Ross status = smb2_encode_create_ctx(&sr->raw_data, &cctx); 368*a90cf9f2SGordon Ross if (status) 369*a90cf9f2SGordon Ross goto errout; 370*a90cf9f2SGordon Ross } 371*a90cf9f2SGordon Ross 372*a90cf9f2SGordon Ross /* 373*a90cf9f2SGordon Ross * SMB2 Create reply 374*a90cf9f2SGordon Ross */ 375*a90cf9f2SGordon Ross rc = smb_mbc_encodef( 376*a90cf9f2SGordon Ross &sr->reply, 377*a90cf9f2SGordon Ross "wb.lTTTTqqllqqll", 378*a90cf9f2SGordon Ross 89, /* StructSize */ /* w */ 379*a90cf9f2SGordon Ross OplockLevel, /* b */ 380*a90cf9f2SGordon Ross op->action_taken, /* l */ 381*a90cf9f2SGordon Ross &attr->sa_crtime, /* T */ 382*a90cf9f2SGordon Ross &attr->sa_vattr.va_atime, /* T */ 383*a90cf9f2SGordon Ross &attr->sa_vattr.va_mtime, /* T */ 384*a90cf9f2SGordon Ross &attr->sa_vattr.va_ctime, /* T */ 385*a90cf9f2SGordon Ross attr->sa_allocsz, /* q */ 386*a90cf9f2SGordon Ross attr->sa_vattr.va_size, /* q */ 387*a90cf9f2SGordon Ross attr->sa_dosattr, /* l */ 388*a90cf9f2SGordon Ross 0, /* reserved2 */ /* l */ 389*a90cf9f2SGordon Ross smb2fid.persistent, /* q */ 390*a90cf9f2SGordon Ross smb2fid.temporal, /* q */ 391*a90cf9f2SGordon Ross 0, /* CreateCtxOffset l */ 392*a90cf9f2SGordon Ross 0); /* CreateCtxLength l */ 393*a90cf9f2SGordon Ross if (rc != 0) { 394*a90cf9f2SGordon Ross status = NT_STATUS_UNSUCCESSFUL; 395*a90cf9f2SGordon Ross goto errout; 396*a90cf9f2SGordon Ross } 397*a90cf9f2SGordon Ross 398*a90cf9f2SGordon Ross CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr; 399*a90cf9f2SGordon Ross CreateCtxLength = MBC_LENGTH(&sr->raw_data); 400*a90cf9f2SGordon Ross if (CreateCtxLength != 0) { 401*a90cf9f2SGordon Ross /* 402*a90cf9f2SGordon Ross * Overwrite CreateCtxOffset, CreateCtxLength, pad 403*a90cf9f2SGordon Ross */ 404*a90cf9f2SGordon Ross sr->reply.chain_offset -= 8; 405*a90cf9f2SGordon Ross rc = smb_mbc_encodef( 406*a90cf9f2SGordon Ross &sr->reply, 407*a90cf9f2SGordon Ross "ll#C", 408*a90cf9f2SGordon Ross CreateCtxOffset, /* l */ 409*a90cf9f2SGordon Ross CreateCtxLength, /* l */ 410*a90cf9f2SGordon Ross CreateCtxLength, /* # */ 411*a90cf9f2SGordon Ross &sr->raw_data); /* C */ 412*a90cf9f2SGordon Ross if (rc != 0) { 413*a90cf9f2SGordon Ross status = NT_STATUS_UNSUCCESSFUL; 414*a90cf9f2SGordon Ross goto errout; 415*a90cf9f2SGordon Ross } 416*a90cf9f2SGordon Ross } else { 417*a90cf9f2SGordon Ross (void) smb_mbc_encodef(&sr->reply, "."); 418*a90cf9f2SGordon Ross } 419*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 420*a90cf9f2SGordon Ross 421*a90cf9f2SGordon Ross errout: 422*a90cf9f2SGordon Ross if (of != NULL) 423*a90cf9f2SGordon Ross smb_ofile_close(of, 0); 424*a90cf9f2SGordon Ross if (cctx.cc_out_flags) 425*a90cf9f2SGordon Ross smb2_free_create_ctx(&cctx); 426*a90cf9f2SGordon Ross smb2sr_put_error(sr, status); 427*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 428*a90cf9f2SGordon Ross } 429*a90cf9f2SGordon Ross 430*a90cf9f2SGordon Ross /* 431*a90cf9f2SGordon Ross * Decode an SMB2 Create Context buffer into our internal form. 432*a90cf9f2SGordon Ross * No policy decisions about what's supported here, just decode. 433*a90cf9f2SGordon Ross */ 434*a90cf9f2SGordon Ross static uint32_t 435*a90cf9f2SGordon Ross smb2_decode_create_ctx(mbuf_chain_t *in_mbc, smb2_create_ctx_t *cc) 436*a90cf9f2SGordon Ross { 437*a90cf9f2SGordon Ross smb2_create_ctx_elem_t *cce; 438*a90cf9f2SGordon Ross mbuf_chain_t name_mbc; 439*a90cf9f2SGordon Ross union { 440*a90cf9f2SGordon Ross uint32_t i; 441*a90cf9f2SGordon Ross char ch[4]; 442*a90cf9f2SGordon Ross } cc_name; 443*a90cf9f2SGordon Ross uint32_t status; 444*a90cf9f2SGordon Ross int32_t next_off; 445*a90cf9f2SGordon Ross uint32_t data_len; 446*a90cf9f2SGordon Ross uint16_t data_off; 447*a90cf9f2SGordon Ross uint16_t name_off; 448*a90cf9f2SGordon Ross uint16_t name_len; 449*a90cf9f2SGordon Ross int top_offset; 450*a90cf9f2SGordon Ross int rc; 451*a90cf9f2SGordon Ross 452*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 453*a90cf9f2SGordon Ross for (;;) { 454*a90cf9f2SGordon Ross cce = NULL; 455*a90cf9f2SGordon Ross top_offset = in_mbc->chain_offset; 456*a90cf9f2SGordon Ross rc = smb_mbc_decodef( 457*a90cf9f2SGordon Ross in_mbc, 458*a90cf9f2SGordon Ross "lww..wl", 459*a90cf9f2SGordon Ross &next_off, /* l */ 460*a90cf9f2SGordon Ross &name_off, /* w */ 461*a90cf9f2SGordon Ross &name_len, /* w */ 462*a90cf9f2SGordon Ross /* reserved .. */ 463*a90cf9f2SGordon Ross &data_off, /* w */ 464*a90cf9f2SGordon Ross &data_len); /* l */ 465*a90cf9f2SGordon Ross if (rc) 466*a90cf9f2SGordon Ross break; 467*a90cf9f2SGordon Ross 468*a90cf9f2SGordon Ross /* 469*a90cf9f2SGordon Ross * The Create Context "name", per [MS-SMB] 2.2.13.2 470*a90cf9f2SGordon Ross * They're defined as network-order integers for our 471*a90cf9f2SGordon Ross * switch below. We don't have routines to decode 472*a90cf9f2SGordon Ross * native order, so read as char[4] then ntohl. 473*a90cf9f2SGordon Ross * NB: in SMB3, some of these are 8 bytes. 474*a90cf9f2SGordon Ross */ 475*a90cf9f2SGordon Ross if ((top_offset + name_off) < in_mbc->chain_offset) 476*a90cf9f2SGordon Ross break; 477*a90cf9f2SGordon Ross rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc, 478*a90cf9f2SGordon Ross top_offset + name_off, name_len); 479*a90cf9f2SGordon Ross if (rc) 480*a90cf9f2SGordon Ross break; 481*a90cf9f2SGordon Ross rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name); 482*a90cf9f2SGordon Ross if (rc) 483*a90cf9f2SGordon Ross break; 484*a90cf9f2SGordon Ross cc_name.i = ntohl(cc_name.i); 485*a90cf9f2SGordon Ross 486*a90cf9f2SGordon Ross switch (cc_name.i) { 487*a90cf9f2SGordon Ross case SMB2_CREATE_EA_BUFFER: /* ("ExtA") */ 488*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_EA_BUFFER; 489*a90cf9f2SGordon Ross cce = &cc->cc_in_ext_attr; 490*a90cf9f2SGordon Ross break; 491*a90cf9f2SGordon Ross case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 492*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_SD_BUFFER; 493*a90cf9f2SGordon Ross cce = &cc->cc_in_sec_desc; 494*a90cf9f2SGordon Ross break; 495*a90cf9f2SGordon Ross case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */ 496*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_DH_REQUEST; 497*a90cf9f2SGordon Ross cce = &cc->cc_in_dh_request; 498*a90cf9f2SGordon Ross break; 499*a90cf9f2SGordon Ross case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */ 500*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_DH_RECONNECT; 501*a90cf9f2SGordon Ross cce = &cc->cc_in_dh_reconnect; 502*a90cf9f2SGordon Ross break; 503*a90cf9f2SGordon Ross case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 504*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_ALLOCATION_SIZE; 505*a90cf9f2SGordon Ross cce = &cc->cc_in_alloc_size; 506*a90cf9f2SGordon Ross break; 507*a90cf9f2SGordon Ross case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */ 508*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS; 509*a90cf9f2SGordon Ross /* no input data for this */ 510*a90cf9f2SGordon Ross break; 511*a90cf9f2SGordon Ross case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 512*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN; 513*a90cf9f2SGordon Ross cce = &cc->cc_in_time_warp; 514*a90cf9f2SGordon Ross break; 515*a90cf9f2SGordon Ross case SMB2_CREATE_QUERY_ON_DISK_ID: /* ("QFid") */ 516*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID; 517*a90cf9f2SGordon Ross /* no input data for this */ 518*a90cf9f2SGordon Ross break; 519*a90cf9f2SGordon Ross case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */ 520*a90cf9f2SGordon Ross cc->cc_in_flags |= CCTX_REQUEST_LEASE; 521*a90cf9f2SGordon Ross cce = &cc->cc_in_req_lease; 522*a90cf9f2SGordon Ross break; 523*a90cf9f2SGordon Ross default: 524*a90cf9f2SGordon Ross /* 525*a90cf9f2SGordon Ross * Unknown create context values are normal, and 526*a90cf9f2SGordon Ross * should be ignored. However, in debug mode, 527*a90cf9f2SGordon Ross * let's log them so we know which ones we're 528*a90cf9f2SGordon Ross * not handling (and may want to add). 529*a90cf9f2SGordon Ross */ 530*a90cf9f2SGordon Ross #ifdef DEBUG 531*a90cf9f2SGordon Ross cmn_err(CE_NOTE, "unknown create context ID 0x%x", 532*a90cf9f2SGordon Ross cc_name.i); 533*a90cf9f2SGordon Ross #endif 534*a90cf9f2SGordon Ross cce = NULL; 535*a90cf9f2SGordon Ross break; 536*a90cf9f2SGordon Ross } 537*a90cf9f2SGordon Ross 538*a90cf9f2SGordon Ross if (cce != NULL && data_len != 0) { 539*a90cf9f2SGordon Ross if ((data_off & 7) != 0) 540*a90cf9f2SGordon Ross break; 541*a90cf9f2SGordon Ross if ((top_offset + data_off) < in_mbc->chain_offset) 542*a90cf9f2SGordon Ross break; 543*a90cf9f2SGordon Ross rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc, 544*a90cf9f2SGordon Ross top_offset + data_off, data_len); 545*a90cf9f2SGordon Ross if (rc) 546*a90cf9f2SGordon Ross break; 547*a90cf9f2SGordon Ross cce->cce_len = data_len; 548*a90cf9f2SGordon Ross } 549*a90cf9f2SGordon Ross 550*a90cf9f2SGordon Ross if (next_off == 0) { 551*a90cf9f2SGordon Ross /* Normal loop termination */ 552*a90cf9f2SGordon Ross status = 0; 553*a90cf9f2SGordon Ross break; 554*a90cf9f2SGordon Ross } 555*a90cf9f2SGordon Ross 556*a90cf9f2SGordon Ross if ((next_off & 7) != 0) 557*a90cf9f2SGordon Ross break; 558*a90cf9f2SGordon Ross if ((top_offset + next_off) < in_mbc->chain_offset) 559*a90cf9f2SGordon Ross break; 560*a90cf9f2SGordon Ross if ((top_offset + next_off) > in_mbc->max_bytes) 561*a90cf9f2SGordon Ross break; 562*a90cf9f2SGordon Ross in_mbc->chain_offset = top_offset + next_off; 563*a90cf9f2SGordon Ross } 564*a90cf9f2SGordon Ross 565*a90cf9f2SGordon Ross return (status); 566*a90cf9f2SGordon Ross } 567*a90cf9f2SGordon Ross 568*a90cf9f2SGordon Ross /* 569*a90cf9f2SGordon Ross * Encode an SMB2 Create Context buffer from our internal form. 570*a90cf9f2SGordon Ross */ 571*a90cf9f2SGordon Ross /* ARGSUSED */ 572*a90cf9f2SGordon Ross static uint32_t 573*a90cf9f2SGordon Ross smb2_encode_create_ctx(mbuf_chain_t *mbc, smb2_create_ctx_t *cc) 574*a90cf9f2SGordon Ross { 575*a90cf9f2SGordon Ross smb2_create_ctx_elem_t *cce; 576*a90cf9f2SGordon Ross int last_top = -1; 577*a90cf9f2SGordon Ross int rc; 578*a90cf9f2SGordon Ross 579*a90cf9f2SGordon Ross if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 580*a90cf9f2SGordon Ross cce = &cc->cc_out_max_access; 581*a90cf9f2SGordon Ross last_top = mbc->chain_offset; 582*a90cf9f2SGordon Ross rc = smb2_encode_create_ctx_elem(mbc, cce, 583*a90cf9f2SGordon Ross SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ); 584*a90cf9f2SGordon Ross if (rc) 585*a90cf9f2SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 586*a90cf9f2SGordon Ross (void) smb_mbc_poke(mbc, last_top, "l", 587*a90cf9f2SGordon Ross mbc->chain_offset - last_top); 588*a90cf9f2SGordon Ross } 589*a90cf9f2SGordon Ross 590*a90cf9f2SGordon Ross if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 591*a90cf9f2SGordon Ross cce = &cc->cc_out_file_id; 592*a90cf9f2SGordon Ross last_top = mbc->chain_offset; 593*a90cf9f2SGordon Ross rc = smb2_encode_create_ctx_elem(mbc, cce, 594*a90cf9f2SGordon Ross SMB2_CREATE_QUERY_ON_DISK_ID); 595*a90cf9f2SGordon Ross if (rc) 596*a90cf9f2SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 597*a90cf9f2SGordon Ross (void) smb_mbc_poke(mbc, last_top, "l", 598*a90cf9f2SGordon Ross mbc->chain_offset - last_top); 599*a90cf9f2SGordon Ross } 600*a90cf9f2SGordon Ross 601*a90cf9f2SGordon Ross if (last_top >= 0) 602*a90cf9f2SGordon Ross (void) smb_mbc_poke(mbc, last_top, "l", 0); 603*a90cf9f2SGordon Ross 604*a90cf9f2SGordon Ross return (0); 605*a90cf9f2SGordon Ross } 606*a90cf9f2SGordon Ross 607*a90cf9f2SGordon Ross static int 608*a90cf9f2SGordon Ross smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc, 609*a90cf9f2SGordon Ross smb2_create_ctx_elem_t *cce, uint32_t id) 610*a90cf9f2SGordon Ross { 611*a90cf9f2SGordon Ross union { 612*a90cf9f2SGordon Ross uint32_t i; 613*a90cf9f2SGordon Ross char ch[4]; 614*a90cf9f2SGordon Ross } cc_name; 615*a90cf9f2SGordon Ross int rc; 616*a90cf9f2SGordon Ross 617*a90cf9f2SGordon Ross /* as above */ 618*a90cf9f2SGordon Ross cc_name.i = htonl(id); 619*a90cf9f2SGordon Ross 620*a90cf9f2SGordon Ross /* 621*a90cf9f2SGordon Ross * This is the header, per [MS-SMB2] 2.2.13.2 622*a90cf9f2SGordon Ross * Sorry about the fixed offsets. We know we'll 623*a90cf9f2SGordon Ross * layout the data part as [name, payload] and 624*a90cf9f2SGordon Ross * name is a fixed length, so this easy. 625*a90cf9f2SGordon Ross * The final layout looks like this: 626*a90cf9f2SGordon Ross * a: this header (16 bytes) 627*a90cf9f2SGordon Ross * b: the name (4 bytes, 4 pad) 628*a90cf9f2SGordon Ross * c: the payload (variable) 629*a90cf9f2SGordon Ross * 630*a90cf9f2SGordon Ross * Note that "Next elem." is filled in later. 631*a90cf9f2SGordon Ross */ 632*a90cf9f2SGordon Ross rc = smb_mbc_encodef( 633*a90cf9f2SGordon Ross out_mbc, "lwwwwl", 634*a90cf9f2SGordon Ross 0, /* Next offset l */ 635*a90cf9f2SGordon Ross 16, /* NameOffset w */ 636*a90cf9f2SGordon Ross 4, /* NameLength w */ 637*a90cf9f2SGordon Ross 0, /* Reserved w */ 638*a90cf9f2SGordon Ross 24, /* DataOffset w */ 639*a90cf9f2SGordon Ross cce->cce_len); /* l */ 640*a90cf9f2SGordon Ross if (rc) 641*a90cf9f2SGordon Ross return (rc); 642*a90cf9f2SGordon Ross 643*a90cf9f2SGordon Ross /* 644*a90cf9f2SGordon Ross * Now the "name" and payload. 645*a90cf9f2SGordon Ross */ 646*a90cf9f2SGordon Ross rc = smb_mbc_encodef( 647*a90cf9f2SGordon Ross out_mbc, "4c4.#C", 648*a90cf9f2SGordon Ross cc_name.ch, /* 4c4. */ 649*a90cf9f2SGordon Ross cce->cce_len, /* # */ 650*a90cf9f2SGordon Ross &cce->cce_mbc); /* C */ 651*a90cf9f2SGordon Ross 652*a90cf9f2SGordon Ross return (rc); 653*a90cf9f2SGordon Ross } 654*a90cf9f2SGordon Ross 655*a90cf9f2SGordon Ross static void 656*a90cf9f2SGordon Ross smb2_free_create_ctx(smb2_create_ctx_t *cc) 657*a90cf9f2SGordon Ross { 658*a90cf9f2SGordon Ross smb2_create_ctx_elem_t *cce; 659*a90cf9f2SGordon Ross 660*a90cf9f2SGordon Ross if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 661*a90cf9f2SGordon Ross cce = &cc->cc_out_max_access; 662*a90cf9f2SGordon Ross MBC_FLUSH(&cce->cce_mbc); 663*a90cf9f2SGordon Ross } 664*a90cf9f2SGordon Ross if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 665*a90cf9f2SGordon Ross cce = &cc->cc_out_file_id; 666*a90cf9f2SGordon Ross MBC_FLUSH(&cce->cce_mbc); 667*a90cf9f2SGordon Ross } 668*a90cf9f2SGordon Ross } 669