1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_SET_INFO
  18  *
  19  * [MS-FSCC 2.4] If a file system does not support ...
  20  * an Information Classs, NT_STATUS_INVALID_PARAMETER...
  21  */
  22 
  23 #include <smbsrv/smb2_kproto.h>
  24 #include <smbsrv/smb_fsops.h>
  25 #include <smbsrv/ntifs.h>
  26 
  27 static uint32_t smb2_setf_rename(smb_request_t *, smb_setinfo_t *);
  28 static uint32_t smb2_setf_link(smb_request_t *, smb_setinfo_t *);
  29 
  30 static uint32_t smb2_setf_seek(smb_request_t *, smb_setinfo_t *);
  31 static uint32_t smb2_setf_full_ea(smb_request_t *, smb_setinfo_t *);
  32 static uint32_t smb2_setf_mode(smb_request_t *, smb_setinfo_t *);
  33 
  34 static uint32_t smb2_setf_pipe(smb_request_t *, smb_setinfo_t *);
  35 static uint32_t smb2_setf_valid_len(smb_request_t *, smb_setinfo_t *);
  36 static uint32_t smb2_setf_shortname(smb_request_t *, smb_setinfo_t *);
  37 
  38 
  39 uint32_t
  40 smb2_setinfo_file(smb_request_t *sr, smb_setinfo_t *si, int InfoClass)
  41 {
  42         smb_ofile_t *of = sr->fid_ofile;
  43         uint32_t status;
  44 
  45         si->si_node = of->f_node;
  46 
  47         switch (InfoClass) {
  48         case FileBasicInformation:              /* 4 */
  49                 status = smb_set_basic_info(sr, si);
  50                 break;
  51         case FileRenameInformation:             /* 10 */
  52                 status = smb2_setf_rename(sr, si);
  53                 break;
  54         case FileLinkInformation:               /* 11 */
  55                 status = smb2_setf_link(sr, si);
  56                 break;
  57         case FileDispositionInformation:        /* 13 */
  58                 status = smb_set_disposition_info(sr, si);
  59                 break;
  60         case FilePositionInformation:           /* 14 */
  61                 status = smb2_setf_seek(sr, si);
  62                 break;
  63         case FileFullEaInformation:             /* 15 */
  64                 status = smb2_setf_full_ea(sr, si);
  65                 break;
  66         case FileModeInformation:               /* 16 */
  67                 status = smb2_setf_mode(sr, si);
  68                 break;
  69         case FileAllocationInformation:         /* 19 */
  70                 status = smb_set_alloc_info(sr, si);
  71                 break;
  72         case FileEndOfFileInformation:          /* 20 */
  73                 status = smb_set_eof_info(sr, si);
  74                 break;
  75         case FilePipeInformation:               /* 23 */
  76                 status = smb2_setf_pipe(sr, si);
  77                 break;
  78         case FileValidDataLengthInformation:    /* 39 */
  79                 status = smb2_setf_valid_len(sr, si);
  80                 break;
  81         case FileShortNameInformation:          /* 40 */
  82                 status = smb2_setf_shortname(sr, si);
  83                 break;
  84         default:
  85                 status = NT_STATUS_INVALID_INFO_CLASS;
  86                 break;
  87         }
  88 
  89         return (status);
  90 }
  91 
  92 
  93 /*
  94  * FileRenameInformation
  95  * See also: smb_set_rename_info()
  96  */
  97 static uint32_t
  98 smb2_setf_rename(smb_request_t *sr, smb_setinfo_t *si)
  99 {
 100         char *fname;
 101         uint8_t flags;
 102         uint64_t rootdir;
 103         uint32_t namelen;
 104         uint32_t status = 0;
 105         int rc;
 106 
 107         rc = smb_mbc_decodef(&si->si_data, "b7.ql",
 108             &flags, &rootdir, &namelen);
 109         if (rc == 0) {
 110                 rc = smb_mbc_decodef(&si->si_data, "%#U",
 111                     sr, namelen, &fname);
 112         }
 113         if (rc != 0)
 114                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
 115 
 116         if ((rootdir != 0) || (namelen == 0) || (namelen >= SMB_MAXPATHLEN)) {
 117                 return (NT_STATUS_INVALID_PARAMETER);
 118         }
 119 
 120         status = smb_setinfo_rename(sr, si->si_node, fname, flags);
 121 
 122         return (status);
 123 }
 124 
 125 /*
 126  * FileLinkInformation
 127  */
 128 static uint32_t
 129 smb2_setf_link(smb_request_t *sr, smb_setinfo_t *si)
 130 {
 131         char *fname;
 132         uint8_t flags;
 133         uint64_t rootdir;
 134         uint32_t namelen;
 135         uint32_t status = 0;
 136         int rc;
 137 
 138         rc = smb_mbc_decodef(&si->si_data, "b7.ql",
 139             &flags, &rootdir, &namelen);
 140         if (rc == 0) {
 141                 rc = smb_mbc_decodef(&si->si_data, "%#U",
 142                     sr, namelen, &fname);
 143         }
 144         if (rc != 0)
 145                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
 146 
 147         if ((rootdir != 0) || (namelen == 0) || (namelen >= SMB_MAXPATHLEN)) {
 148                 return (NT_STATUS_INVALID_PARAMETER);
 149         }
 150 
 151         status = smb_setinfo_link(sr, si->si_node, fname, flags);
 152 
 153         return (status);
 154 }
 155 
 156 
 157 /*
 158  * FilePositionInformation
 159  */
 160 static uint32_t
 161 smb2_setf_seek(smb_request_t *sr, smb_setinfo_t *si)
 162 {
 163         smb_ofile_t *of = sr->fid_ofile;
 164         uint64_t newoff;
 165 
 166         if (smb_mbc_decodef(&si->si_data, "q", &newoff) != 0)
 167                 return (NT_STATUS_INVALID_PARAMETER);
 168 
 169         ASSERT(of->f_magic == SMB_OFILE_MAGIC);
 170         mutex_enter(&of->f_mutex);
 171         of->f_seek_pos = newoff;
 172         mutex_exit(&of->f_mutex);
 173 
 174         return (0);
 175 }
 176 
 177 /*
 178  * FileFullEaInformation
 179  * We could put EAs in a named stream...
 180  */
 181 /* ARGSUSED */
 182 static uint32_t
 183 smb2_setf_full_ea(smb_request_t *sr, smb_setinfo_t *si)
 184 {
 185         return (NT_STATUS_EAS_NOT_SUPPORTED);
 186 }
 187 
 188 /*
 189  * FileModeInformation [MS-FSCC 2.4.24]
 190  *      FILE_WRITE_THROUGH
 191  *      FILE_SEQUENTIAL_ONLY
 192  *      FILE_NO_INTERMEDIATE_BUFFERING
 193  *      etc.
 194  */
 195 static uint32_t
 196 smb2_setf_mode(smb_request_t *sr, smb_setinfo_t *si)
 197 {
 198         _NOTE(ARGUNUSED(sr))
 199         uint32_t        Mode;
 200 
 201         if (smb_mbc_decodef(&si->si_data, "l", &Mode) != 0)
 202                 return (NT_STATUS_INVALID_PARAMETER);
 203 
 204 #if 0   /* XXX - todo */
 205         if (Mode & FILE_WRITE_THROUGH) {
 206                 /* store this in the ofile */
 207         }
 208 #endif
 209 
 210         return (NT_STATUS_SUCCESS);
 211 }
 212 
 213 
 214 
 215 /*
 216  * FilePipeInformation
 217  */
 218 static uint32_t
 219 smb2_setf_pipe(smb_request_t *sr, smb_setinfo_t *si)
 220 {
 221         _NOTE(ARGUNUSED(si))
 222         smb_ofile_t *of = sr->fid_ofile;
 223         uint32_t        ReadMode;
 224         uint32_t        CompletionMode;
 225         uint32_t        status;
 226 
 227         if (smb_mbc_decodef(&si->si_data, "ll",
 228             &ReadMode, &CompletionMode) != 0)
 229                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
 230 
 231         switch (of->f_ftype) {
 232         case SMB_FTYPE_BYTE_PIPE:
 233         case SMB_FTYPE_MESG_PIPE:
 234                 /*
 235                  * XXX: Do we need to actually do anything with
 236                  * ReadMode or CompletionMode?  If so, (later)
 237                  * store these in the opipe object.
 238                  *
 239                  * See also: smb2_sif_pipe()
 240                  */
 241                 status = 0;
 242                 break;
 243         case SMB_FTYPE_DISK:
 244         case SMB_FTYPE_PRINTER:
 245         default:
 246                 status = NT_STATUS_INVALID_PARAMETER;
 247         }
 248 
 249         return (status);
 250 }
 251 
 252 /*
 253  * FileValidDataLengthInformation
 254  */
 255 /* ARGSUSED */
 256 static uint32_t
 257 smb2_setf_valid_len(smb_request_t *sr, smb_setinfo_t *si)
 258 {
 259         smb_ofile_t *of = sr->fid_ofile;
 260         uint64_t eod;
 261         int rc;
 262 
 263         if (smb_mbc_decodef(&si->si_data, "q", &eod) != 0)
 264                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
 265 
 266         rc = smb_fsop_set_data_length(sr, of->f_cr, of->f_node, eod);
 267         if (rc != 0)
 268                 return (smb_errno2status(rc));
 269 
 270         return (0);
 271 }
 272 
 273 /*
 274  * FileShortNameInformation
 275  *      We can (optionally) support supply short names,
 276  *      but you can't change them.
 277  */
 278 static uint32_t
 279 smb2_setf_shortname(smb_request_t *sr, smb_setinfo_t *si)
 280 {
 281         _NOTE(ARGUNUSED(si))
 282         smb_ofile_t *of = sr->fid_ofile;
 283 
 284         if (of->f_ftype != SMB_FTYPE_DISK)
 285                 return (NT_STATUS_INVALID_PARAMETER);
 286         if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
 287                 return (NT_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME);
 288 
 289         return (NT_STATUS_ACCESS_DENIED);
 290 }