Home | History | Annotate | Download | only in smbsrv
      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 
     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, &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			OplockLevel;
    144 	uint8_t			DirFlag;
    145 	smb_attr_t		attr;
    146 	smb_node_t		*node;
    147 	uint32_t status;
    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->tid_tree,
    178 		    (uint16_t)op->rootdirfid);
    179 		if (op->dir == NULL) {
    180 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
    181 			    ERRDOS, ERRbadfid);
    182 			return (SDRC_ERROR);
    183 		}
    184 		op->fqi.fq_dnode = op->dir->f_node;
    185 	}
    186 
    187 	status = smb_common_open(sr);
    188 
    189 	if (status != NT_STATUS_SUCCESS)
    190 		return (SDRC_ERROR);
    191 
    192 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
    193 		switch (op->op_oplock_level) {
    194 		case SMB_OPLOCK_EXCLUSIVE:
    195 			OplockLevel = 1;
    196 			break;
    197 		case SMB_OPLOCK_BATCH:
    198 			OplockLevel = 2;
    199 			break;
    200 		case SMB_OPLOCK_LEVEL_II:
    201 			OplockLevel = 3;
    202 			break;
    203 		case SMB_OPLOCK_NONE:
    204 		default:
    205 			OplockLevel = 0;
    206 			break;
    207 		}
    208 
    209 		if (op->create_options & FILE_DELETE_ON_CLOSE)
    210 			smb_ofile_set_delete_on_close(sr->fid_ofile);
    211 
    212 		node = sr->fid_ofile->f_node;
    213 		DirFlag = smb_node_is_dir(node) ? 1 : 0;
    214 		if (smb_node_getattr(sr, node, &attr) != 0) {
    215 			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
    216 			    ERRDOS, ERROR_INTERNAL_ERROR);
    217 			return (SDRC_ERROR);
    218 		}
    219 
    220 		(void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
    221 		    OplockLevel,
    222 		    sr->smb_fid,
    223 		    op->action_taken,
    224 		    0,	/* EaErrorOffset */
    225 		    &attr.sa_crtime,
    226 		    &attr.sa_vattr.va_atime,
    227 		    &attr.sa_vattr.va_mtime,
    228 		    &attr.sa_vattr.va_ctime,
    229 		    op->dattr & FILE_ATTRIBUTE_MASK,
    230 		    attr.sa_allocsz,
    231 		    attr.sa_vattr.va_size,
    232 		    op->ftype,
    233 		    op->devstate,
    234 		    DirFlag);
    235 	} else {
    236 		/* Named PIPE */
    237 		bzero(&attr, sizeof (smb_attr_t));
    238 		(void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
    239 		    0,
    240 		    sr->smb_fid,
    241 		    op->action_taken,
    242 		    0,	/* EaErrorOffset */
    243 		    &attr.sa_crtime,
    244 		    &attr.sa_vattr.va_atime,
    245 		    &attr.sa_vattr.va_mtime,
    246 		    &attr.sa_vattr.va_ctime,
    247 		    op->dattr,
    248 		    0x1000LL,
    249 		    0LL,
    250 		    op->ftype,
    251 		    op->devstate,
    252 		    0);
    253 	}
    254 
    255 	return (SDRC_SUCCESS);
    256 }
    257