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