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 2016 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 #include <smbsrv/smb_kproto.h>
  27 
  28 #define SMB_CREATE_NAMEBUF_SZ   16
  29 
  30 /*
  31  * Create a new file, or truncate an existing file to zero length,
  32  * open the file and return a fid.  The file is specified using a
  33  * fully qualified name relative to the tree.
  34  */
  35 smb_sdrc_t
  36 smb_pre_create(smb_request_t *sr)
  37 {
  38         struct open_param *op = &sr->arg.open;
  39         int rc;
  40 
  41         bzero(op, sizeof (sr->arg.open));
  42 
  43         rc = smbsr_decode_vwv(sr, "wl", &op->dattr, &op->mtime.tv_sec);
  44         if (rc == 0)
  45                 rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path);
  46 
  47         op->create_disposition = FILE_OVERWRITE_IF;
  48         op->create_options = FILE_NON_DIRECTORY_FILE;
  49 
  50         DTRACE_SMB_2(op__Create__start, smb_request_t *, sr,
  51             struct open_param *, op);
  52 
  53         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  54 }
  55 
  56 void
  57 smb_post_create(smb_request_t *sr)
  58 {
  59         DTRACE_SMB_1(op__Create__done, smb_request_t *, sr);
  60 }
  61 
  62 smb_sdrc_t
  63 smb_com_create(smb_request_t *sr)
  64 {
  65         if (smb_common_create(sr) != NT_STATUS_SUCCESS)
  66                 return (SDRC_ERROR);
  67 
  68         if (smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0))
  69                 return (SDRC_ERROR);
  70 
  71         return (SDRC_SUCCESS);
  72 }
  73 
  74 /*
  75  * Create a new file and return a fid.  The file is specified using
  76  * a fully qualified name relative to the tree.
  77  */
  78 smb_sdrc_t
  79 smb_pre_create_new(smb_request_t *sr)
  80 {
  81         struct open_param *op = &sr->arg.open;
  82         int rc;
  83 
  84         bzero(op, sizeof (sr->arg.open));
  85 
  86         rc = smbsr_decode_vwv(sr, "wl", &op->dattr, &op->mtime.tv_sec);
  87         if (rc == 0)
  88                 rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path);
  89 
  90         op->create_disposition = FILE_CREATE;
  91 
  92         DTRACE_SMB_2(op__CreateNew__start, smb_request_t *, sr,
  93             struct open_param *, op);
  94 
  95         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  96 }
  97 
  98 void
  99 smb_post_create_new(smb_request_t *sr)
 100 {
 101         DTRACE_SMB_1(op__CreateNew__done, smb_request_t *, sr);
 102 }
 103 
 104 smb_sdrc_t
 105 smb_com_create_new(smb_request_t *sr)
 106 {
 107         if (smb_common_create(sr) != NT_STATUS_SUCCESS)
 108                 return (SDRC_ERROR);
 109 
 110         if (smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0))
 111                 return (SDRC_ERROR);
 112 
 113         return (SDRC_SUCCESS);
 114 }
 115 
 116 /*
 117  * Create a unique file in the specified directory relative to the
 118  * current tree.  No attributes are specified.
 119  */
 120 smb_sdrc_t
 121 smb_pre_create_temporary(smb_request_t *sr)
 122 {
 123         struct open_param *op = &sr->arg.open;
 124         uint16_t reserved;
 125         int rc;
 126 
 127         bzero(op, sizeof (sr->arg.open));
 128 
 129         rc = smbsr_decode_vwv(sr, "wl", &reserved, &op->mtime.tv_sec);
 130         if (rc == 0)
 131                 rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path);
 132 
 133         op->create_disposition = FILE_CREATE;
 134 
 135         DTRACE_SMB_2(op__CreateTemporary__start, smb_request_t *, sr,
 136             struct open_param *, op);
 137 
 138         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 139 }
 140 
 141 void
 142 smb_post_create_temporary(smb_request_t *sr)
 143 {
 144         DTRACE_SMB_1(op__CreateTemporary__done, smb_request_t *, sr);
 145 }
 146 
 147 smb_sdrc_t
 148 smb_com_create_temporary(smb_request_t *sr)
 149 {
 150         static uint16_t tmp_id = 10000;
 151         struct open_param *op = &sr->arg.open;
 152         char name[SMB_CREATE_NAMEBUF_SZ];
 153         char *buf;
 154         uint16_t bcc;
 155 
 156         ++tmp_id;
 157         bcc = 1; /* null terminator */
 158         bcc += snprintf(name, SMB_CREATE_NAMEBUF_SZ, "tt%05d.tmp", tmp_id);
 159 
 160         buf = smb_srm_zalloc(sr, MAXPATHLEN);
 161         (void) snprintf(buf, MAXPATHLEN, "%s\\%s",
 162             op->fqi.fq_path.pn_path, name);
 163         op->fqi.fq_path.pn_path = buf;
 164 
 165         if (smb_common_create(sr) != NT_STATUS_SUCCESS)
 166                 return (SDRC_ERROR);
 167 
 168         if (smbsr_encode_result(sr, 1, VAR_BCC, "bww%s", 1, sr->smb_fid,
 169             VAR_BCC, sr, name))
 170                 return (SDRC_ERROR);
 171 
 172         return (SDRC_SUCCESS);
 173 }
 174 
 175 /*
 176  * Common create file function.  The file is opened in compatibility
 177  * mode with read/write access.
 178  */
 179 uint32_t
 180 smb_common_create(smb_request_t *sr)
 181 {
 182         struct open_param *op = &sr->arg.open;
 183         uint32_t status;
 184 
 185         if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX))
 186                 op->mtime.tv_sec = smb_time_local_to_gmt(sr, op->mtime.tv_sec);
 187         op->mtime.tv_nsec = 0;
 188         op->dsize = 0;
 189         op->omode = SMB_DA_ACCESS_READ_WRITE | SMB_DA_SHARE_COMPATIBILITY;
 190         op->desired_access = smb_omode_to_amask(op->omode);
 191         op->share_access = smb_denymode_to_sharemode(op->omode,
 192             op->fqi.fq_path.pn_path);
 193 
 194         if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
 195                 if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
 196                         op->op_oplock_level = SMB_OPLOCK_BATCH;
 197                 else
 198                         op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
 199         } else {
 200                 op->op_oplock_level = SMB_OPLOCK_NONE;
 201         }
 202         op->op_oplock_levelII = B_FALSE;
 203 
 204         status = smb_common_open(sr);
 205 
 206         if (op->op_oplock_level == SMB_OPLOCK_NONE) {
 207                 sr->smb_flg &=
 208                     ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
 209         }
 210 
 211         if (status)
 212                 smbsr_status(sr, status, 0, 0);
 213 
 214         return (status);
 215 }