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 2017 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Trans2 Set File/Path Information Levels: 28 * 29 * SMB_INFO_STANDARD 30 * SMB_INFO_SET_EAS 31 * SMB_SET_FILE_BASIC_INFO 32 * SMB_SET_FILE_DISPOSITION_INFO 33 * SMB_SET_FILE_END_OF_FILE_INFO 34 * SMB_SET_FILE_ALLOCATION_INFO 35 * 36 * Handled Passthrough levels: 37 * SMB_FILE_BASIC_INFORMATION 38 * SMB_FILE_RENAME_INFORMATION 39 * SMB_FILE_LINK_INFORMATION 40 * SMB_FILE_DISPOSITION_INFORMATION 41 * SMB_FILE_END_OF_FILE_INFORMATION 42 * SMB_FILE_ALLOCATION_INFORMATION 43 * 44 * Internal levels representing non trans2 requests 45 * SMB_SET_INFORMATION 46 * SMB_SET_INFORMATION2 47 */ 48 49 /* 50 * Setting timestamps: 51 * The behaviour when the time field is set to -1 is not documented 52 * but is generally treated like 0, meaning that that server file 53 * system assigned value need not be changed. 54 * 55 * Setting attributes - FILE_ATTRIBUTE_NORMAL: 56 * SMB_SET_INFORMATION - 57 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 58 * do NOT change the file's attributes. 59 * SMB_SET_BASIC_INFO - 60 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 61 * clear (0) the file's attributes. 62 * - if the specified attributes are 0 do NOT change the file's 63 * attributes. 64 */ 65 66 #include <smbsrv/smb_kproto.h> 67 #include <smbsrv/smb_fsops.h> 68 69 static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t); 70 static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t); 71 72 /* 73 * These functions all return and NT status code. 74 */ 75 static uint32_t smb_set_fileinfo(smb_request_t *, smb_setinfo_t *, int); 76 static uint32_t smb_set_information(smb_request_t *, smb_setinfo_t *); 77 static uint32_t smb_set_information2(smb_request_t *, smb_setinfo_t *); 78 static uint32_t smb_set_standard_info(smb_request_t *, smb_setinfo_t *); 79 static uint32_t smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *); 80 81 /* 82 * smb_com_trans2_set_file_information 83 */ 84 smb_sdrc_t 85 smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa) 86 { 87 uint16_t infolev; 88 89 if (smb_mbc_decodef(&xa->req_param_mb, "ww", 90 &sr->smb_fid, &infolev) != 0) 91 return (SDRC_ERROR); 92 93 if (smb_set_by_fid(sr, xa, infolev) != 0) 94 return (SDRC_ERROR); 95 96 return (SDRC_SUCCESS); 97 } 98 99 /* 100 * smb_com_trans2_set_path_information 101 */ 102 smb_sdrc_t 103 smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa) 104 { 105 uint16_t infolev; 106 smb_fqi_t *fqi = &sr->arg.dirop.fqi; 107 108 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 109 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, 110 ERRDOS, ERROR_INVALID_FUNCTION); 111 return (SDRC_ERROR); 112 } 113 114 if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", 115 sr, &infolev, &fqi->fq_path.pn_path) != 0) 116 return (SDRC_ERROR); 117 118 if (smb_set_by_path(sr, xa, infolev) != 0) 119 return (SDRC_ERROR); 120 121 return (SDRC_SUCCESS); 122 } 123 124 /* 125 * smb_com_set_information (aka setattr) 126 */ 127 smb_sdrc_t 128 smb_pre_set_information(smb_request_t *sr) 129 { 130 DTRACE_SMB_START(op__SetInformation, smb_request_t *, sr); 131 return (SDRC_SUCCESS); 132 } 133 134 void 135 smb_post_set_information(smb_request_t *sr) 136 { 137 DTRACE_SMB_DONE(op__SetInformation, smb_request_t *, sr); 138 } 139 140 smb_sdrc_t 141 smb_com_set_information(smb_request_t *sr) 142 { 143 uint16_t infolev = SMB_SET_INFORMATION; 144 smb_fqi_t *fqi = &sr->arg.dirop.fqi; 145 146 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 147 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 148 ERRDOS, ERROR_ACCESS_DENIED); 149 return (SDRC_ERROR); 150 } 151 152 if (smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path) != 0) 153 return (SDRC_ERROR); 154 155 if (smb_set_by_path(sr, NULL, infolev) != 0) 156 return (SDRC_ERROR); 157 158 if (smbsr_encode_empty_result(sr) != 0) 159 return (SDRC_ERROR); 160 161 return (SDRC_SUCCESS); 162 } 163 164 /* 165 * smb_com_set_information2 (aka setattre) 166 */ 167 smb_sdrc_t 168 smb_pre_set_information2(smb_request_t *sr) 169 { 170 DTRACE_SMB_START(op__SetInformation2, smb_request_t *, sr); 171 return (SDRC_SUCCESS); 172 } 173 174 void 175 smb_post_set_information2(smb_request_t *sr) 176 { 177 DTRACE_SMB_DONE(op__SetInformation2, smb_request_t *, sr); 178 } 179 180 smb_sdrc_t 181 smb_com_set_information2(smb_request_t *sr) 182 { 183 uint16_t infolev = SMB_SET_INFORMATION2; 184 185 if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0) 186 return (SDRC_ERROR); 187 188 if (smb_set_by_fid(sr, NULL, infolev) != 0) 189 return (SDRC_ERROR); 190 191 if (smbsr_encode_empty_result(sr) != 0) 192 return (SDRC_ERROR); 193 194 return (SDRC_SUCCESS); 195 } 196 197 /* 198 * smb_set_by_fid 199 * 200 * Common code for setting file information by open file id. 201 * Use the id to identify the node object and invoke smb_set_fileinfo 202 * for that node. 203 * 204 * Setting attributes on a named pipe by id is handled by simply 205 * returning success. 206 */ 207 static int 208 smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) 209 { 210 smb_setinfo_t sinfo; 211 uint32_t status; 212 int rc = 0; 213 214 if (SMB_TREE_IS_READONLY(sr)) { 215 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 216 ERRDOS, ERROR_ACCESS_DENIED); 217 return (-1); 218 } 219 220 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) 221 return (0); 222 223 smbsr_lookup_file(sr); 224 if (sr->fid_ofile == NULL) { 225 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 226 return (-1); 227 } 228 229 if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) { 230 smbsr_release_file(sr); 231 return (0); 232 } 233 234 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 235 236 bzero(&sinfo, sizeof (sinfo)); 237 sinfo.si_node = sr->fid_ofile->f_node; 238 if (xa != NULL) 239 sinfo.si_data = xa->req_data_mb; 240 status = smb_set_fileinfo(sr, &sinfo, infolev); 241 if (status != 0) { 242 smbsr_error(sr, status, 0, 0); 243 rc = -1; 244 } 245 246 smbsr_release_file(sr); 247 return (rc); 248 } 249 250 /* 251 * smb_set_by_path 252 * 253 * Common code for setting file information by file name. 254 * Use the file name to identify the node object and invoke 255 * smb_set_fileinfo for that node. 256 * 257 * Path should be set in sr->arg.dirop.fqi.fq_path prior to 258 * calling smb_set_by_path. 259 * 260 * Setting attributes on a named pipe by name is an error and 261 * is handled in the calling functions so that they can return 262 * the appropriate error status code (which differs by caller). 263 */ 264 static int 265 smb_set_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) 266 { 267 int rc; 268 uint32_t status; 269 smb_setinfo_t sinfo; 270 smb_node_t *node, *dnode; 271 char *name; 272 smb_pathname_t *pn; 273 274 if (SMB_TREE_IS_READONLY(sr)) { 275 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 276 ERRDOS, ERROR_ACCESS_DENIED); 277 return (-1); 278 } 279 280 pn = &sr->arg.dirop.fqi.fq_path; 281 smb_pathname_init(sr, pn, pn->pn_path); 282 if (!smb_pathname_validate(sr, pn)) 283 return (-1); 284 285 name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 286 rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path, 287 sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name); 288 if (rc == 0) { 289 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS, 290 sr->tid_tree->t_snode, dnode, name, &node); 291 smb_node_release(dnode); 292 } 293 kmem_free(name, MAXNAMELEN); 294 295 if (rc != 0) { 296 smbsr_errno(sr, rc); 297 return (-1); 298 } 299 300 bzero(&sinfo, sizeof (sinfo)); 301 sinfo.si_node = node; 302 if (xa != NULL) 303 sinfo.si_data = xa->req_data_mb; 304 status = smb_set_fileinfo(sr, &sinfo, infolev); 305 if (status != 0) { 306 smbsr_error(sr, status, 0, 0); 307 rc = -1; 308 } 309 310 smb_node_release(node); 311 return (rc); 312 } 313 314 /* 315 * smb_set_fileinfo 316 * 317 * For compatibility with windows servers, SMB_FILE_LINK_INFORMATION 318 * is handled by returning NT_STATUS_NOT_SUPPORTED. 319 */ 320 static uint32_t 321 smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo, int infolev) 322 { 323 uint32_t status; 324 325 switch (infolev) { 326 case SMB_SET_INFORMATION: 327 status = smb_set_information(sr, sinfo); 328 break; 329 330 case SMB_SET_INFORMATION2: 331 status = smb_set_information2(sr, sinfo); 332 break; 333 334 case SMB_INFO_STANDARD: 335 status = smb_set_standard_info(sr, sinfo); 336 break; 337 338 case SMB_INFO_SET_EAS: 339 status = NT_STATUS_EAS_NOT_SUPPORTED; 340 break; 341 342 case SMB_SET_FILE_BASIC_INFO: 343 case SMB_FILE_BASIC_INFORMATION: 344 status = smb_set_basic_info(sr, sinfo); 345 break; 346 347 case SMB_SET_FILE_DISPOSITION_INFO: 348 case SMB_FILE_DISPOSITION_INFORMATION: 349 status = smb_set_disposition_info(sr, sinfo); 350 break; 351 352 case SMB_SET_FILE_END_OF_FILE_INFO: 353 case SMB_FILE_END_OF_FILE_INFORMATION: 354 status = smb_set_eof_info(sr, sinfo); 355 break; 356 357 case SMB_SET_FILE_ALLOCATION_INFO: 358 case SMB_FILE_ALLOCATION_INFORMATION: 359 status = smb_set_alloc_info(sr, sinfo); 360 break; 361 362 case SMB_FILE_RENAME_INFORMATION: 363 status = smb_set_rename_info(sr, sinfo); 364 break; 365 366 case SMB_FILE_LINK_INFORMATION: 367 status = NT_STATUS_NOT_SUPPORTED; 368 break; 369 370 default: 371 status = NT_STATUS_INVALID_INFO_CLASS; 372 break; 373 } 374 375 return (status); 376 } 377 378 /* 379 * smb_set_information 380 * 381 * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the 382 * target is not a directory. 383 * 384 * For compatibility with Windows Servers, if the specified 385 * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change 386 * the file's attributes. 387 */ 388 static uint32_t 389 smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo) 390 { 391 smb_attr_t attr; 392 smb_node_t *node = sinfo->si_node; 393 uint32_t status = 0; 394 uint32_t mtime; 395 uint16_t attributes; 396 int rc; 397 398 if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0) 399 return (NT_STATUS_INFO_LENGTH_MISMATCH); 400 401 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) && 402 (!smb_node_is_dir(node))) { 403 return (NT_STATUS_INVALID_PARAMETER); 404 } 405 406 bzero(&attr, sizeof (smb_attr_t)); 407 if (attributes != FILE_ATTRIBUTE_NORMAL) { 408 attr.sa_dosattr = attributes; 409 attr.sa_mask |= SMB_AT_DOSATTR; 410 } 411 412 if (mtime != 0 && mtime != UINT_MAX) { 413 attr.sa_vattr.va_mtime.tv_sec = 414 smb_time_local_to_gmt(sr, mtime); 415 attr.sa_mask |= SMB_AT_MTIME; 416 } 417 418 rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr); 419 if (rc != 0) 420 status = smb_errno2status(rc); 421 422 return (status); 423 } 424 425 /* 426 * smb_set_information2 427 */ 428 static uint32_t 429 smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo) 430 { 431 smb_attr_t attr; 432 uint32_t crtime, atime, mtime; 433 uint32_t status = 0; 434 int rc; 435 436 if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0) 437 return (NT_STATUS_INFO_LENGTH_MISMATCH); 438 439 bzero(&attr, sizeof (smb_attr_t)); 440 if (mtime != 0 && mtime != UINT_MAX) { 441 attr.sa_vattr.va_mtime.tv_sec = 442 smb_time_local_to_gmt(sr, mtime); 443 attr.sa_mask |= SMB_AT_MTIME; 444 } 445 446 if (crtime != 0 && crtime != UINT_MAX) { 447 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime); 448 attr.sa_mask |= SMB_AT_CRTIME; 449 } 450 451 if (atime != 0 && atime != UINT_MAX) { 452 attr.sa_vattr.va_atime.tv_sec = 453 smb_time_local_to_gmt(sr, atime); 454 attr.sa_mask |= SMB_AT_ATIME; 455 } 456 457 rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr, 458 sr->fid_ofile, &attr); 459 if (rc != 0) 460 status = smb_errno2status(rc); 461 462 return (status); 463 } 464 465 /* 466 * smb_set_standard_info 467 * 468 * Sets standard file/path information. 469 */ 470 static uint32_t 471 smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo) 472 { 473 smb_attr_t attr; 474 smb_node_t *node = sinfo->si_node; 475 uint32_t crtime, atime, mtime; 476 uint32_t status = 0; 477 int rc; 478 479 if (smb_mbc_decodef(&sinfo->si_data, "yyy", 480 &crtime, &atime, &mtime) != 0) 481 return (NT_STATUS_INFO_LENGTH_MISMATCH); 482 483 bzero(&attr, sizeof (smb_attr_t)); 484 if (mtime != 0 && mtime != (uint32_t)-1) { 485 attr.sa_vattr.va_mtime.tv_sec = 486 smb_time_local_to_gmt(sr, mtime); 487 attr.sa_mask |= SMB_AT_MTIME; 488 } 489 490 if (crtime != 0 && crtime != (uint32_t)-1) { 491 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime); 492 attr.sa_mask |= SMB_AT_CRTIME; 493 } 494 495 if (atime != 0 && atime != (uint32_t)-1) { 496 attr.sa_vattr.va_atime.tv_sec = 497 smb_time_local_to_gmt(sr, atime); 498 attr.sa_mask |= SMB_AT_ATIME; 499 } 500 501 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 502 if (rc != 0) 503 status = smb_errno2status(rc); 504 505 return (status); 506 } 507 508 /* 509 * smb_set_rename_info 510 * 511 * This call only allows a rename in the same directory, and the 512 * directory name is not part of the new name provided. 513 * 514 * Explicitly specified parameter validation rules: 515 * - If rootdir is not NULL respond with NT_STATUS_INVALID_PARAMETER. 516 * - If the filename contains a separator character respond with 517 * NT_STATUS_INVALID_PARAMETER. 518 * 519 * Oplock break: 520 * Some Windows servers break BATCH oplocks prior to the rename. 521 * W2K3 does not. We behave as W2K3; we do not send an oplock break. 522 */ 523 static uint32_t 524 smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *sinfo) 525 { 526 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 527 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 528 char *fname; 529 char *path; 530 uint8_t flags; 531 uint32_t rootdir, namelen; 532 uint32_t status = 0; 533 int rc; 534 535 rc = smb_mbc_decodef(&sinfo->si_data, "b...ll", 536 &flags, &rootdir, &namelen); 537 if (rc == 0) { 538 rc = smb_mbc_decodef(&sinfo->si_data, "%#U", 539 sr, namelen, &fname); 540 } 541 if (rc != 0) 542 return (NT_STATUS_INFO_LENGTH_MISMATCH); 543 544 if ((rootdir != 0) || (namelen == 0) || (namelen >= MAXNAMELEN)) { 545 return (NT_STATUS_INVALID_PARAMETER); 546 } 547 548 if (strchr(fname, '\\') != NULL) { 549 return (NT_STATUS_NOT_SUPPORTED); 550 } 551 552 /* 553 * Construct the full dst. path relative to the share root. 554 * Allocated path is free'd in smb_request_free. 555 */ 556 path = smb_srm_zalloc(sr, SMB_MAXPATHLEN); 557 if (src_fqi->fq_path.pn_pname) { 558 /* Got here via: smb_set_by_path */ 559 (void) snprintf(path, SMB_MAXPATHLEN, "%s\\%s", 560 src_fqi->fq_path.pn_pname, fname); 561 } else { 562 /* Got here via: smb_set_by_fid */ 563 rc = smb_node_getshrpath(sinfo->si_node->n_dnode, 564 sr->tid_tree, path, SMB_MAXPATHLEN); 565 if (rc != 0) { 566 status = smb_errno2status(rc); 567 return (status); 568 } 569 (void) strlcat(path, "\\", SMB_MAXPATHLEN); 570 (void) strlcat(path, fname, SMB_MAXPATHLEN); 571 } 572 573 /* 574 * The common rename code can slightly optimize a 575 * rename in the same directory when we set the 576 * dst_fqi->fq_dnode, dst_fqi->fq_last_comp 577 */ 578 dst_fqi->fq_dnode = sinfo->si_node->n_dnode; 579 (void) strlcpy(dst_fqi->fq_last_comp, fname, MAXNAMELEN); 580 581 status = smb_setinfo_rename(sr, sinfo->si_node, path, flags); 582 return (status); 583 } 584