8992 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>4 * Copyright (C) 2018 Samsung Electronics Co., Ltd.5 */6 7#include <linux/inetdevice.h>8#include <net/addrconf.h>9#include <linux/syscalls.h>10#include <linux/namei.h>11#include <linux/statfs.h>12#include <linux/ethtool.h>13#include <linux/falloc.h>14#include <linux/mount.h>15#include <linux/filelock.h>16 17#include "glob.h"18#include "smbfsctl.h"19#include "oplock.h"20#include "smbacl.h"21 22#include "auth.h"23#include "asn1.h"24#include "connection.h"25#include "transport_ipc.h"26#include "transport_rdma.h"27#include "vfs.h"28#include "vfs_cache.h"29#include "misc.h"30 31#include "server.h"32#include "smb_common.h"33#include "../common/smb2status.h"34#include "ksmbd_work.h"35#include "mgmt/user_config.h"36#include "mgmt/share_config.h"37#include "mgmt/tree_connect.h"38#include "mgmt/user_session.h"39#include "mgmt/ksmbd_ida.h"40#include "ndr.h"41 42static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)43{44 if (work->next_smb2_rcv_hdr_off) {45 *req = ksmbd_req_buf_next(work);46 *rsp = ksmbd_resp_buf_next(work);47 } else {48 *req = smb2_get_msg(work->request_buf);49 *rsp = smb2_get_msg(work->response_buf);50 }51}52 53#define WORK_BUFFERS(w, rq, rs) __wbuf((w), (void **)&(rq), (void **)&(rs))54 55/**56 * check_session_id() - check for valid session id in smb header57 * @conn: connection instance58 * @id: session id from smb header59 *60 * Return: 1 if valid session id, otherwise 061 */62static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)63{64 struct ksmbd_session *sess;65 66 if (id == 0 || id == -1)67 return false;68 69 sess = ksmbd_session_lookup_all(conn, id);70 if (sess)71 return true;72 pr_err("Invalid user session id: %llu\n", id);73 return false;74}75 76struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)77{78 return xa_load(&sess->ksmbd_chann_list, (long)conn);79}80 81/**82 * smb2_get_ksmbd_tcon() - get tree connection information using a tree id.83 * @work: smb work84 *85 * Return: 0 if there is a tree connection matched or these are86 * skipable commands, otherwise error87 */88int smb2_get_ksmbd_tcon(struct ksmbd_work *work)89{90 struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work);91 unsigned int cmd = le16_to_cpu(req_hdr->Command);92 unsigned int tree_id;93 94 if (cmd == SMB2_TREE_CONNECT_HE ||95 cmd == SMB2_CANCEL_HE ||96 cmd == SMB2_LOGOFF_HE) {97 ksmbd_debug(SMB, "skip to check tree connect request\n");98 return 0;99 }100 101 if (xa_empty(&work->sess->tree_conns)) {102 ksmbd_debug(SMB, "NO tree connected\n");103 return -ENOENT;104 }105 106 tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId);107 108 /*109 * If request is not the first in Compound request,110 * Just validate tree id in header with work->tcon->id.111 */112 if (work->next_smb2_rcv_hdr_off) {113 if (!work->tcon) {114 pr_err("The first operation in the compound does not have tcon\n");115 return -EINVAL;116 }117 if (tree_id != UINT_MAX && work->tcon->id != tree_id) {118 pr_err("tree id(%u) is different with id(%u) in first operation\n",119 tree_id, work->tcon->id);120 return -EINVAL;121 }122 return 1;123 }124 125 work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id);126 if (!work->tcon) {127 pr_err("Invalid tid %d\n", tree_id);128 return -ENOENT;129 }130 131 return 1;132}133 134/**135 * smb2_set_err_rsp() - set error response code on smb response136 * @work: smb work containing response buffer137 */138void smb2_set_err_rsp(struct ksmbd_work *work)139{140 struct smb2_err_rsp *err_rsp;141 142 if (work->next_smb2_rcv_hdr_off)143 err_rsp = ksmbd_resp_buf_next(work);144 else145 err_rsp = smb2_get_msg(work->response_buf);146 147 if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) {148 int err;149 150 err_rsp->StructureSize = SMB2_ERROR_STRUCTURE_SIZE2_LE;151 err_rsp->ErrorContextCount = 0;152 err_rsp->Reserved = 0;153 err_rsp->ByteCount = 0;154 err_rsp->ErrorData[0] = 0;155 err = ksmbd_iov_pin_rsp(work, (void *)err_rsp,156 __SMB2_HEADER_STRUCTURE_SIZE +157 SMB2_ERROR_STRUCTURE_SIZE2);158 if (err)159 work->send_no_response = 1;160 }161}162 163/**164 * is_smb2_neg_cmd() - is it smb2 negotiation command165 * @work: smb work containing smb header166 *167 * Return: true if smb2 negotiation command, otherwise false168 */169bool is_smb2_neg_cmd(struct ksmbd_work *work)170{171 struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);172 173 /* is it SMB2 header ? */174 if (hdr->ProtocolId != SMB2_PROTO_NUMBER)175 return false;176 177 /* make sure it is request not response message */178 if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)179 return false;180 181 if (hdr->Command != SMB2_NEGOTIATE)182 return false;183 184 return true;185}186 187/**188 * is_smb2_rsp() - is it smb2 response189 * @work: smb work containing smb response buffer190 *191 * Return: true if smb2 response, otherwise false192 */193bool is_smb2_rsp(struct ksmbd_work *work)194{195 struct smb2_hdr *hdr = smb2_get_msg(work->response_buf);196 197 /* is it SMB2 header ? */198 if (hdr->ProtocolId != SMB2_PROTO_NUMBER)199 return false;200 201 /* make sure it is response not request message */202 if (!(hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR))203 return false;204 205 return true;206}207 208/**209 * get_smb2_cmd_val() - get smb command code from smb header210 * @work: smb work containing smb request buffer211 *212 * Return: smb2 request command value213 */214u16 get_smb2_cmd_val(struct ksmbd_work *work)215{216 struct smb2_hdr *rcv_hdr;217 218 if (work->next_smb2_rcv_hdr_off)219 rcv_hdr = ksmbd_req_buf_next(work);220 else221 rcv_hdr = smb2_get_msg(work->request_buf);222 return le16_to_cpu(rcv_hdr->Command);223}224 225/**226 * set_smb2_rsp_status() - set error response code on smb2 header227 * @work: smb work containing response buffer228 * @err: error response code229 */230void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err)231{232 struct smb2_hdr *rsp_hdr;233 234 rsp_hdr = smb2_get_msg(work->response_buf);235 rsp_hdr->Status = err;236 237 work->iov_idx = 0;238 work->iov_cnt = 0;239 work->next_smb2_rcv_hdr_off = 0;240 smb2_set_err_rsp(work);241}242 243/**244 * init_smb2_neg_rsp() - initialize smb2 response for negotiate command245 * @work: smb work containing smb request buffer246 *247 * smb2 negotiate response is sent in reply of smb1 negotiate command for248 * dialect auto-negotiation.249 */250int init_smb2_neg_rsp(struct ksmbd_work *work)251{252 struct smb2_hdr *rsp_hdr;253 struct smb2_negotiate_rsp *rsp;254 struct ksmbd_conn *conn = work->conn;255 int err;256 257 rsp_hdr = smb2_get_msg(work->response_buf);258 memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);259 rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;260 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;261 rsp_hdr->CreditRequest = cpu_to_le16(2);262 rsp_hdr->Command = SMB2_NEGOTIATE;263 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);264 rsp_hdr->NextCommand = 0;265 rsp_hdr->MessageId = 0;266 rsp_hdr->Id.SyncId.ProcessId = 0;267 rsp_hdr->Id.SyncId.TreeId = 0;268 rsp_hdr->SessionId = 0;269 memset(rsp_hdr->Signature, 0, 16);270 271 rsp = smb2_get_msg(work->response_buf);272 273 WARN_ON(ksmbd_conn_good(conn));274 275 rsp->StructureSize = cpu_to_le16(65);276 ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);277 rsp->DialectRevision = cpu_to_le16(conn->dialect);278 /* Not setting conn guid rsp->ServerGUID, as it279 * not used by client for identifying connection280 */281 rsp->Capabilities = cpu_to_le32(conn->vals->capabilities);282 /* Default Max Message Size till SMB2.0, 64K*/283 rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size);284 rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size);285 rsp->MaxWriteSize = cpu_to_le32(conn->vals->max_write_size);286 287 rsp->SystemTime = cpu_to_le64(ksmbd_systime());288 rsp->ServerStartTime = 0;289 290 rsp->SecurityBufferOffset = cpu_to_le16(128);291 rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH);292 ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) +293 le16_to_cpu(rsp->SecurityBufferOffset));294 rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE;295 if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY)296 rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;297 err = ksmbd_iov_pin_rsp(work, rsp,298 sizeof(struct smb2_negotiate_rsp) + AUTH_GSS_LENGTH);299 if (err)300 return err;301 conn->use_spnego = true;302 303 ksmbd_conn_set_need_negotiate(conn);304 return 0;305}306 307/**308 * smb2_set_rsp_credits() - set number of credits in response buffer309 * @work: smb work containing smb response buffer310 */311int smb2_set_rsp_credits(struct ksmbd_work *work)312{313 struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work);314 struct smb2_hdr *hdr = ksmbd_resp_buf_next(work);315 struct ksmbd_conn *conn = work->conn;316 unsigned short credits_requested, aux_max;317 unsigned short credit_charge, credits_granted = 0;318 319 if (work->send_no_response)320 return 0;321 322 hdr->CreditCharge = req_hdr->CreditCharge;323 324 if (conn->total_credits > conn->vals->max_credits) {325 hdr->CreditRequest = 0;326 pr_err("Total credits overflow: %d\n", conn->total_credits);327 return -EINVAL;328 }329 330 credit_charge = max_t(unsigned short,331 le16_to_cpu(req_hdr->CreditCharge), 1);332 if (credit_charge > conn->total_credits) {333 ksmbd_debug(SMB, "Insufficient credits granted, given: %u, granted: %u\n",334 credit_charge, conn->total_credits);335 return -EINVAL;336 }337 338 conn->total_credits -= credit_charge;339 conn->outstanding_credits -= credit_charge;340 credits_requested = max_t(unsigned short,341 le16_to_cpu(req_hdr->CreditRequest), 1);342 343 /* according to smb2.credits smbtorture, Windows server344 * 2016 or later grant up to 8192 credits at once.345 *346 * TODO: Need to adjuct CreditRequest value according to347 * current cpu load348 */349 if (hdr->Command == SMB2_NEGOTIATE)350 aux_max = 1;351 else352 aux_max = conn->vals->max_credits - conn->total_credits;353 credits_granted = min_t(unsigned short, credits_requested, aux_max);354 355 conn->total_credits += credits_granted;356 work->credits_granted += credits_granted;357 358 if (!req_hdr->NextCommand) {359 /* Update CreditRequest in last request */360 hdr->CreditRequest = cpu_to_le16(work->credits_granted);361 }362 ksmbd_debug(SMB,363 "credits: requested[%d] granted[%d] total_granted[%d]\n",364 credits_requested, credits_granted,365 conn->total_credits);366 return 0;367}368 369/**370 * init_chained_smb2_rsp() - initialize smb2 chained response371 * @work: smb work containing smb response buffer372 */373static void init_chained_smb2_rsp(struct ksmbd_work *work)374{375 struct smb2_hdr *req = ksmbd_req_buf_next(work);376 struct smb2_hdr *rsp = ksmbd_resp_buf_next(work);377 struct smb2_hdr *rsp_hdr;378 struct smb2_hdr *rcv_hdr;379 int next_hdr_offset = 0;380 int len, new_len;381 382 /* Len of this response = updated RFC len - offset of previous cmd383 * in the compound rsp384 */385 386 /* Storing the current local FID which may be needed by subsequent387 * command in the compound request388 */389 if (req->Command == SMB2_CREATE && rsp->Status == STATUS_SUCCESS) {390 work->compound_fid = ((struct smb2_create_rsp *)rsp)->VolatileFileId;391 work->compound_pfid = ((struct smb2_create_rsp *)rsp)->PersistentFileId;392 work->compound_sid = le64_to_cpu(rsp->SessionId);393 }394 395 len = get_rfc1002_len(work->response_buf) - work->next_smb2_rsp_hdr_off;396 next_hdr_offset = le32_to_cpu(req->NextCommand);397 398 new_len = ALIGN(len, 8);399 work->iov[work->iov_idx].iov_len += (new_len - len);400 inc_rfc1001_len(work->response_buf, new_len - len);401 rsp->NextCommand = cpu_to_le32(new_len);402 403 work->next_smb2_rcv_hdr_off += next_hdr_offset;404 work->curr_smb2_rsp_hdr_off = work->next_smb2_rsp_hdr_off;405 work->next_smb2_rsp_hdr_off += new_len;406 ksmbd_debug(SMB,407 "Compound req new_len = %d rcv off = %d rsp off = %d\n",408 new_len, work->next_smb2_rcv_hdr_off,409 work->next_smb2_rsp_hdr_off);410 411 rsp_hdr = ksmbd_resp_buf_next(work);412 rcv_hdr = ksmbd_req_buf_next(work);413 414 if (!(rcv_hdr->Flags & SMB2_FLAGS_RELATED_OPERATIONS)) {415 ksmbd_debug(SMB, "related flag should be set\n");416 work->compound_fid = KSMBD_NO_FID;417 work->compound_pfid = KSMBD_NO_FID;418 }419 memset((char *)rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);420 rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;421 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;422 rsp_hdr->Command = rcv_hdr->Command;423 424 /*425 * Message is response. We don't grant oplock yet.426 */427 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR |428 SMB2_FLAGS_RELATED_OPERATIONS);429 rsp_hdr->NextCommand = 0;430 rsp_hdr->MessageId = rcv_hdr->MessageId;431 rsp_hdr->Id.SyncId.ProcessId = rcv_hdr->Id.SyncId.ProcessId;432 rsp_hdr->Id.SyncId.TreeId = rcv_hdr->Id.SyncId.TreeId;433 rsp_hdr->SessionId = rcv_hdr->SessionId;434 memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);435}436 437/**438 * is_chained_smb2_message() - check for chained command439 * @work: smb work containing smb request buffer440 *441 * Return: true if chained request, otherwise false442 */443bool is_chained_smb2_message(struct ksmbd_work *work)444{445 struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);446 unsigned int len, next_cmd;447 448 if (hdr->ProtocolId != SMB2_PROTO_NUMBER)449 return false;450 451 hdr = ksmbd_req_buf_next(work);452 next_cmd = le32_to_cpu(hdr->NextCommand);453 if (next_cmd > 0) {454 if ((u64)work->next_smb2_rcv_hdr_off + next_cmd +455 __SMB2_HEADER_STRUCTURE_SIZE >456 get_rfc1002_len(work->request_buf)) {457 pr_err("next command(%u) offset exceeds smb msg size\n",458 next_cmd);459 return false;460 }461 462 if ((u64)get_rfc1002_len(work->response_buf) + MAX_CIFS_SMALL_BUFFER_SIZE >463 work->response_sz) {464 pr_err("next response offset exceeds response buffer size\n");465 return false;466 }467 468 ksmbd_debug(SMB, "got SMB2 chained command\n");469 init_chained_smb2_rsp(work);470 return true;471 } else if (work->next_smb2_rcv_hdr_off) {472 /*473 * This is last request in chained command,474 * align response to 8 byte475 */476 len = ALIGN(get_rfc1002_len(work->response_buf), 8);477 len = len - get_rfc1002_len(work->response_buf);478 if (len) {479 ksmbd_debug(SMB, "padding len %u\n", len);480 work->iov[work->iov_idx].iov_len += len;481 inc_rfc1001_len(work->response_buf, len);482 }483 work->curr_smb2_rsp_hdr_off = work->next_smb2_rsp_hdr_off;484 }485 return false;486}487 488/**489 * init_smb2_rsp_hdr() - initialize smb2 response490 * @work: smb work containing smb request buffer491 *492 * Return: 0493 */494int init_smb2_rsp_hdr(struct ksmbd_work *work)495{496 struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf);497 struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf);498 499 memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);500 rsp_hdr->ProtocolId = rcv_hdr->ProtocolId;501 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;502 rsp_hdr->Command = rcv_hdr->Command;503 504 /*505 * Message is response. We don't grant oplock yet.506 */507 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);508 rsp_hdr->NextCommand = 0;509 rsp_hdr->MessageId = rcv_hdr->MessageId;510 rsp_hdr->Id.SyncId.ProcessId = rcv_hdr->Id.SyncId.ProcessId;511 rsp_hdr->Id.SyncId.TreeId = rcv_hdr->Id.SyncId.TreeId;512 rsp_hdr->SessionId = rcv_hdr->SessionId;513 memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);514 515 return 0;516}517 518/**519 * smb2_allocate_rsp_buf() - allocate smb2 response buffer520 * @work: smb work containing smb request buffer521 *522 * Return: 0 on success, otherwise error523 */524int smb2_allocate_rsp_buf(struct ksmbd_work *work)525{526 struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);527 size_t small_sz = MAX_CIFS_SMALL_BUFFER_SIZE;528 size_t large_sz = small_sz + work->conn->vals->max_trans_size;529 size_t sz = small_sz;530 int cmd = le16_to_cpu(hdr->Command);531 532 if (cmd == SMB2_IOCTL_HE || cmd == SMB2_QUERY_DIRECTORY_HE)533 sz = large_sz;534 535 if (cmd == SMB2_QUERY_INFO_HE) {536 struct smb2_query_info_req *req;537 538 if (get_rfc1002_len(work->request_buf) <539 offsetof(struct smb2_query_info_req, OutputBufferLength))540 return -EINVAL;541 542 req = smb2_get_msg(work->request_buf);543 if ((req->InfoType == SMB2_O_INFO_FILE &&544 (req->FileInfoClass == FILE_FULL_EA_INFORMATION ||545 req->FileInfoClass == FILE_ALL_INFORMATION)) ||546 req->InfoType == SMB2_O_INFO_SECURITY)547 sz = large_sz;548 }549 550 /* allocate large response buf for chained commands */551 if (le32_to_cpu(hdr->NextCommand) > 0)552 sz = large_sz;553 554 work->response_buf = kvzalloc(sz, GFP_KERNEL);555 if (!work->response_buf)556 return -ENOMEM;557 558 work->response_sz = sz;559 return 0;560}561 562/**563 * smb2_check_user_session() - check for valid session for a user564 * @work: smb work containing smb request buffer565 *566 * Return: 0 on success, otherwise error567 */568int smb2_check_user_session(struct ksmbd_work *work)569{570 struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work);571 struct ksmbd_conn *conn = work->conn;572 unsigned int cmd = le16_to_cpu(req_hdr->Command);573 unsigned long long sess_id;574 575 /*576 * SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not577 * require a session id, so no need to validate user session's for578 * these commands.579 */580 if (cmd == SMB2_ECHO_HE || cmd == SMB2_NEGOTIATE_HE ||581 cmd == SMB2_SESSION_SETUP_HE)582 return 0;583 584 if (!ksmbd_conn_good(conn))585 return -EIO;586 587 sess_id = le64_to_cpu(req_hdr->SessionId);588 589 /*590 * If request is not the first in Compound request,591 * Just validate session id in header with work->sess->id.592 */593 if (work->next_smb2_rcv_hdr_off) {594 if (!work->sess) {595 pr_err("The first operation in the compound does not have sess\n");596 return -EINVAL;597 }598 if (sess_id != ULLONG_MAX && work->sess->id != sess_id) {599 pr_err("session id(%llu) is different with the first operation(%lld)\n",600 sess_id, work->sess->id);601 return -EINVAL;602 }603 return 1;604 }605 606 /* Check for validity of user session */607 work->sess = ksmbd_session_lookup_all(conn, sess_id);608 if (work->sess) {609 ksmbd_user_session_get(work->sess);610 return 1;611 }612 ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);613 return -ENOENT;614}615 616/**617 * smb2_get_name() - get filename string from on the wire smb format618 * @src: source buffer619 * @maxlen: maxlen of source string620 * @local_nls: nls_table pointer621 *622 * Return: matching converted filename on success, otherwise error ptr623 */624static char *625smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls)626{627 char *name;628 629 name = smb_strndup_from_utf16(src, maxlen, 1, local_nls);630 if (IS_ERR(name)) {631 pr_err("failed to get name %ld\n", PTR_ERR(name));632 return name;633 }634 635 if (*name == '\\') {636 pr_err("not allow directory name included leading slash\n");637 kfree(name);638 return ERR_PTR(-EINVAL);639 }640 641 ksmbd_conv_path_to_unix(name);642 ksmbd_strip_last_slash(name);643 return name;644}645 646int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)647{648 struct ksmbd_conn *conn = work->conn;649 int id;650 651 id = ksmbd_acquire_async_msg_id(&conn->async_ida);652 if (id < 0) {653 pr_err("Failed to alloc async message id\n");654 return id;655 }656 work->asynchronous = true;657 work->async_id = id;658 659 ksmbd_debug(SMB,660 "Send interim Response to inform async request id : %d\n",661 work->async_id);662 663 work->cancel_fn = fn;664 work->cancel_argv = arg;665 666 if (list_empty(&work->async_request_entry)) {667 spin_lock(&conn->request_lock);668 list_add_tail(&work->async_request_entry, &conn->async_requests);669 spin_unlock(&conn->request_lock);670 }671 672 return 0;673}674 675void release_async_work(struct ksmbd_work *work)676{677 struct ksmbd_conn *conn = work->conn;678 679 spin_lock(&conn->request_lock);680 list_del_init(&work->async_request_entry);681 spin_unlock(&conn->request_lock);682 683 work->asynchronous = 0;684 work->cancel_fn = NULL;685 kfree(work->cancel_argv);686 work->cancel_argv = NULL;687 if (work->async_id) {688 ksmbd_release_id(&conn->async_ida, work->async_id);689 work->async_id = 0;690 }691}692 693void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)694{695 struct smb2_hdr *rsp_hdr;696 struct ksmbd_work *in_work = ksmbd_alloc_work_struct();697 698 if (allocate_interim_rsp_buf(in_work)) {699 pr_err("smb_allocate_rsp_buf failed!\n");700 ksmbd_free_work_struct(in_work);701 return;702 }703 704 in_work->conn = work->conn;705 memcpy(smb2_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),706 __SMB2_HEADER_STRUCTURE_SIZE);707 708 rsp_hdr = smb2_get_msg(in_work->response_buf);709 rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;710 rsp_hdr->Id.AsyncId = cpu_to_le64(work->async_id);711 smb2_set_err_rsp(in_work);712 rsp_hdr->Status = status;713 714 ksmbd_conn_write(in_work);715 ksmbd_free_work_struct(in_work);716}717 718static __le32 smb2_get_reparse_tag_special_file(umode_t mode)719{720 if (S_ISDIR(mode) || S_ISREG(mode))721 return 0;722 723 if (S_ISLNK(mode))724 return IO_REPARSE_TAG_LX_SYMLINK_LE;725 else if (S_ISFIFO(mode))726 return IO_REPARSE_TAG_LX_FIFO_LE;727 else if (S_ISSOCK(mode))728 return IO_REPARSE_TAG_AF_UNIX_LE;729 else if (S_ISCHR(mode))730 return IO_REPARSE_TAG_LX_CHR_LE;731 else if (S_ISBLK(mode))732 return IO_REPARSE_TAG_LX_BLK_LE;733 734 return 0;735}736 737/**738 * smb2_get_dos_mode() - get file mode in dos format from unix mode739 * @stat: kstat containing file mode740 * @attribute: attribute flags741 *742 * Return: converted dos mode743 */744static int smb2_get_dos_mode(struct kstat *stat, int attribute)745{746 int attr = 0;747 748 if (S_ISDIR(stat->mode)) {749 attr = FILE_ATTRIBUTE_DIRECTORY |750 (attribute & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM));751 } else {752 attr = (attribute & 0x00005137) | FILE_ATTRIBUTE_ARCHIVE;753 attr &= ~(FILE_ATTRIBUTE_DIRECTORY);754 if (S_ISREG(stat->mode) && (server_conf.share_fake_fscaps &755 FILE_SUPPORTS_SPARSE_FILES))756 attr |= FILE_ATTRIBUTE_SPARSE_FILE;757 758 if (smb2_get_reparse_tag_special_file(stat->mode))759 attr |= FILE_ATTRIBUTE_REPARSE_POINT;760 }761 762 return attr;763}764 765static void build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt,766 __le16 hash_id)767{768 pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;769 pneg_ctxt->DataLength = cpu_to_le16(38);770 pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1);771 pneg_ctxt->Reserved = cpu_to_le32(0);772 pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE);773 get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE);774 pneg_ctxt->HashAlgorithms = hash_id;775}776 777static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt,778 __le16 cipher_type)779{780 pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;781 pneg_ctxt->DataLength = cpu_to_le16(4);782 pneg_ctxt->Reserved = cpu_to_le32(0);783 pneg_ctxt->CipherCount = cpu_to_le16(1);784 pneg_ctxt->Ciphers[0] = cipher_type;785}786 787static void build_sign_cap_ctxt(struct smb2_signing_capabilities *pneg_ctxt,788 __le16 sign_algo)789{790 pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES;791 pneg_ctxt->DataLength =792 cpu_to_le16((sizeof(struct smb2_signing_capabilities) + 2)793 - sizeof(struct smb2_neg_context));794 pneg_ctxt->Reserved = cpu_to_le32(0);795 pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(1);796 pneg_ctxt->SigningAlgorithms[0] = sign_algo;797}798 799static void build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)800{801 pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE;802 pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);803 /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */804 pneg_ctxt->Name[0] = 0x93;805 pneg_ctxt->Name[1] = 0xAD;806 pneg_ctxt->Name[2] = 0x25;807 pneg_ctxt->Name[3] = 0x50;808 pneg_ctxt->Name[4] = 0x9C;809 pneg_ctxt->Name[5] = 0xB4;810 pneg_ctxt->Name[6] = 0x11;811 pneg_ctxt->Name[7] = 0xE7;812 pneg_ctxt->Name[8] = 0xB4;813 pneg_ctxt->Name[9] = 0x23;814 pneg_ctxt->Name[10] = 0x83;815 pneg_ctxt->Name[11] = 0xDE;816 pneg_ctxt->Name[12] = 0x96;817 pneg_ctxt->Name[13] = 0x8B;818 pneg_ctxt->Name[14] = 0xCD;819 pneg_ctxt->Name[15] = 0x7C;820}821 822static unsigned int assemble_neg_contexts(struct ksmbd_conn *conn,823 struct smb2_negotiate_rsp *rsp)824{825 char * const pneg_ctxt = (char *)rsp +826 le32_to_cpu(rsp->NegotiateContextOffset);827 int neg_ctxt_cnt = 1;828 int ctxt_size;829 830 ksmbd_debug(SMB,831 "assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n");832 build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt,833 conn->preauth_info->Preauth_HashId);834 ctxt_size = sizeof(struct smb2_preauth_neg_context);835 836 if (conn->cipher_type) {837 /* Round to 8 byte boundary */838 ctxt_size = round_up(ctxt_size, 8);839 ksmbd_debug(SMB,840 "assemble SMB2_ENCRYPTION_CAPABILITIES context\n");841 build_encrypt_ctxt((struct smb2_encryption_neg_context *)842 (pneg_ctxt + ctxt_size),843 conn->cipher_type);844 neg_ctxt_cnt++;845 ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2;846 }847 848 /* compression context not yet supported */849 WARN_ON(conn->compress_algorithm != SMB3_COMPRESS_NONE);850 851 if (conn->posix_ext_supported) {852 ctxt_size = round_up(ctxt_size, 8);853 ksmbd_debug(SMB,854 "assemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n");855 build_posix_ctxt((struct smb2_posix_neg_context *)856 (pneg_ctxt + ctxt_size));857 neg_ctxt_cnt++;858 ctxt_size += sizeof(struct smb2_posix_neg_context);859 }860 861 if (conn->signing_negotiated) {862 ctxt_size = round_up(ctxt_size, 8);863 ksmbd_debug(SMB,864 "assemble SMB2_SIGNING_CAPABILITIES context\n");865 build_sign_cap_ctxt((struct smb2_signing_capabilities *)866 (pneg_ctxt + ctxt_size),867 conn->signing_algorithm);868 neg_ctxt_cnt++;869 ctxt_size += sizeof(struct smb2_signing_capabilities) + 2;870 }871 872 rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt);873 return ctxt_size + AUTH_GSS_PADDING;874}875 876static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,877 struct smb2_preauth_neg_context *pneg_ctxt,878 int ctxt_len)879{880 /*881 * sizeof(smb2_preauth_neg_context) assumes SMB311_SALT_SIZE Salt,882 * which may not be present. Only check for used HashAlgorithms[1].883 */884 if (ctxt_len <885 sizeof(struct smb2_neg_context) + MIN_PREAUTH_CTXT_DATA_LEN)886 return STATUS_INVALID_PARAMETER;887 888 if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)889 return STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP;890 891 conn->preauth_info->Preauth_HashId = SMB2_PREAUTH_INTEGRITY_SHA512;892 return STATUS_SUCCESS;893}894 895static void decode_encrypt_ctxt(struct ksmbd_conn *conn,896 struct smb2_encryption_neg_context *pneg_ctxt,897 int ctxt_len)898{899 int cph_cnt;900 int i, cphs_size;901 902 if (sizeof(struct smb2_encryption_neg_context) > ctxt_len) {903 pr_err("Invalid SMB2_ENCRYPTION_CAPABILITIES context size\n");904 return;905 }906 907 conn->cipher_type = 0;908 909 cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);910 cphs_size = cph_cnt * sizeof(__le16);911 912 if (sizeof(struct smb2_encryption_neg_context) + cphs_size >913 ctxt_len) {914 pr_err("Invalid cipher count(%d)\n", cph_cnt);915 return;916 }917 918 if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF)919 return;920 921 for (i = 0; i < cph_cnt; i++) {922 if (pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_GCM ||923 pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_CCM ||924 pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_CCM ||925 pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_GCM) {926 ksmbd_debug(SMB, "Cipher ID = 0x%x\n",927 pneg_ctxt->Ciphers[i]);928 conn->cipher_type = pneg_ctxt->Ciphers[i];929 break;930 }931 }932}933 934/**935 * smb3_encryption_negotiated() - checks if server and client agreed on enabling encryption936 * @conn: smb connection937 *938 * Return: true if connection should be encrypted, else false939 */940bool smb3_encryption_negotiated(struct ksmbd_conn *conn)941{942 if (!conn->ops->generate_encryptionkey)943 return false;944 945 /*946 * SMB 3.0 and 3.0.2 dialects use the SMB2_GLOBAL_CAP_ENCRYPTION flag.947 * SMB 3.1.1 uses the cipher_type field.948 */949 return (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) ||950 conn->cipher_type;951}952 953static void decode_compress_ctxt(struct ksmbd_conn *conn,954 struct smb2_compression_capabilities_context *pneg_ctxt)955{956 conn->compress_algorithm = SMB3_COMPRESS_NONE;957}958 959static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,960 struct smb2_signing_capabilities *pneg_ctxt,961 int ctxt_len)962{963 int sign_algo_cnt;964 int i, sign_alos_size;965 966 if (sizeof(struct smb2_signing_capabilities) > ctxt_len) {967 pr_err("Invalid SMB2_SIGNING_CAPABILITIES context length\n");968 return;969 }970 971 conn->signing_negotiated = false;972 sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);973 sign_alos_size = sign_algo_cnt * sizeof(__le16);974 975 if (sizeof(struct smb2_signing_capabilities) + sign_alos_size >976 ctxt_len) {977 pr_err("Invalid signing algorithm count(%d)\n", sign_algo_cnt);978 return;979 }980 981 for (i = 0; i < sign_algo_cnt; i++) {982 if (pneg_ctxt->SigningAlgorithms[i] == SIGNING_ALG_HMAC_SHA256_LE ||983 pneg_ctxt->SigningAlgorithms[i] == SIGNING_ALG_AES_CMAC_LE) {984 ksmbd_debug(SMB, "Signing Algorithm ID = 0x%x\n",985 pneg_ctxt->SigningAlgorithms[i]);986 conn->signing_negotiated = true;987 conn->signing_algorithm =988 pneg_ctxt->SigningAlgorithms[i];989 break;990 }991 }992}993 994static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,995 struct smb2_negotiate_req *req,996 unsigned int len_of_smb)997{998 /* +4 is to account for the RFC1001 len field */999 struct smb2_neg_context *pctx = (struct smb2_neg_context *)req;1000 int i = 0, len_of_ctxts;1001 unsigned int offset = le32_to_cpu(req->NegotiateContextOffset);1002 unsigned int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);1003 __le32 status = STATUS_INVALID_PARAMETER;1004 1005 ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt);1006 if (len_of_smb <= offset) {1007 ksmbd_debug(SMB, "Invalid response: negotiate context offset\n");1008 return status;1009 }1010 1011 len_of_ctxts = len_of_smb - offset;1012 1013 while (i++ < neg_ctxt_cnt) {1014 int clen, ctxt_len;1015 1016 if (len_of_ctxts < (int)sizeof(struct smb2_neg_context))1017 break;1018 1019 pctx = (struct smb2_neg_context *)((char *)pctx + offset);1020 clen = le16_to_cpu(pctx->DataLength);1021 ctxt_len = clen + sizeof(struct smb2_neg_context);1022 1023 if (ctxt_len > len_of_ctxts)1024 break;1025 1026 if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) {1027 ksmbd_debug(SMB,1028 "deassemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n");1029 if (conn->preauth_info->Preauth_HashId)1030 break;1031 1032 status = decode_preauth_ctxt(conn,1033 (struct smb2_preauth_neg_context *)pctx,1034 ctxt_len);1035 if (status != STATUS_SUCCESS)1036 break;1037 } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) {1038 ksmbd_debug(SMB,1039 "deassemble SMB2_ENCRYPTION_CAPABILITIES context\n");1040 if (conn->cipher_type)1041 break;1042 1043 decode_encrypt_ctxt(conn,1044 (struct smb2_encryption_neg_context *)pctx,1045 ctxt_len);1046 } else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) {1047 ksmbd_debug(SMB,1048 "deassemble SMB2_COMPRESSION_CAPABILITIES context\n");1049 if (conn->compress_algorithm)1050 break;1051 1052 decode_compress_ctxt(conn,1053 (struct smb2_compression_capabilities_context *)pctx);1054 } else if (pctx->ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) {1055 ksmbd_debug(SMB,1056 "deassemble SMB2_NETNAME_NEGOTIATE_CONTEXT_ID context\n");1057 } else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) {1058 ksmbd_debug(SMB,1059 "deassemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n");1060 conn->posix_ext_supported = true;1061 } else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) {1062 ksmbd_debug(SMB,1063 "deassemble SMB2_SIGNING_CAPABILITIES context\n");1064 1065 decode_sign_cap_ctxt(conn,1066 (struct smb2_signing_capabilities *)pctx,1067 ctxt_len);1068 }1069 1070 /* offsets must be 8 byte aligned */1071 offset = (ctxt_len + 7) & ~0x7;1072 len_of_ctxts -= offset;1073 }1074 return status;1075}1076 1077/**1078 * smb2_handle_negotiate() - handler for smb2 negotiate command1079 * @work: smb work containing smb request buffer1080 *1081 * Return: 01082 */1083int smb2_handle_negotiate(struct ksmbd_work *work)1084{1085 struct ksmbd_conn *conn = work->conn;1086 struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf);1087 struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf);1088 int rc = 0;1089 unsigned int smb2_buf_len, smb2_neg_size, neg_ctxt_len = 0;1090 __le32 status;1091 1092 ksmbd_debug(SMB, "Received negotiate request\n");1093 conn->need_neg = false;1094 if (ksmbd_conn_good(conn)) {1095 pr_err("conn->tcp_status is already in CifsGood State\n");1096 work->send_no_response = 1;1097 return rc;1098 }1099 1100 smb2_buf_len = get_rfc1002_len(work->request_buf);1101 smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);1102 if (smb2_neg_size > smb2_buf_len) {1103 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1104 rc = -EINVAL;1105 goto err_out;1106 }1107 1108 if (req->DialectCount == 0) {1109 pr_err("malformed packet\n");1110 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1111 rc = -EINVAL;1112 goto err_out;1113 }1114 1115 if (conn->dialect == SMB311_PROT_ID) {1116 unsigned int nego_ctxt_off = le32_to_cpu(req->NegotiateContextOffset);1117 1118 if (smb2_buf_len < nego_ctxt_off) {1119 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1120 rc = -EINVAL;1121 goto err_out;1122 }1123 1124 if (smb2_neg_size > nego_ctxt_off) {1125 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1126 rc = -EINVAL;1127 goto err_out;1128 }1129 1130 if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >1131 nego_ctxt_off) {1132 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1133 rc = -EINVAL;1134 goto err_out;1135 }1136 } else {1137 if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >1138 smb2_buf_len) {1139 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1140 rc = -EINVAL;1141 goto err_out;1142 }1143 }1144 1145 conn->cli_cap = le32_to_cpu(req->Capabilities);1146 switch (conn->dialect) {1147 case SMB311_PROT_ID:1148 conn->preauth_info =1149 kzalloc(sizeof(struct preauth_integrity_info),1150 GFP_KERNEL);1151 if (!conn->preauth_info) {1152 rc = -ENOMEM;1153 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1154 goto err_out;1155 }1156 1157 status = deassemble_neg_contexts(conn, req,1158 get_rfc1002_len(work->request_buf));1159 if (status != STATUS_SUCCESS) {1160 pr_err("deassemble_neg_contexts error(0x%x)\n",1161 status);1162 rsp->hdr.Status = status;1163 rc = -EINVAL;1164 kfree(conn->preauth_info);1165 conn->preauth_info = NULL;1166 goto err_out;1167 }1168 1169 rc = init_smb3_11_server(conn);1170 if (rc < 0) {1171 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1172 kfree(conn->preauth_info);1173 conn->preauth_info = NULL;1174 goto err_out;1175 }1176 1177 ksmbd_gen_preauth_integrity_hash(conn,1178 work->request_buf,1179 conn->preauth_info->Preauth_HashValue);1180 rsp->NegotiateContextOffset =1181 cpu_to_le32(OFFSET_OF_NEG_CONTEXT);1182 neg_ctxt_len = assemble_neg_contexts(conn, rsp);1183 break;1184 case SMB302_PROT_ID:1185 init_smb3_02_server(conn);1186 break;1187 case SMB30_PROT_ID:1188 init_smb3_0_server(conn);1189 break;1190 case SMB21_PROT_ID:1191 init_smb2_1_server(conn);1192 break;1193 case SMB2X_PROT_ID:1194 case BAD_PROT_ID:1195 default:1196 ksmbd_debug(SMB, "Server dialect :0x%x not supported\n",1197 conn->dialect);1198 rsp->hdr.Status = STATUS_NOT_SUPPORTED;1199 rc = -EINVAL;1200 goto err_out;1201 }1202 rsp->Capabilities = cpu_to_le32(conn->vals->capabilities);1203 1204 /* For stats */1205 conn->connection_type = conn->dialect;1206 1207 rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size);1208 rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size);1209 rsp->MaxWriteSize = cpu_to_le32(conn->vals->max_write_size);1210 1211 memcpy(conn->ClientGUID, req->ClientGUID,1212 SMB2_CLIENT_GUID_SIZE);1213 conn->cli_sec_mode = le16_to_cpu(req->SecurityMode);1214 1215 rsp->StructureSize = cpu_to_le16(65);1216 rsp->DialectRevision = cpu_to_le16(conn->dialect);1217 /* Not setting conn guid rsp->ServerGUID, as it1218 * not used by client for identifying server1219 */1220 memset(rsp->ServerGUID, 0, SMB2_CLIENT_GUID_SIZE);1221 1222 rsp->SystemTime = cpu_to_le64(ksmbd_systime());1223 rsp->ServerStartTime = 0;1224 ksmbd_debug(SMB, "negotiate context offset %d, count %d\n",1225 le32_to_cpu(rsp->NegotiateContextOffset),1226 le16_to_cpu(rsp->NegotiateContextCount));1227 1228 rsp->SecurityBufferOffset = cpu_to_le16(128);1229 rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH);1230 ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) +1231 le16_to_cpu(rsp->SecurityBufferOffset));1232 1233 rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE;1234 conn->use_spnego = true;1235 1236 if ((server_conf.signing == KSMBD_CONFIG_OPT_AUTO ||1237 server_conf.signing == KSMBD_CONFIG_OPT_DISABLED) &&1238 req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED_LE)1239 conn->sign = true;1240 else if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) {1241 server_conf.enforced_signing = true;1242 rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;1243 conn->sign = true;1244 }1245 1246 conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode);1247 ksmbd_conn_set_need_negotiate(conn);1248 1249err_out:1250 if (rc)1251 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;1252 1253 if (!rc)1254 rc = ksmbd_iov_pin_rsp(work, rsp,1255 sizeof(struct smb2_negotiate_rsp) +1256 AUTH_GSS_LENGTH + neg_ctxt_len);1257 if (rc < 0)1258 smb2_set_err_rsp(work);1259 return rc;1260}1261 1262static int alloc_preauth_hash(struct ksmbd_session *sess,1263 struct ksmbd_conn *conn)1264{1265 if (sess->Preauth_HashValue)1266 return 0;1267 1268 sess->Preauth_HashValue = kmemdup(conn->preauth_info->Preauth_HashValue,1269 PREAUTH_HASHVALUE_SIZE, GFP_KERNEL);1270 if (!sess->Preauth_HashValue)1271 return -ENOMEM;1272 1273 return 0;1274}1275 1276static int generate_preauth_hash(struct ksmbd_work *work)1277{1278 struct ksmbd_conn *conn = work->conn;1279 struct ksmbd_session *sess = work->sess;1280 u8 *preauth_hash;1281 1282 if (conn->dialect != SMB311_PROT_ID)1283 return 0;1284 1285 if (conn->binding) {1286 struct preauth_session *preauth_sess;1287 1288 preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);1289 if (!preauth_sess) {1290 preauth_sess = ksmbd_preauth_session_alloc(conn, sess->id);1291 if (!preauth_sess)1292 return -ENOMEM;1293 }1294 1295 preauth_hash = preauth_sess->Preauth_HashValue;1296 } else {1297 if (!sess->Preauth_HashValue)1298 if (alloc_preauth_hash(sess, conn))1299 return -ENOMEM;1300 preauth_hash = sess->Preauth_HashValue;1301 }1302 1303 ksmbd_gen_preauth_integrity_hash(conn, work->request_buf, preauth_hash);1304 return 0;1305}1306 1307static int decode_negotiation_token(struct ksmbd_conn *conn,1308 struct negotiate_message *negblob,1309 size_t sz)1310{1311 if (!conn->use_spnego)1312 return -EINVAL;1313 1314 if (ksmbd_decode_negTokenInit((char *)negblob, sz, conn)) {1315 if (ksmbd_decode_negTokenTarg((char *)negblob, sz, conn)) {1316 conn->auth_mechs |= KSMBD_AUTH_NTLMSSP;1317 conn->preferred_auth_mech = KSMBD_AUTH_NTLMSSP;1318 conn->use_spnego = false;1319 }1320 }1321 return 0;1322}1323 1324static int ntlm_negotiate(struct ksmbd_work *work,1325 struct negotiate_message *negblob,1326 size_t negblob_len, struct smb2_sess_setup_rsp *rsp)1327{1328 struct challenge_message *chgblob;1329 unsigned char *spnego_blob = NULL;1330 u16 spnego_blob_len;1331 char *neg_blob;1332 int sz, rc;1333 1334 ksmbd_debug(SMB, "negotiate phase\n");1335 rc = ksmbd_decode_ntlmssp_neg_blob(negblob, negblob_len, work->conn);1336 if (rc)1337 return rc;1338 1339 sz = le16_to_cpu(rsp->SecurityBufferOffset);1340 chgblob = (struct challenge_message *)rsp->Buffer;1341 memset(chgblob, 0, sizeof(struct challenge_message));1342 1343 if (!work->conn->use_spnego) {1344 sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->conn);1345 if (sz < 0)1346 return -ENOMEM;1347 1348 rsp->SecurityBufferLength = cpu_to_le16(sz);1349 return 0;1350 }1351 1352 sz = sizeof(struct challenge_message);1353 sz += (strlen(ksmbd_netbios_name()) * 2 + 1 + 4) * 6;1354 1355 neg_blob = kzalloc(sz, GFP_KERNEL);1356 if (!neg_blob)1357 return -ENOMEM;1358 1359 chgblob = (struct challenge_message *)neg_blob;1360 sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->conn);1361 if (sz < 0) {1362 rc = -ENOMEM;1363 goto out;1364 }1365 1366 rc = build_spnego_ntlmssp_neg_blob(&spnego_blob, &spnego_blob_len,1367 neg_blob, sz);1368 if (rc) {1369 rc = -ENOMEM;1370 goto out;1371 }1372 1373 memcpy(rsp->Buffer, spnego_blob, spnego_blob_len);1374 rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);1375 1376out:1377 kfree(spnego_blob);1378 kfree(neg_blob);1379 return rc;1380}1381 1382static struct authenticate_message *user_authblob(struct ksmbd_conn *conn,1383 struct smb2_sess_setup_req *req)1384{1385 int sz;1386 1387 if (conn->use_spnego && conn->mechToken)1388 return (struct authenticate_message *)conn->mechToken;1389 1390 sz = le16_to_cpu(req->SecurityBufferOffset);1391 return (struct authenticate_message *)((char *)&req->hdr.ProtocolId1392 + sz);1393}1394 1395static struct ksmbd_user *session_user(struct ksmbd_conn *conn,1396 struct smb2_sess_setup_req *req)1397{1398 struct authenticate_message *authblob;1399 struct ksmbd_user *user;1400 char *name;1401 unsigned int name_off, name_len, secbuf_len;1402 1403 if (conn->use_spnego && conn->mechToken)1404 secbuf_len = conn->mechTokenLen;1405 else1406 secbuf_len = le16_to_cpu(req->SecurityBufferLength);1407 if (secbuf_len < sizeof(struct authenticate_message)) {1408 ksmbd_debug(SMB, "blob len %d too small\n", secbuf_len);1409 return NULL;1410 }1411 authblob = user_authblob(conn, req);1412 name_off = le32_to_cpu(authblob->UserName.BufferOffset);1413 name_len = le16_to_cpu(authblob->UserName.Length);1414 1415 if (secbuf_len < (u64)name_off + name_len)1416 return NULL;1417 1418 name = smb_strndup_from_utf16((const char *)authblob + name_off,1419 name_len,1420 true,1421 conn->local_nls);1422 if (IS_ERR(name)) {1423 pr_err("cannot allocate memory\n");1424 return NULL;1425 }1426 1427 ksmbd_debug(SMB, "session setup request for user %s\n", name);1428 user = ksmbd_login_user(name);1429 kfree(name);1430 return user;1431}1432 1433static int ntlm_authenticate(struct ksmbd_work *work,1434 struct smb2_sess_setup_req *req,1435 struct smb2_sess_setup_rsp *rsp)1436{1437 struct ksmbd_conn *conn = work->conn;1438 struct ksmbd_session *sess = work->sess;1439 struct channel *chann = NULL;1440 struct ksmbd_user *user;1441 u64 prev_id;1442 int sz, rc;1443 1444 ksmbd_debug(SMB, "authenticate phase\n");1445 if (conn->use_spnego) {1446 unsigned char *spnego_blob;1447 u16 spnego_blob_len;1448 1449 rc = build_spnego_ntlmssp_auth_blob(&spnego_blob,1450 &spnego_blob_len,1451 0);1452 if (rc)1453 return -ENOMEM;1454 1455 memcpy(rsp->Buffer, spnego_blob, spnego_blob_len);1456 rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);1457 kfree(spnego_blob);1458 }1459 1460 user = session_user(conn, req);1461 if (!user) {1462 ksmbd_debug(SMB, "Unknown user name or an error\n");1463 return -EPERM;1464 }1465 1466 /* Check for previous session */1467 prev_id = le64_to_cpu(req->PreviousSessionId);1468 if (prev_id && prev_id != sess->id)1469 destroy_previous_session(conn, user, prev_id);1470 1471 if (sess->state == SMB2_SESSION_VALID) {1472 /*1473 * Reuse session if anonymous try to connect1474 * on reauthetication.1475 */1476 if (conn->binding == false && ksmbd_anonymous_user(user)) {1477 ksmbd_free_user(user);1478 return 0;1479 }1480 1481 if (!ksmbd_compare_user(sess->user, user)) {1482 ksmbd_free_user(user);1483 return -EPERM;1484 }1485 ksmbd_free_user(user);1486 } else {1487 sess->user = user;1488 }1489 1490 if (conn->binding == false && user_guest(sess->user)) {1491 rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE;1492 } else {1493 struct authenticate_message *authblob;1494 1495 authblob = user_authblob(conn, req);1496 if (conn->use_spnego && conn->mechToken)1497 sz = conn->mechTokenLen;1498 else1499 sz = le16_to_cpu(req->SecurityBufferLength);1500 rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess);1501 if (rc) {1502 set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD);1503 ksmbd_debug(SMB, "authentication failed\n");1504 return -EPERM;1505 }1506 }1507 1508 /*1509 * If session state is SMB2_SESSION_VALID, We can assume1510 * that it is reauthentication. And the user/password1511 * has been verified, so return it here.1512 */1513 if (sess->state == SMB2_SESSION_VALID) {1514 if (conn->binding)1515 goto binding_session;1516 return 0;1517 }1518 1519 if ((rsp->SessionFlags != SMB2_SESSION_FLAG_IS_GUEST_LE &&1520 (conn->sign || server_conf.enforced_signing)) ||1521 (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))1522 sess->sign = true;1523 1524 if (smb3_encryption_negotiated(conn) &&1525 !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {1526 rc = conn->ops->generate_encryptionkey(conn, sess);1527 if (rc) {1528 ksmbd_debug(SMB,1529 "SMB3 encryption key generation failed\n");1530 return -EINVAL;1531 }1532 sess->enc = true;1533 if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION)1534 rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE;1535 /*1536 * signing is disable if encryption is enable1537 * on this session1538 */1539 sess->sign = false;1540 }1541 1542binding_session:1543 if (conn->dialect >= SMB30_PROT_ID) {1544 chann = lookup_chann_list(sess, conn);1545 if (!chann) {1546 chann = kmalloc(sizeof(struct channel), GFP_KERNEL);1547 if (!chann)1548 return -ENOMEM;1549 1550 chann->conn = conn;1551 xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);1552 }1553 }1554 1555 if (conn->ops->generate_signingkey) {1556 rc = conn->ops->generate_signingkey(sess, conn);1557 if (rc) {1558 ksmbd_debug(SMB, "SMB3 signing key generation failed\n");1559 return -EINVAL;1560 }1561 }1562 1563 if (!ksmbd_conn_lookup_dialect(conn)) {1564 pr_err("fail to verify the dialect\n");1565 return -ENOENT;1566 }1567 return 0;1568}1569 1570#ifdef CONFIG_SMB_SERVER_KERBEROS51571static int krb5_authenticate(struct ksmbd_work *work,1572 struct smb2_sess_setup_req *req,1573 struct smb2_sess_setup_rsp *rsp)1574{1575 struct ksmbd_conn *conn = work->conn;1576 struct ksmbd_session *sess = work->sess;1577 char *in_blob, *out_blob;1578 struct channel *chann = NULL;1579 u64 prev_sess_id;1580 int in_len, out_len;1581 int retval;1582 1583 in_blob = (char *)&req->hdr.ProtocolId +1584 le16_to_cpu(req->SecurityBufferOffset);1585 in_len = le16_to_cpu(req->SecurityBufferLength);1586 out_blob = (char *)&rsp->hdr.ProtocolId +1587 le16_to_cpu(rsp->SecurityBufferOffset);1588 out_len = work->response_sz -1589 (le16_to_cpu(rsp->SecurityBufferOffset) + 4);1590 1591 /* Check previous session */1592 prev_sess_id = le64_to_cpu(req->PreviousSessionId);1593 if (prev_sess_id && prev_sess_id != sess->id)1594 destroy_previous_session(conn, sess->user, prev_sess_id);1595 1596 if (sess->state == SMB2_SESSION_VALID)1597 ksmbd_free_user(sess->user);1598 1599 retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,1600 out_blob, &out_len);1601 if (retval) {1602 ksmbd_debug(SMB, "krb5 authentication failed\n");1603 return -EINVAL;1604 }1605 rsp->SecurityBufferLength = cpu_to_le16(out_len);1606 1607 if ((conn->sign || server_conf.enforced_signing) ||1608 (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))1609 sess->sign = true;1610 1611 if (smb3_encryption_negotiated(conn)) {1612 retval = conn->ops->generate_encryptionkey(conn, sess);1613 if (retval) {1614 ksmbd_debug(SMB,1615 "SMB3 encryption key generation failed\n");1616 return -EINVAL;1617 }1618 sess->enc = true;1619 if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION)1620 rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE;1621 sess->sign = false;1622 }1623 1624 if (conn->dialect >= SMB30_PROT_ID) {1625 chann = lookup_chann_list(sess, conn);1626 if (!chann) {1627 chann = kmalloc(sizeof(struct channel), GFP_KERNEL);1628 if (!chann)1629 return -ENOMEM;1630 1631 chann->conn = conn;1632 xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);1633 }1634 }1635 1636 if (conn->ops->generate_signingkey) {1637 retval = conn->ops->generate_signingkey(sess, conn);1638 if (retval) {1639 ksmbd_debug(SMB, "SMB3 signing key generation failed\n");1640 return -EINVAL;1641 }1642 }1643 1644 if (!ksmbd_conn_lookup_dialect(conn)) {1645 pr_err("fail to verify the dialect\n");1646 return -ENOENT;1647 }1648 return 0;1649}1650#else1651static int krb5_authenticate(struct ksmbd_work *work,1652 struct smb2_sess_setup_req *req,1653 struct smb2_sess_setup_rsp *rsp)1654{1655 return -EOPNOTSUPP;1656}1657#endif1658 1659int smb2_sess_setup(struct ksmbd_work *work)1660{1661 struct ksmbd_conn *conn = work->conn;1662 struct smb2_sess_setup_req *req;1663 struct smb2_sess_setup_rsp *rsp;1664 struct ksmbd_session *sess;1665 struct negotiate_message *negblob;1666 unsigned int negblob_len, negblob_off;1667 int rc = 0;1668 1669 ksmbd_debug(SMB, "Received request for session setup\n");1670 1671 WORK_BUFFERS(work, req, rsp);1672 1673 rsp->StructureSize = cpu_to_le16(9);1674 rsp->SessionFlags = 0;1675 rsp->SecurityBufferOffset = cpu_to_le16(72);1676 rsp->SecurityBufferLength = 0;1677 1678 ksmbd_conn_lock(conn);1679 if (!req->hdr.SessionId) {1680 sess = ksmbd_smb2_session_create();1681 if (!sess) {1682 rc = -ENOMEM;1683 goto out_err;1684 }1685 rsp->hdr.SessionId = cpu_to_le64(sess->id);1686 rc = ksmbd_session_register(conn, sess);1687 if (rc)1688 goto out_err;1689 1690 conn->binding = false;1691 } else if (conn->dialect >= SMB30_PROT_ID &&1692 (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&1693 req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) {1694 u64 sess_id = le64_to_cpu(req->hdr.SessionId);1695 1696 sess = ksmbd_session_lookup_slowpath(sess_id);1697 if (!sess) {1698 rc = -ENOENT;1699 goto out_err;1700 }1701 1702 if (conn->dialect != sess->dialect) {1703 rc = -EINVAL;1704 goto out_err;1705 }1706 1707 if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {1708 rc = -EINVAL;1709 goto out_err;1710 }1711 1712 if (strncmp(conn->ClientGUID, sess->ClientGUID,1713 SMB2_CLIENT_GUID_SIZE)) {1714 rc = -ENOENT;1715 goto out_err;1716 }1717 1718 if (sess->state == SMB2_SESSION_IN_PROGRESS) {1719 rc = -EACCES;1720 goto out_err;1721 }1722 1723 if (sess->state == SMB2_SESSION_EXPIRED) {1724 rc = -EFAULT;1725 goto out_err;1726 }1727 1728 if (ksmbd_conn_need_reconnect(conn)) {1729 rc = -EFAULT;1730 sess = NULL;1731 goto out_err;1732 }1733 1734 if (ksmbd_session_lookup(conn, sess_id)) {1735 rc = -EACCES;1736 goto out_err;1737 }1738 1739 if (user_guest(sess->user)) {1740 rc = -EOPNOTSUPP;1741 goto out_err;1742 }1743 1744 conn->binding = true;1745 ksmbd_user_session_get(sess);1746 } else if ((conn->dialect < SMB30_PROT_ID ||1747 server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&1748 (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {1749 sess = NULL;1750 rc = -EACCES;1751 goto out_err;1752 } else {1753 sess = ksmbd_session_lookup(conn,1754 le64_to_cpu(req->hdr.SessionId));1755 if (!sess) {1756 rc = -ENOENT;1757 goto out_err;1758 }1759 1760 if (sess->state == SMB2_SESSION_EXPIRED) {1761 rc = -EFAULT;1762 goto out_err;1763 }1764 1765 if (ksmbd_conn_need_reconnect(conn)) {1766 rc = -EFAULT;1767 sess = NULL;1768 goto out_err;1769 }1770 1771 conn->binding = false;1772 ksmbd_user_session_get(sess);1773 }1774 work->sess = sess;1775 1776 negblob_off = le16_to_cpu(req->SecurityBufferOffset);1777 negblob_len = le16_to_cpu(req->SecurityBufferLength);1778 if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer)) {1779 rc = -EINVAL;1780 goto out_err;1781 }1782 1783 negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +1784 negblob_off);1785 1786 if (decode_negotiation_token(conn, negblob, negblob_len) == 0) {1787 if (conn->mechToken) {1788 negblob = (struct negotiate_message *)conn->mechToken;1789 negblob_len = conn->mechTokenLen;1790 }1791 }1792 1793 if (negblob_len < offsetof(struct negotiate_message, NegotiateFlags)) {1794 rc = -EINVAL;1795 goto out_err;1796 }1797 1798 if (server_conf.auth_mechs & conn->auth_mechs) {1799 rc = generate_preauth_hash(work);1800 if (rc)1801 goto out_err;1802 1803 if (conn->preferred_auth_mech &1804 (KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) {1805 rc = krb5_authenticate(work, req, rsp);1806 if (rc) {1807 rc = -EINVAL;1808 goto out_err;1809 }1810 1811 if (!ksmbd_conn_need_reconnect(conn)) {1812 ksmbd_conn_set_good(conn);1813 sess->state = SMB2_SESSION_VALID;1814 }1815 kfree(sess->Preauth_HashValue);1816 sess->Preauth_HashValue = NULL;1817 } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {1818 if (negblob->MessageType == NtLmNegotiate) {1819 rc = ntlm_negotiate(work, negblob, negblob_len, rsp);1820 if (rc)1821 goto out_err;1822 rsp->hdr.Status =1823 STATUS_MORE_PROCESSING_REQUIRED;1824 } else if (negblob->MessageType == NtLmAuthenticate) {1825 rc = ntlm_authenticate(work, req, rsp);1826 if (rc)1827 goto out_err;1828 1829 if (!ksmbd_conn_need_reconnect(conn)) {1830 ksmbd_conn_set_good(conn);1831 sess->state = SMB2_SESSION_VALID;1832 }1833 if (conn->binding) {1834 struct preauth_session *preauth_sess;1835 1836 preauth_sess =1837 ksmbd_preauth_session_lookup(conn, sess->id);1838 if (preauth_sess) {1839 list_del(&preauth_sess->preauth_entry);1840 kfree(preauth_sess);1841 }1842 }1843 kfree(sess->Preauth_HashValue);1844 sess->Preauth_HashValue = NULL;1845 } else {1846 pr_info_ratelimited("Unknown NTLMSSP message type : 0x%x\n",1847 le32_to_cpu(negblob->MessageType));1848 rc = -EINVAL;1849 }1850 } else {1851 /* TODO: need one more negotiation */1852 pr_err("Not support the preferred authentication\n");1853 rc = -EINVAL;1854 }1855 } else {1856 pr_err("Not support authentication\n");1857 rc = -EINVAL;1858 }1859 1860out_err:1861 if (rc == -EINVAL)1862 rsp->hdr.Status = STATUS_INVALID_PARAMETER;1863 else if (rc == -ENOENT)1864 rsp->hdr.Status = STATUS_USER_SESSION_DELETED;1865 else if (rc == -EACCES)1866 rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;1867 else if (rc == -EFAULT)1868 rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED;1869 else if (rc == -ENOMEM)1870 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;1871 else if (rc == -EOPNOTSUPP)1872 rsp->hdr.Status = STATUS_NOT_SUPPORTED;1873 else if (rc)1874 rsp->hdr.Status = STATUS_LOGON_FAILURE;1875 1876 if (conn->use_spnego && conn->mechToken) {1877 kfree(conn->mechToken);1878 conn->mechToken = NULL;1879 }1880 1881 if (rc < 0) {1882 /*1883 * SecurityBufferOffset should be set to zero1884 * in session setup error response.1885 */1886 rsp->SecurityBufferOffset = 0;1887 1888 if (sess) {1889 bool try_delay = false;1890 1891 /*1892 * To avoid dictionary attacks (repeated session setups rapidly sent) to1893 * connect to server, ksmbd make a delay of a 5 seconds on session setup1894 * failure to make it harder to send enough random connection requests1895 * to break into a server.1896 */1897 if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)1898 try_delay = true;1899 1900 sess->last_active = jiffies;1901 sess->state = SMB2_SESSION_EXPIRED;1902 if (try_delay) {1903 ksmbd_conn_set_need_reconnect(conn);1904 ssleep(5);1905 ksmbd_conn_set_need_negotiate(conn);1906 }1907 }1908 smb2_set_err_rsp(work);1909 } else {1910 unsigned int iov_len;1911 1912 if (rsp->SecurityBufferLength)1913 iov_len = offsetof(struct smb2_sess_setup_rsp, Buffer) +1914 le16_to_cpu(rsp->SecurityBufferLength);1915 else1916 iov_len = sizeof(struct smb2_sess_setup_rsp);1917 rc = ksmbd_iov_pin_rsp(work, rsp, iov_len);1918 if (rc)1919 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;1920 }1921 1922 ksmbd_conn_unlock(conn);1923 return rc;1924}1925 1926/**1927 * smb2_tree_connect() - handler for smb2 tree connect command1928 * @work: smb work containing smb request buffer1929 *1930 * Return: 0 on success, otherwise error1931 */1932int smb2_tree_connect(struct ksmbd_work *work)1933{1934 struct ksmbd_conn *conn = work->conn;1935 struct smb2_tree_connect_req *req;1936 struct smb2_tree_connect_rsp *rsp;1937 struct ksmbd_session *sess = work->sess;1938 char *treename = NULL, *name = NULL;1939 struct ksmbd_tree_conn_status status;1940 struct ksmbd_share_config *share = NULL;1941 int rc = -EINVAL;1942 1943 WORK_BUFFERS(work, req, rsp);1944 1945 treename = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->PathOffset),1946 le16_to_cpu(req->PathLength), true,1947 conn->local_nls);1948 if (IS_ERR(treename)) {1949 pr_err("treename is NULL\n");1950 status.ret = KSMBD_TREE_CONN_STATUS_ERROR;1951 goto out_err1;1952 }1953 1954 name = ksmbd_extract_sharename(conn->um, treename);1955 if (IS_ERR(name)) {1956 status.ret = KSMBD_TREE_CONN_STATUS_ERROR;1957 goto out_err1;1958 }1959 1960 ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n",1961 name, treename);1962 1963 status = ksmbd_tree_conn_connect(work, name);1964 if (status.ret == KSMBD_TREE_CONN_STATUS_OK)1965 rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id);1966 else1967 goto out_err1;1968 1969 share = status.tree_conn->share_conf;1970 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {1971 ksmbd_debug(SMB, "IPC share path request\n");1972 rsp->ShareType = SMB2_SHARE_TYPE_PIPE;1973 rsp->MaximalAccess = FILE_READ_DATA_LE | FILE_READ_EA_LE |1974 FILE_EXECUTE_LE | FILE_READ_ATTRIBUTES_LE |1975 FILE_DELETE_LE | FILE_READ_CONTROL_LE |1976 FILE_WRITE_DAC_LE | FILE_WRITE_OWNER_LE |1977 FILE_SYNCHRONIZE_LE;1978 } else {1979 rsp->ShareType = SMB2_SHARE_TYPE_DISK;1980 rsp->MaximalAccess = FILE_READ_DATA_LE | FILE_READ_EA_LE |1981 FILE_EXECUTE_LE | FILE_READ_ATTRIBUTES_LE;1982 if (test_tree_conn_flag(status.tree_conn,1983 KSMBD_TREE_CONN_FLAG_WRITABLE)) {1984 rsp->MaximalAccess |= FILE_WRITE_DATA_LE |1985 FILE_APPEND_DATA_LE | FILE_WRITE_EA_LE |1986 FILE_DELETE_LE | FILE_WRITE_ATTRIBUTES_LE |1987 FILE_DELETE_CHILD_LE | FILE_READ_CONTROL_LE |1988 FILE_WRITE_DAC_LE | FILE_WRITE_OWNER_LE |1989 FILE_SYNCHRONIZE_LE;1990 }1991 }1992 1993 status.tree_conn->maximal_access = le32_to_cpu(rsp->MaximalAccess);1994 if (conn->posix_ext_supported)1995 status.tree_conn->posix_extensions = true;1996 1997 write_lock(&sess->tree_conns_lock);1998 status.tree_conn->t_state = TREE_CONNECTED;1999 write_unlock(&sess->tree_conns_lock);2000 rsp->StructureSize = cpu_to_le16(16);2001out_err1:2002 if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share &&2003 test_share_config_flag(share,2004 KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY))2005 rsp->Capabilities = SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;2006 else2007 rsp->Capabilities = 0;2008 rsp->Reserved = 0;2009 /* default manual caching */2010 rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING;2011 2012 rc = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_tree_connect_rsp));2013 if (rc)2014 status.ret = KSMBD_TREE_CONN_STATUS_NOMEM;2015 2016 if (!IS_ERR(treename))2017 kfree(treename);2018 if (!IS_ERR(name))2019 kfree(name);2020 2021 switch (status.ret) {2022 case KSMBD_TREE_CONN_STATUS_OK:2023 rsp->hdr.Status = STATUS_SUCCESS;2024 rc = 0;2025 break;2026 case -ESTALE:2027 case -ENOENT:2028 case KSMBD_TREE_CONN_STATUS_NO_SHARE:2029 rsp->hdr.Status = STATUS_BAD_NETWORK_NAME;2030 break;2031 case -ENOMEM:2032 case KSMBD_TREE_CONN_STATUS_NOMEM:2033 rsp->hdr.Status = STATUS_NO_MEMORY;2034 break;2035 case KSMBD_TREE_CONN_STATUS_ERROR:2036 case KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS:2037 case KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS:2038 rsp->hdr.Status = STATUS_ACCESS_DENIED;2039 break;2040 case -EINVAL:2041 rsp->hdr.Status = STATUS_INVALID_PARAMETER;2042 break;2043 default:2044 rsp->hdr.Status = STATUS_ACCESS_DENIED;2045 }2046 2047 if (status.ret != KSMBD_TREE_CONN_STATUS_OK)2048 smb2_set_err_rsp(work);2049 2050 return rc;2051}2052 2053/**2054 * smb2_create_open_flags() - convert smb open flags to unix open flags2055 * @file_present: is file already present2056 * @access: file access flags2057 * @disposition: file disposition flags2058 * @may_flags: set with MAY_ flags2059 * @coptions: file creation options2060 * @mode: file mode2061 *2062 * Return: file open flags2063 */2064static int smb2_create_open_flags(bool file_present, __le32 access,2065 __le32 disposition,2066 int *may_flags,2067 __le32 coptions,2068 umode_t mode)2069{2070 int oflags = O_NONBLOCK | O_LARGEFILE;2071 2072 if (coptions & FILE_DIRECTORY_FILE_LE || S_ISDIR(mode)) {2073 access &= ~FILE_WRITE_DESIRE_ACCESS_LE;2074 ksmbd_debug(SMB, "Discard write access to a directory\n");2075 }2076 2077 if (access & FILE_READ_DESIRED_ACCESS_LE &&2078 access & FILE_WRITE_DESIRE_ACCESS_LE) {2079 oflags |= O_RDWR;2080 *may_flags = MAY_OPEN | MAY_READ | MAY_WRITE;2081 } else if (access & FILE_WRITE_DESIRE_ACCESS_LE) {2082 oflags |= O_WRONLY;2083 *may_flags = MAY_OPEN | MAY_WRITE;2084 } else {2085 oflags |= O_RDONLY;2086 *may_flags = MAY_OPEN | MAY_READ;2087 }2088 2089 if (access == FILE_READ_ATTRIBUTES_LE || S_ISBLK(mode) || S_ISCHR(mode))2090 oflags |= O_PATH;2091 2092 if (file_present) {2093 switch (disposition & FILE_CREATE_MASK_LE) {2094 case FILE_OPEN_LE:2095 case FILE_CREATE_LE:2096 break;2097 case FILE_SUPERSEDE_LE:2098 case FILE_OVERWRITE_LE:2099 case FILE_OVERWRITE_IF_LE:2100 oflags |= O_TRUNC;2101 break;2102 default:2103 break;2104 }2105 } else {2106 switch (disposition & FILE_CREATE_MASK_LE) {2107 case FILE_SUPERSEDE_LE:2108 case FILE_CREATE_LE:2109 case FILE_OPEN_IF_LE:2110 case FILE_OVERWRITE_IF_LE:2111 oflags |= O_CREAT;2112 break;2113 case FILE_OPEN_LE:2114 case FILE_OVERWRITE_LE:2115 oflags &= ~O_CREAT;2116 break;2117 default:2118 break;2119 }2120 }2121 2122 return oflags;2123}2124 2125/**2126 * smb2_tree_disconnect() - handler for smb tree connect request2127 * @work: smb work containing request buffer2128 *2129 * Return: 02130 */2131int smb2_tree_disconnect(struct ksmbd_work *work)2132{2133 struct smb2_tree_disconnect_rsp *rsp;2134 struct smb2_tree_disconnect_req *req;2135 struct ksmbd_session *sess = work->sess;2136 struct ksmbd_tree_connect *tcon = work->tcon;2137 int err;2138 2139 WORK_BUFFERS(work, req, rsp);2140 2141 ksmbd_debug(SMB, "request\n");2142 2143 if (!tcon) {2144 ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);2145 2146 rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;2147 err = -ENOENT;2148 goto err_out;2149 }2150 2151 ksmbd_close_tree_conn_fds(work);2152 2153 write_lock(&sess->tree_conns_lock);2154 if (tcon->t_state == TREE_DISCONNECTED) {2155 write_unlock(&sess->tree_conns_lock);2156 rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;2157 err = -ENOENT;2158 goto err_out;2159 }2160 2161 WARN_ON_ONCE(atomic_dec_and_test(&tcon->refcount));2162 tcon->t_state = TREE_DISCONNECTED;2163 write_unlock(&sess->tree_conns_lock);2164 2165 err = ksmbd_tree_conn_disconnect(sess, tcon);2166 if (err) {2167 rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;2168 goto err_out;2169 }2170 2171 work->tcon = NULL;2172 2173 rsp->StructureSize = cpu_to_le16(4);2174 err = ksmbd_iov_pin_rsp(work, rsp,2175 sizeof(struct smb2_tree_disconnect_rsp));2176 if (err) {2177 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;2178 goto err_out;2179 }2180 2181 return 0;2182 2183err_out:2184 smb2_set_err_rsp(work);2185 return err;2186 2187}2188 2189/**2190 * smb2_session_logoff() - handler for session log off request2191 * @work: smb work containing request buffer2192 *2193 * Return: 02194 */2195int smb2_session_logoff(struct ksmbd_work *work)2196{2197 struct ksmbd_conn *conn = work->conn;2198 struct smb2_logoff_req *req;2199 struct smb2_logoff_rsp *rsp;2200 struct ksmbd_session *sess;2201 u64 sess_id;2202 int err;2203 2204 WORK_BUFFERS(work, req, rsp);2205 2206 ksmbd_debug(SMB, "request\n");2207 2208 ksmbd_conn_lock(conn);2209 if (!ksmbd_conn_good(conn)) {2210 ksmbd_conn_unlock(conn);2211 rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;2212 smb2_set_err_rsp(work);2213 return -ENOENT;2214 }2215 sess_id = le64_to_cpu(req->hdr.SessionId);2216 ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT);2217 ksmbd_conn_unlock(conn);2218 2219 ksmbd_close_session_fds(work);2220 ksmbd_conn_wait_idle(conn);2221 2222 /*2223 * Re-lookup session to validate if session is deleted2224 * while waiting request complete2225 */2226 sess = ksmbd_session_lookup_all(conn, sess_id);2227 if (ksmbd_tree_conn_session_logoff(sess)) {2228 ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);2229 rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;2230 smb2_set_err_rsp(work);2231 return -ENOENT;2232 }2233 2234 ksmbd_destroy_file_table(&sess->file_table);2235 down_write(&conn->session_lock);2236 sess->state = SMB2_SESSION_EXPIRED;2237 up_write(&conn->session_lock);2238 2239 ksmbd_free_user(sess->user);2240 sess->user = NULL;2241 ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);2242 2243 rsp->StructureSize = cpu_to_le16(4);2244 err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));2245 if (err) {2246 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;2247 smb2_set_err_rsp(work);2248 return err;2249 }2250 return 0;2251}2252 2253/**2254 * create_smb2_pipe() - create IPC pipe2255 * @work: smb work containing request buffer2256 *2257 * Return: 0 on success, otherwise error2258 */2259static noinline int create_smb2_pipe(struct ksmbd_work *work)2260{2261 struct smb2_create_rsp *rsp;2262 struct smb2_create_req *req;2263 int id;2264 int err;2265 char *name;2266 2267 WORK_BUFFERS(work, req, rsp);2268 2269 name = smb_strndup_from_utf16(req->Buffer, le16_to_cpu(req->NameLength),2270 1, work->conn->local_nls);2271 if (IS_ERR(name)) {2272 rsp->hdr.Status = STATUS_NO_MEMORY;2273 err = PTR_ERR(name);2274 goto out;2275 }2276 2277 id = ksmbd_session_rpc_open(work->sess, name);2278 if (id < 0) {2279 pr_err("Unable to open RPC pipe: %d\n", id);2280 err = id;2281 goto out;2282 }2283 2284 rsp->hdr.Status = STATUS_SUCCESS;2285 rsp->StructureSize = cpu_to_le16(89);2286 rsp->OplockLevel = SMB2_OPLOCK_LEVEL_NONE;2287 rsp->Flags = 0;2288 rsp->CreateAction = cpu_to_le32(FILE_OPENED);2289 2290 rsp->CreationTime = cpu_to_le64(0);2291 rsp->LastAccessTime = cpu_to_le64(0);2292 rsp->ChangeTime = cpu_to_le64(0);2293 rsp->AllocationSize = cpu_to_le64(0);2294 rsp->EndofFile = cpu_to_le64(0);2295 rsp->FileAttributes = FILE_ATTRIBUTE_NORMAL_LE;2296 rsp->Reserved2 = 0;2297 rsp->VolatileFileId = id;2298 rsp->PersistentFileId = 0;2299 rsp->CreateContextsOffset = 0;2300 rsp->CreateContextsLength = 0;2301 2302 err = ksmbd_iov_pin_rsp(work, rsp, offsetof(struct smb2_create_rsp, Buffer));2303 if (err)2304 goto out;2305 2306 kfree(name);2307 return 0;2308 2309out:2310 switch (err) {2311 case -EINVAL:2312 rsp->hdr.Status = STATUS_INVALID_PARAMETER;2313 break;2314 case -ENOSPC:2315 case -ENOMEM:2316 rsp->hdr.Status = STATUS_NO_MEMORY;2317 break;2318 }2319 2320 if (!IS_ERR(name))2321 kfree(name);2322 2323 smb2_set_err_rsp(work);2324 return err;2325}2326 2327/**2328 * smb2_set_ea() - handler for setting extended attributes using set2329 * info command2330 * @eabuf: set info command buffer2331 * @buf_len: set info command buffer length2332 * @path: dentry path for get ea2333 * @get_write: get write access to a mount2334 *2335 * Return: 0 on success, otherwise error2336 */2337static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,2338 const struct path *path, bool get_write)2339{2340 struct mnt_idmap *idmap = mnt_idmap(path->mnt);2341 char *attr_name = NULL, *value;2342 int rc = 0;2343 unsigned int next = 0;2344 2345 if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength +2346 le16_to_cpu(eabuf->EaValueLength))2347 return -EINVAL;2348 2349 attr_name = kmalloc(XATTR_NAME_MAX + 1, GFP_KERNEL);2350 if (!attr_name)2351 return -ENOMEM;2352 2353 do {2354 if (!eabuf->EaNameLength)2355 goto next;2356 2357 ksmbd_debug(SMB,2358 "name : <%s>, name_len : %u, value_len : %u, next : %u\n",2359 eabuf->name, eabuf->EaNameLength,2360 le16_to_cpu(eabuf->EaValueLength),2361 le32_to_cpu(eabuf->NextEntryOffset));2362 2363 if (eabuf->EaNameLength >2364 (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) {2365 rc = -EINVAL;2366 break;2367 }2368 2369 memcpy(attr_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);2370 memcpy(&attr_name[XATTR_USER_PREFIX_LEN], eabuf->name,2371 eabuf->EaNameLength);2372 attr_name[XATTR_USER_PREFIX_LEN + eabuf->EaNameLength] = '\0';2373 value = (char *)&eabuf->name + eabuf->EaNameLength + 1;2374 2375 if (!eabuf->EaValueLength) {2376 rc = ksmbd_vfs_casexattr_len(idmap,2377 path->dentry,2378 attr_name,2379 XATTR_USER_PREFIX_LEN +2380 eabuf->EaNameLength);2381 2382 /* delete the EA only when it exits */2383 if (rc > 0) {2384 rc = ksmbd_vfs_remove_xattr(idmap,2385 path,2386 attr_name,2387 get_write);2388 2389 if (rc < 0) {2390 ksmbd_debug(SMB,2391 "remove xattr failed(%d)\n",2392 rc);2393 break;2394 }2395 }2396 2397 /* if the EA doesn't exist, just do nothing. */2398 rc = 0;2399 } else {2400 rc = ksmbd_vfs_setxattr(idmap, path, attr_name, value,2401 le16_to_cpu(eabuf->EaValueLength),2402 0, get_write);2403 if (rc < 0) {2404 ksmbd_debug(SMB,2405 "ksmbd_vfs_setxattr is failed(%d)\n",2406 rc);2407 break;2408 }2409 }2410 2411next:2412 next = le32_to_cpu(eabuf->NextEntryOffset);2413 if (next == 0 || buf_len < next)2414 break;2415 buf_len -= next;2416 eabuf = (struct smb2_ea_info *)((char *)eabuf + next);2417 if (buf_len < sizeof(struct smb2_ea_info)) {2418 rc = -EINVAL;2419 break;2420 }2421 2422 if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength +2423 le16_to_cpu(eabuf->EaValueLength)) {2424 rc = -EINVAL;2425 break;2426 }2427 } while (next != 0);2428 2429 kfree(attr_name);2430 return rc;2431}2432 2433static noinline int smb2_set_stream_name_xattr(const struct path *path,2434 struct ksmbd_file *fp,2435 char *stream_name, int s_type)2436{2437 struct mnt_idmap *idmap = mnt_idmap(path->mnt);2438 size_t xattr_stream_size;2439 char *xattr_stream_name;2440 int rc;2441 2442 rc = ksmbd_vfs_xattr_stream_name(stream_name,2443 &xattr_stream_name,2444 &xattr_stream_size,2445 s_type);2446 if (rc)2447 return rc;2448 2449 fp->stream.name = xattr_stream_name;2450 fp->stream.size = xattr_stream_size;2451 2452 /* Check if there is stream prefix in xattr space */2453 rc = ksmbd_vfs_casexattr_len(idmap,2454 path->dentry,2455 xattr_stream_name,2456 xattr_stream_size);2457 if (rc >= 0)2458 return 0;2459 2460 if (fp->cdoption == FILE_OPEN_LE) {2461 ksmbd_debug(SMB, "XATTR stream name lookup failed: %d\n", rc);2462 return -EBADF;2463 }2464 2465 rc = ksmbd_vfs_setxattr(idmap, path, xattr_stream_name, NULL, 0, 0, false);2466 if (rc < 0)2467 pr_err("Failed to store XATTR stream name :%d\n", rc);2468 return 0;2469}2470 2471static int smb2_remove_smb_xattrs(const struct path *path)2472{2473 struct mnt_idmap *idmap = mnt_idmap(path->mnt);2474 char *name, *xattr_list = NULL;2475 ssize_t xattr_list_len;2476 int err = 0;2477 2478 xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);2479 if (xattr_list_len < 0) {2480 goto out;2481 } else if (!xattr_list_len) {2482 ksmbd_debug(SMB, "empty xattr in the file\n");2483 goto out;2484 }2485 2486 for (name = xattr_list; name - xattr_list < xattr_list_len;2487 name += strlen(name) + 1) {2488 ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));2489 2490 if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&2491 !strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,2492 STREAM_PREFIX_LEN)) {2493 err = ksmbd_vfs_remove_xattr(idmap, path,2494 name, true);2495 if (err)2496 ksmbd_debug(SMB, "remove xattr failed : %s\n",2497 name);2498 }2499 }2500out:2501 kvfree(xattr_list);2502 return err;2503}2504 2505static int smb2_create_truncate(const struct path *path)2506{2507 int rc = vfs_truncate(path, 0);2508 2509 if (rc) {2510 pr_err("vfs_truncate failed, rc %d\n", rc);2511 return rc;2512 }2513 2514 rc = smb2_remove_smb_xattrs(path);2515 if (rc == -EOPNOTSUPP)2516 rc = 0;2517 if (rc)2518 ksmbd_debug(SMB,2519 "ksmbd_truncate_stream_name_xattr failed, rc %d\n",2520 rc);2521 return rc;2522}2523 2524static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *path,2525 struct ksmbd_file *fp)2526{2527 struct xattr_dos_attrib da = {0};2528 int rc;2529 2530 if (!test_share_config_flag(tcon->share_conf,2531 KSMBD_SHARE_FLAG_STORE_DOS_ATTRS))2532 return;2533 2534 da.version = 4;2535 da.attr = le32_to_cpu(fp->f_ci->m_fattr);2536 da.itime = da.create_time = fp->create_time;2537 da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |2538 XATTR_DOSINFO_ITIME;2539 2540 rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt), path, &da, true);2541 if (rc)2542 ksmbd_debug(SMB, "failed to store file attribute into xattr\n");2543}2544 2545static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon,2546 const struct path *path, struct ksmbd_file *fp)2547{2548 struct xattr_dos_attrib da;2549 int rc;2550 2551 fp->f_ci->m_fattr &= ~(FILE_ATTRIBUTE_HIDDEN_LE | FILE_ATTRIBUTE_SYSTEM_LE);2552 2553 /* get FileAttributes from XATTR_NAME_DOS_ATTRIBUTE */2554 if (!test_share_config_flag(tcon->share_conf,2555 KSMBD_SHARE_FLAG_STORE_DOS_ATTRS))2556 return;2557 2558 rc = ksmbd_vfs_get_dos_attrib_xattr(mnt_idmap(path->mnt),2559 path->dentry, &da);2560 if (rc > 0) {2561 fp->f_ci->m_fattr = cpu_to_le32(da.attr);2562 fp->create_time = da.create_time;2563 fp->itime = da.itime;2564 }2565}2566 2567static int smb2_creat(struct ksmbd_work *work, struct path *parent_path,2568 struct path *path, char *name, int open_flags,2569 umode_t posix_mode, bool is_dir)2570{2571 struct ksmbd_tree_connect *tcon = work->tcon;2572 struct ksmbd_share_config *share = tcon->share_conf;2573 umode_t mode;2574 int rc;2575 2576 if (!(open_flags & O_CREAT))2577 return -EBADF;2578 2579 ksmbd_debug(SMB, "file does not exist, so creating\n");2580 if (is_dir == true) {2581 ksmbd_debug(SMB, "creating directory\n");2582 2583 mode = share_config_directory_mode(share, posix_mode);2584 rc = ksmbd_vfs_mkdir(work, name, mode);2585 if (rc)2586 return rc;2587 } else {2588 ksmbd_debug(SMB, "creating regular file\n");2589 2590 mode = share_config_create_mode(share, posix_mode);2591 rc = ksmbd_vfs_create(work, name, mode);2592 if (rc)2593 return rc;2594 }2595 2596 rc = ksmbd_vfs_kern_path_locked(work, name, 0, parent_path, path, 0);2597 if (rc) {2598 pr_err("cannot get linux path (%s), err = %d\n",2599 name, rc);2600 return rc;2601 }2602 return 0;2603}2604 2605static int smb2_create_sd_buffer(struct ksmbd_work *work,2606 struct smb2_create_req *req,2607 const struct path *path)2608{2609 struct create_context *context;2610 struct create_sd_buf_req *sd_buf;2611 2612 if (!req->CreateContextsOffset)2613 return -ENOENT;2614 2615 /* Parse SD BUFFER create contexts */2616 context = smb2_find_context_vals(req, SMB2_CREATE_SD_BUFFER, 4);2617 if (!context)2618 return -ENOENT;2619 else if (IS_ERR(context))2620 return PTR_ERR(context);2621 2622 ksmbd_debug(SMB,2623 "Set ACLs using SMB2_CREATE_SD_BUFFER context\n");2624 sd_buf = (struct create_sd_buf_req *)context;2625 if (le16_to_cpu(context->DataOffset) +2626 le32_to_cpu(context->DataLength) <2627 sizeof(struct create_sd_buf_req))2628 return -EINVAL;2629 return set_info_sec(work->conn, work->tcon, path, &sd_buf->ntsd,2630 le32_to_cpu(sd_buf->ccontext.DataLength), true, false);2631}2632 2633static void ksmbd_acls_fattr(struct smb_fattr *fattr,2634 struct mnt_idmap *idmap,2635 struct inode *inode)2636{2637 vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);2638 vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);2639 2640 fattr->cf_uid = vfsuid_into_kuid(vfsuid);2641 fattr->cf_gid = vfsgid_into_kgid(vfsgid);2642 fattr->cf_mode = inode->i_mode;2643 fattr->cf_acls = NULL;2644 fattr->cf_dacls = NULL;2645 2646 if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {2647 fattr->cf_acls = get_inode_acl(inode, ACL_TYPE_ACCESS);2648 if (S_ISDIR(inode->i_mode))2649 fattr->cf_dacls = get_inode_acl(inode, ACL_TYPE_DEFAULT);2650 }2651}2652 2653enum {2654 DURABLE_RECONN_V2 = 1,2655 DURABLE_RECONN,2656 DURABLE_REQ_V2,2657 DURABLE_REQ,2658};2659 2660struct durable_info {2661 struct ksmbd_file *fp;2662 unsigned short int type;2663 bool persistent;2664 bool reconnected;2665 unsigned int timeout;2666 char *CreateGuid;2667};2668 2669static int parse_durable_handle_context(struct ksmbd_work *work,2670 struct smb2_create_req *req,2671 struct lease_ctx_info *lc,2672 struct durable_info *dh_info)2673{2674 struct ksmbd_conn *conn = work->conn;2675 struct create_context *context;2676 int dh_idx, err = 0;2677 u64 persistent_id = 0;2678 int req_op_level;2679 static const char * const durable_arr[] = {"DH2C", "DHnC", "DH2Q", "DHnQ"};2680 2681 req_op_level = req->RequestedOplockLevel;2682 for (dh_idx = DURABLE_RECONN_V2; dh_idx <= ARRAY_SIZE(durable_arr);2683 dh_idx++) {2684 context = smb2_find_context_vals(req, durable_arr[dh_idx - 1], 4);2685 if (IS_ERR(context)) {2686 err = PTR_ERR(context);2687 goto out;2688 }2689 if (!context)2690 continue;2691 2692 switch (dh_idx) {2693 case DURABLE_RECONN_V2:2694 {2695 struct create_durable_reconn_v2_req *recon_v2;2696 2697 if (dh_info->type == DURABLE_RECONN ||2698 dh_info->type == DURABLE_REQ_V2) {2699 err = -EINVAL;2700 goto out;2701 }2702 2703 recon_v2 = (struct create_durable_reconn_v2_req *)context;2704 persistent_id = recon_v2->Fid.PersistentFileId;2705 dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);2706 if (!dh_info->fp) {2707 ksmbd_debug(SMB, "Failed to get durable handle state\n");2708 err = -EBADF;2709 goto out;2710 }2711 2712 if (memcmp(dh_info->fp->create_guid, recon_v2->CreateGuid,2713 SMB2_CREATE_GUID_SIZE)) {2714 err = -EBADF;2715 ksmbd_put_durable_fd(dh_info->fp);2716 goto out;2717 }2718 2719 dh_info->type = dh_idx;2720 dh_info->reconnected = true;2721 ksmbd_debug(SMB,2722 "reconnect v2 Persistent-id from reconnect = %llu\n",2723 persistent_id);2724 break;2725 }2726 case DURABLE_RECONN:2727 {2728 struct create_durable_reconn_req *recon;2729 2730 if (dh_info->type == DURABLE_RECONN_V2 ||2731 dh_info->type == DURABLE_REQ_V2) {2732 err = -EINVAL;2733 goto out;2734 }2735 2736 recon = (struct create_durable_reconn_req *)context;2737 persistent_id = recon->Data.Fid.PersistentFileId;2738 dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);2739 if (!dh_info->fp) {2740 ksmbd_debug(SMB, "Failed to get durable handle state\n");2741 err = -EBADF;2742 goto out;2743 }2744 2745 dh_info->type = dh_idx;2746 dh_info->reconnected = true;2747 ksmbd_debug(SMB, "reconnect Persistent-id from reconnect = %llu\n",2748 persistent_id);2749 break;2750 }2751 case DURABLE_REQ_V2:2752 {2753 struct create_durable_req_v2 *durable_v2_blob;2754 2755 if (dh_info->type == DURABLE_RECONN ||2756 dh_info->type == DURABLE_RECONN_V2) {2757 err = -EINVAL;2758 goto out;2759 }2760 2761 durable_v2_blob =2762 (struct create_durable_req_v2 *)context;2763 ksmbd_debug(SMB, "Request for durable v2 open\n");2764 dh_info->fp = ksmbd_lookup_fd_cguid(durable_v2_blob->CreateGuid);2765 if (dh_info->fp) {2766 if (!memcmp(conn->ClientGUID, dh_info->fp->client_guid,2767 SMB2_CLIENT_GUID_SIZE)) {2768 if (!(req->hdr.Flags & SMB2_FLAGS_REPLAY_OPERATION)) {2769 err = -ENOEXEC;2770 goto out;2771 }2772 2773 dh_info->fp->conn = conn;2774 dh_info->reconnected = true;2775 goto out;2776 }2777 }2778 2779 if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) ||2780 req_op_level == SMB2_OPLOCK_LEVEL_BATCH) {2781 dh_info->CreateGuid =2782 durable_v2_blob->CreateGuid;2783 dh_info->persistent =2784 le32_to_cpu(durable_v2_blob->Flags);2785 dh_info->timeout =2786 le32_to_cpu(durable_v2_blob->Timeout);2787 dh_info->type = dh_idx;2788 }2789 break;2790 }2791 case DURABLE_REQ:2792 if (dh_info->type == DURABLE_RECONN)2793 goto out;2794 if (dh_info->type == DURABLE_RECONN_V2 ||2795 dh_info->type == DURABLE_REQ_V2) {2796 err = -EINVAL;2797 goto out;2798 }2799 2800 if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) ||2801 req_op_level == SMB2_OPLOCK_LEVEL_BATCH) {2802 ksmbd_debug(SMB, "Request for durable open\n");2803 dh_info->type = dh_idx;2804 }2805 }2806 }2807 2808out:2809 return err;2810}2811 2812/**2813 * smb2_open() - handler for smb file open request2814 * @work: smb work containing request buffer2815 *2816 * Return: 0 on success, otherwise error2817 */2818int smb2_open(struct ksmbd_work *work)2819{2820 struct ksmbd_conn *conn = work->conn;2821 struct ksmbd_session *sess = work->sess;2822 struct ksmbd_tree_connect *tcon = work->tcon;2823 struct smb2_create_req *req;2824 struct smb2_create_rsp *rsp;2825 struct path path, parent_path;2826 struct ksmbd_share_config *share = tcon->share_conf;2827 struct ksmbd_file *fp = NULL;2828 struct file *filp = NULL;2829 struct mnt_idmap *idmap = NULL;2830 struct kstat stat;2831 struct create_context *context;2832 struct lease_ctx_info *lc = NULL;2833 struct create_ea_buf_req *ea_buf = NULL;2834 struct oplock_info *opinfo;2835 struct durable_info dh_info = {0};2836 __le32 *next_ptr = NULL;2837 int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0;2838 int rc = 0;2839 int contxt_cnt = 0, query_disk_id = 0;2840 int maximal_access_ctxt = 0, posix_ctxt = 0;2841 int s_type = 0;2842 int next_off = 0;2843 char *name = NULL;2844 char *stream_name = NULL;2845 bool file_present = false, created = false, already_permitted = false;2846 int share_ret, need_truncate = 0;2847 u64 time;2848 umode_t posix_mode = 0;2849 __le32 daccess, maximal_access = 0;2850 int iov_len = 0;2851 2852 WORK_BUFFERS(work, req, rsp);2853 2854 if (req->hdr.NextCommand && !work->next_smb2_rcv_hdr_off &&2855 (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS)) {2856 ksmbd_debug(SMB, "invalid flag in chained command\n");2857 rsp->hdr.Status = STATUS_INVALID_PARAMETER;2858 smb2_set_err_rsp(work);2859 return -EINVAL;2860 }2861 2862 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {2863 ksmbd_debug(SMB, "IPC pipe create request\n");2864 return create_smb2_pipe(work);2865 }2866 2867 if (req->NameLength) {2868 name = smb2_get_name((char *)req + le16_to_cpu(req->NameOffset),2869 le16_to_cpu(req->NameLength),2870 work->conn->local_nls);2871 if (IS_ERR(name)) {2872 rc = PTR_ERR(name);2873 name = NULL;2874 goto err_out2;2875 }2876 2877 ksmbd_debug(SMB, "converted name = %s\n", name);2878 if (strchr(name, ':')) {2879 if (!test_share_config_flag(work->tcon->share_conf,2880 KSMBD_SHARE_FLAG_STREAMS)) {2881 rc = -EBADF;2882 goto err_out2;2883 }2884 rc = parse_stream_name(name, &stream_name, &s_type);2885 if (rc < 0)2886 goto err_out2;2887 }2888 2889 rc = ksmbd_validate_filename(name);2890 if (rc < 0)2891 goto err_out2;2892 2893 if (ksmbd_share_veto_filename(share, name)) {2894 rc = -ENOENT;2895 ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n",2896 name);2897 goto err_out2;2898 }2899 } else {2900 name = kstrdup("", GFP_KERNEL);2901 if (!name) {2902 rc = -ENOMEM;2903 goto err_out2;2904 }2905 }2906 2907 req_op_level = req->RequestedOplockLevel;2908 2909 if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE &&2910 req->CreateContextsOffset) {2911 lc = parse_lease_state(req);2912 rc = parse_durable_handle_context(work, req, lc, &dh_info);2913 if (rc) {2914 ksmbd_debug(SMB, "error parsing durable handle context\n");2915 goto err_out2;2916 }2917 2918 if (dh_info.reconnected == true) {2919 rc = smb2_check_durable_oplock(conn, share, dh_info.fp, lc, name);2920 if (rc) {2921 ksmbd_put_durable_fd(dh_info.fp);2922 goto err_out2;2923 }2924 2925 rc = ksmbd_reopen_durable_fd(work, dh_info.fp);2926 if (rc) {2927 ksmbd_put_durable_fd(dh_info.fp);2928 goto err_out2;2929 }2930 2931 if (ksmbd_override_fsids(work)) {2932 rc = -ENOMEM;2933 ksmbd_put_durable_fd(dh_info.fp);2934 goto err_out2;2935 }2936 2937 fp = dh_info.fp;2938 file_info = FILE_OPENED;2939 2940 rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat);2941 if (rc)2942 goto err_out2;2943 2944 ksmbd_put_durable_fd(fp);2945 goto reconnected_fp;2946 }2947 } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)2948 lc = parse_lease_state(req);2949 2950 if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) {2951 pr_err("Invalid impersonationlevel : 0x%x\n",2952 le32_to_cpu(req->ImpersonationLevel));2953 rc = -EIO;2954 rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL;2955 goto err_out2;2956 }2957 2958 if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK_LE)) {2959 pr_err("Invalid create options : 0x%x\n",2960 le32_to_cpu(req->CreateOptions));2961 rc = -EINVAL;2962 goto err_out2;2963 } else {2964 if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE &&2965 req->CreateOptions & FILE_RANDOM_ACCESS_LE)2966 req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE);2967 2968 if (req->CreateOptions &2969 (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION |2970 FILE_RESERVE_OPFILTER_LE)) {2971 rc = -EOPNOTSUPP;2972 goto err_out2;2973 }2974 2975 if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {2976 if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) {2977 rc = -EINVAL;2978 goto err_out2;2979 } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) {2980 req->CreateOptions = ~(FILE_NO_COMPRESSION_LE);2981 }2982 }2983 }2984 2985 if (le32_to_cpu(req->CreateDisposition) >2986 le32_to_cpu(FILE_OVERWRITE_IF_LE)) {2987 pr_err("Invalid create disposition : 0x%x\n",2988 le32_to_cpu(req->CreateDisposition));2989 rc = -EINVAL;2990 goto err_out2;2991 }2992 2993 if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) {2994 pr_err("Invalid desired access : 0x%x\n",2995 le32_to_cpu(req->DesiredAccess));2996 rc = -EACCES;2997 goto err_out2;2998 }2999 3000 if (req->FileAttributes && !(req->FileAttributes & FILE_ATTRIBUTE_MASK_LE)) {3001 pr_err("Invalid file attribute : 0x%x\n",3002 le32_to_cpu(req->FileAttributes));3003 rc = -EINVAL;3004 goto err_out2;3005 }3006 3007 if (req->CreateContextsOffset) {3008 /* Parse non-durable handle create contexts */3009 context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER, 4);3010 if (IS_ERR(context)) {3011 rc = PTR_ERR(context);3012 goto err_out2;3013 } else if (context) {3014 ea_buf = (struct create_ea_buf_req *)context;3015 if (le16_to_cpu(context->DataOffset) +3016 le32_to_cpu(context->DataLength) <3017 sizeof(struct create_ea_buf_req)) {3018 rc = -EINVAL;3019 goto err_out2;3020 }3021 if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) {3022 rsp->hdr.Status = STATUS_ACCESS_DENIED;3023 rc = -EACCES;3024 goto err_out2;3025 }3026 }3027 3028 context = smb2_find_context_vals(req,3029 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST, 4);3030 if (IS_ERR(context)) {3031 rc = PTR_ERR(context);3032 goto err_out2;3033 } else if (context) {3034 ksmbd_debug(SMB,3035 "get query maximal access context\n");3036 maximal_access_ctxt = 1;3037 }3038 3039 context = smb2_find_context_vals(req,3040 SMB2_CREATE_TIMEWARP_REQUEST, 4);3041 if (IS_ERR(context)) {3042 rc = PTR_ERR(context);3043 goto err_out2;3044 } else if (context) {3045 ksmbd_debug(SMB, "get timewarp context\n");3046 rc = -EBADF;3047 goto err_out2;3048 }3049 3050 if (tcon->posix_extensions) {3051 context = smb2_find_context_vals(req,3052 SMB2_CREATE_TAG_POSIX, 16);3053 if (IS_ERR(context)) {3054 rc = PTR_ERR(context);3055 goto err_out2;3056 } else if (context) {3057 struct create_posix *posix =3058 (struct create_posix *)context;3059 if (le16_to_cpu(context->DataOffset) +3060 le32_to_cpu(context->DataLength) <3061 sizeof(struct create_posix) - 4) {3062 rc = -EINVAL;3063 goto err_out2;3064 }3065 ksmbd_debug(SMB, "get posix context\n");3066 3067 posix_mode = le32_to_cpu(posix->Mode);3068 posix_ctxt = 1;3069 }3070 }3071 }3072 3073 if (ksmbd_override_fsids(work)) {3074 rc = -ENOMEM;3075 goto err_out2;3076 }3077 3078 rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS,3079 &parent_path, &path, 1);3080 if (!rc) {3081 file_present = true;3082 3083 if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {3084 /*3085 * If file exists with under flags, return access3086 * denied error.3087 */3088 if (req->CreateDisposition == FILE_OVERWRITE_IF_LE ||3089 req->CreateDisposition == FILE_OPEN_IF_LE) {3090 rc = -EACCES;3091 goto err_out;3092 }3093 3094 if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {3095 ksmbd_debug(SMB,3096 "User does not have write permission\n");3097 rc = -EACCES;3098 goto err_out;3099 }3100 } else if (d_is_symlink(path.dentry)) {3101 rc = -EACCES;3102 goto err_out;3103 }3104 3105 idmap = mnt_idmap(path.mnt);3106 } else {3107 if (rc != -ENOENT)3108 goto err_out;3109 ksmbd_debug(SMB, "can not get linux path for %s, rc = %d\n",3110 name, rc);3111 rc = 0;3112 }3113 3114 if (stream_name) {3115 if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {3116 if (s_type == DATA_STREAM) {3117 rc = -EIO;3118 rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;3119 }3120 } else {3121 if (file_present && S_ISDIR(d_inode(path.dentry)->i_mode) &&3122 s_type == DATA_STREAM) {3123 rc = -EIO;3124 rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;3125 }3126 }3127 3128 if (req->CreateOptions & FILE_DIRECTORY_FILE_LE &&3129 req->FileAttributes & FILE_ATTRIBUTE_NORMAL_LE) {3130 rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;3131 rc = -EIO;3132 }3133 3134 if (rc < 0)3135 goto err_out;3136 }3137 3138 if (file_present && req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE &&3139 S_ISDIR(d_inode(path.dentry)->i_mode) &&3140 !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {3141 ksmbd_debug(SMB, "open() argument is a directory: %s, %x\n",3142 name, req->CreateOptions);3143 rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;3144 rc = -EIO;3145 goto err_out;3146 }3147 3148 if (file_present && (req->CreateOptions & FILE_DIRECTORY_FILE_LE) &&3149 !(req->CreateDisposition == FILE_CREATE_LE) &&3150 !S_ISDIR(d_inode(path.dentry)->i_mode)) {3151 rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;3152 rc = -EIO;3153 goto err_out;3154 }3155 3156 if (!stream_name && file_present &&3157 req->CreateDisposition == FILE_CREATE_LE) {3158 rc = -EEXIST;3159 goto err_out;3160 }3161 3162 daccess = smb_map_generic_desired_access(req->DesiredAccess);3163 3164 if (file_present && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {3165 rc = smb_check_perm_dacl(conn, &path, &daccess,3166 sess->user->uid);3167 if (rc)3168 goto err_out;3169 }3170 3171 if (daccess & FILE_MAXIMAL_ACCESS_LE) {3172 if (!file_present) {3173 daccess = cpu_to_le32(GENERIC_ALL_FLAGS);3174 } else {3175 ksmbd_vfs_query_maximal_access(idmap,3176 path.dentry,3177 &daccess);3178 already_permitted = true;3179 }3180 maximal_access = daccess;3181 }3182 3183 open_flags = smb2_create_open_flags(file_present, daccess,3184 req->CreateDisposition,3185 &may_flags,3186 req->CreateOptions,3187 file_present ? d_inode(path.dentry)->i_mode : 0);3188 3189 if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {3190 if (open_flags & (O_CREAT | O_TRUNC)) {3191 ksmbd_debug(SMB,3192 "User does not have write permission\n");3193 rc = -EACCES;3194 goto err_out;3195 }3196 }3197 3198 /*create file if not present */3199 if (!file_present) {3200 rc = smb2_creat(work, &parent_path, &path, name, open_flags,3201 posix_mode,3202 req->CreateOptions & FILE_DIRECTORY_FILE_LE);3203 if (rc) {3204 if (rc == -ENOENT) {3205 rc = -EIO;3206 rsp->hdr.Status = STATUS_OBJECT_PATH_NOT_FOUND;3207 }3208 goto err_out;3209 }3210 3211 created = true;3212 idmap = mnt_idmap(path.mnt);3213 if (ea_buf) {3214 if (le32_to_cpu(ea_buf->ccontext.DataLength) <3215 sizeof(struct smb2_ea_info)) {3216 rc = -EINVAL;3217 goto err_out;3218 }3219 3220 rc = smb2_set_ea(&ea_buf->ea,3221 le32_to_cpu(ea_buf->ccontext.DataLength),3222 &path, false);3223 if (rc == -EOPNOTSUPP)3224 rc = 0;3225 else if (rc)3226 goto err_out;3227 }3228 } else if (!already_permitted) {3229 /* FILE_READ_ATTRIBUTE is allowed without inode_permission,3230 * because execute(search) permission on a parent directory,3231 * is already granted.3232 */3233 if (daccess & ~(FILE_READ_ATTRIBUTES_LE | FILE_READ_CONTROL_LE)) {3234 rc = inode_permission(idmap,3235 d_inode(path.dentry),3236 may_flags);3237 if (rc)3238 goto err_out;3239 3240 if ((daccess & FILE_DELETE_LE) ||3241 (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {3242 rc = inode_permission(idmap,3243 d_inode(path.dentry->d_parent),3244 MAY_EXEC | MAY_WRITE);3245 if (rc)3246 goto err_out;3247 }3248 }3249 }3250 3251 rc = ksmbd_query_inode_status(path.dentry->d_parent);3252 if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) {3253 rc = -EBUSY;3254 goto err_out;3255 }3256 3257 rc = 0;3258 filp = dentry_open(&path, open_flags, current_cred());3259 if (IS_ERR(filp)) {3260 rc = PTR_ERR(filp);3261 pr_err("dentry open for dir failed, rc %d\n", rc);3262 goto err_out;3263 }3264 3265 if (file_present) {3266 if (!(open_flags & O_TRUNC))3267 file_info = FILE_OPENED;3268 else3269 file_info = FILE_OVERWRITTEN;3270 3271 if ((req->CreateDisposition & FILE_CREATE_MASK_LE) ==3272 FILE_SUPERSEDE_LE)3273 file_info = FILE_SUPERSEDED;3274 } else if (open_flags & O_CREAT) {3275 file_info = FILE_CREATED;3276 }3277 3278 ksmbd_vfs_set_fadvise(filp, req->CreateOptions);3279 3280 /* Obtain Volatile-ID */3281 fp = ksmbd_open_fd(work, filp);3282 if (IS_ERR(fp)) {3283 fput(filp);3284 rc = PTR_ERR(fp);3285 fp = NULL;3286 goto err_out;3287 }3288 3289 /* Get Persistent-ID */3290 ksmbd_open_durable_fd(fp);3291 if (!has_file_id(fp->persistent_id)) {3292 rc = -ENOMEM;3293 goto err_out;3294 }3295 3296 fp->cdoption = req->CreateDisposition;3297 fp->daccess = daccess;3298 fp->saccess = req->ShareAccess;3299 fp->coption = req->CreateOptions;3300 3301 /* Set default windows and posix acls if creating new file */3302 if (created) {3303 int posix_acl_rc;3304 struct inode *inode = d_inode(path.dentry);3305 3306 posix_acl_rc = ksmbd_vfs_inherit_posix_acl(idmap,3307 &path,3308 d_inode(path.dentry->d_parent));3309 if (posix_acl_rc)3310 ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);3311 3312 if (test_share_config_flag(work->tcon->share_conf,3313 KSMBD_SHARE_FLAG_ACL_XATTR)) {3314 rc = smb_inherit_dacl(conn, &path, sess->user->uid,3315 sess->user->gid);3316 }3317 3318 if (rc) {3319 rc = smb2_create_sd_buffer(work, req, &path);3320 if (rc) {3321 if (posix_acl_rc)3322 ksmbd_vfs_set_init_posix_acl(idmap,3323 &path);3324 3325 if (test_share_config_flag(work->tcon->share_conf,3326 KSMBD_SHARE_FLAG_ACL_XATTR)) {3327 struct smb_fattr fattr;3328 struct smb_ntsd *pntsd;3329 int pntsd_size, ace_num = 0;3330 3331 ksmbd_acls_fattr(&fattr, idmap, inode);3332 if (fattr.cf_acls)3333 ace_num = fattr.cf_acls->a_count;3334 if (fattr.cf_dacls)3335 ace_num += fattr.cf_dacls->a_count;3336 3337 pntsd = kmalloc(sizeof(struct smb_ntsd) +3338 sizeof(struct smb_sid) * 3 +3339 sizeof(struct smb_acl) +3340 sizeof(struct smb_ace) * ace_num * 2,3341 GFP_KERNEL);3342 if (!pntsd) {3343 posix_acl_release(fattr.cf_acls);3344 posix_acl_release(fattr.cf_dacls);3345 goto err_out;3346 }3347 3348 rc = build_sec_desc(idmap,3349 pntsd, NULL, 0,3350 OWNER_SECINFO |3351 GROUP_SECINFO |3352 DACL_SECINFO,3353 &pntsd_size, &fattr);3354 posix_acl_release(fattr.cf_acls);3355 posix_acl_release(fattr.cf_dacls);3356 if (rc) {3357 kfree(pntsd);3358 goto err_out;3359 }3360 3361 rc = ksmbd_vfs_set_sd_xattr(conn,3362 idmap,3363 &path,3364 pntsd,3365 pntsd_size,3366 false);3367 kfree(pntsd);3368 if (rc)3369 pr_err("failed to store ntacl in xattr : %d\n",3370 rc);3371 }3372 }3373 }3374 rc = 0;3375 }3376 3377 if (stream_name) {3378 rc = smb2_set_stream_name_xattr(&path,3379 fp,3380 stream_name,3381 s_type);3382 if (rc)3383 goto err_out;3384 file_info = FILE_CREATED;3385 }3386 3387 fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE |3388 FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE));3389 3390 /* fp should be searchable through ksmbd_inode.m_fp_list3391 * after daccess, saccess, attrib_only, and stream are3392 * initialized.3393 */3394 down_write(&fp->f_ci->m_lock);3395 list_add(&fp->node, &fp->f_ci->m_fp_list);3396 up_write(&fp->f_ci->m_lock);3397 3398 /* Check delete pending among previous fp before oplock break */3399 if (ksmbd_inode_pending_delete(fp)) {3400 rc = -EBUSY;3401 goto err_out;3402 }3403 3404 if (file_present || created)3405 ksmbd_vfs_kern_path_unlock(&parent_path, &path);3406 3407 if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&3408 !fp->attrib_only && !stream_name) {3409 smb_break_all_oplock(work, fp);3410 need_truncate = 1;3411 }3412 3413 share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);3414 if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) ||3415 (req_op_level == SMB2_OPLOCK_LEVEL_LEASE &&3416 !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) {3417 if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) {3418 rc = share_ret;3419 goto err_out1;3420 }3421 } else {3422 if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && lc) {3423 if (S_ISDIR(file_inode(filp)->i_mode)) {3424 lc->req_state &= ~SMB2_LEASE_WRITE_CACHING_LE;3425 lc->is_dir = true;3426 }3427 3428 /*3429 * Compare parent lease using parent key. If there is no3430 * a lease that has same parent key, Send lease break3431 * notification.3432 */3433 smb_send_parent_lease_break_noti(fp, lc);3434 3435 req_op_level = smb2_map_lease_to_oplock(lc->req_state);3436 ksmbd_debug(SMB,3437 "lease req for(%s) req oplock state 0x%x, lease state 0x%x\n",3438 name, req_op_level, lc->req_state);3439 rc = find_same_lease_key(sess, fp->f_ci, lc);3440 if (rc)3441 goto err_out1;3442 } else if (open_flags == O_RDONLY &&3443 (req_op_level == SMB2_OPLOCK_LEVEL_BATCH ||3444 req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE))3445 req_op_level = SMB2_OPLOCK_LEVEL_II;3446 3447 rc = smb_grant_oplock(work, req_op_level,3448 fp->persistent_id, fp,3449 le32_to_cpu(req->hdr.Id.SyncId.TreeId),3450 lc, share_ret);3451 if (rc < 0)3452 goto err_out1;3453 }3454 3455 if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)3456 ksmbd_fd_set_delete_on_close(fp, file_info);3457 3458 if (need_truncate) {3459 rc = smb2_create_truncate(&fp->filp->f_path);3460 if (rc)3461 goto err_out1;3462 }3463 3464 if (req->CreateContextsOffset) {3465 struct create_alloc_size_req *az_req;3466 3467 az_req = (struct create_alloc_size_req *)smb2_find_context_vals(req,3468 SMB2_CREATE_ALLOCATION_SIZE, 4);3469 if (IS_ERR(az_req)) {3470 rc = PTR_ERR(az_req);3471 goto err_out1;3472 } else if (az_req) {3473 loff_t alloc_size;3474 int err;3475 3476 if (le16_to_cpu(az_req->ccontext.DataOffset) +3477 le32_to_cpu(az_req->ccontext.DataLength) <3478 sizeof(struct create_alloc_size_req)) {3479 rc = -EINVAL;3480 goto err_out1;3481 }3482 alloc_size = le64_to_cpu(az_req->AllocationSize);3483 ksmbd_debug(SMB,3484 "request smb2 create allocate size : %llu\n",3485 alloc_size);3486 smb_break_all_levII_oplock(work, fp, 1);3487 err = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,3488 alloc_size);3489 if (err < 0)3490 ksmbd_debug(SMB,3491 "vfs_fallocate is failed : %d\n",3492 err);3493 }3494 3495 context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4);3496 if (IS_ERR(context)) {3497 rc = PTR_ERR(context);3498 goto err_out1;3499 } else if (context) {3500 ksmbd_debug(SMB, "get query on disk id context\n");3501 query_disk_id = 1;3502 }3503 }3504 3505 rc = ksmbd_vfs_getattr(&path, &stat);3506 if (rc)3507 goto err_out1;3508 3509 if (stat.result_mask & STATX_BTIME)3510 fp->create_time = ksmbd_UnixTimeToNT(stat.btime);3511 else3512 fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);3513 if (req->FileAttributes || fp->f_ci->m_fattr == 0)3514 fp->f_ci->m_fattr =3515 cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));3516 3517 if (!created)3518 smb2_update_xattrs(tcon, &path, fp);3519 else3520 smb2_new_xattrs(tcon, &path, fp);3521 3522 memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);3523 3524 if (dh_info.type == DURABLE_REQ_V2 || dh_info.type == DURABLE_REQ) {3525 if (dh_info.type == DURABLE_REQ_V2 && dh_info.persistent &&3526 test_share_config_flag(work->tcon->share_conf,3527 KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY))3528 fp->is_persistent = true;3529 else3530 fp->is_durable = true;3531 3532 if (dh_info.type == DURABLE_REQ_V2) {3533 memcpy(fp->create_guid, dh_info.CreateGuid,3534 SMB2_CREATE_GUID_SIZE);3535 if (dh_info.timeout)3536 fp->durable_timeout =3537 min_t(unsigned int, dh_info.timeout,3538 DURABLE_HANDLE_MAX_TIMEOUT);3539 else3540 fp->durable_timeout = 60;3541 }3542 }3543 3544reconnected_fp:3545 rsp->StructureSize = cpu_to_le16(89);3546 rcu_read_lock();3547 opinfo = rcu_dereference(fp->f_opinfo);3548 rsp->OplockLevel = opinfo != NULL ? opinfo->level : 0;3549 rcu_read_unlock();3550 rsp->Flags = 0;3551 rsp->CreateAction = cpu_to_le32(file_info);3552 rsp->CreationTime = cpu_to_le64(fp->create_time);3553 time = ksmbd_UnixTimeToNT(stat.atime);3554 rsp->LastAccessTime = cpu_to_le64(time);3555 time = ksmbd_UnixTimeToNT(stat.mtime);3556 rsp->LastWriteTime = cpu_to_le64(time);3557 time = ksmbd_UnixTimeToNT(stat.ctime);3558 rsp->ChangeTime = cpu_to_le64(time);3559 rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :3560 cpu_to_le64(stat.blocks << 9);3561 rsp->EndofFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);3562 rsp->FileAttributes = fp->f_ci->m_fattr;3563 3564 rsp->Reserved2 = 0;3565 3566 rsp->PersistentFileId = fp->persistent_id;3567 rsp->VolatileFileId = fp->volatile_id;3568 3569 rsp->CreateContextsOffset = 0;3570 rsp->CreateContextsLength = 0;3571 iov_len = offsetof(struct smb2_create_rsp, Buffer);3572 3573 /* If lease is request send lease context response */3574 if (opinfo && opinfo->is_lease) {3575 struct create_context *lease_ccontext;3576 3577 ksmbd_debug(SMB, "lease granted on(%s) lease state 0x%x\n",3578 name, opinfo->o_lease->state);3579 rsp->OplockLevel = SMB2_OPLOCK_LEVEL_LEASE;3580 3581 lease_ccontext = (struct create_context *)rsp->Buffer;3582 contxt_cnt++;3583 create_lease_buf(rsp->Buffer, opinfo->o_lease);3584 le32_add_cpu(&rsp->CreateContextsLength,3585 conn->vals->create_lease_size);3586 iov_len += conn->vals->create_lease_size;3587 next_ptr = &lease_ccontext->Next;3588 next_off = conn->vals->create_lease_size;3589 }3590 3591 if (maximal_access_ctxt) {3592 struct create_context *mxac_ccontext;3593 3594 if (maximal_access == 0)3595 ksmbd_vfs_query_maximal_access(idmap,3596 path.dentry,3597 &maximal_access);3598 mxac_ccontext = (struct create_context *)(rsp->Buffer +3599 le32_to_cpu(rsp->CreateContextsLength));3600 contxt_cnt++;3601 create_mxac_rsp_buf(rsp->Buffer +3602 le32_to_cpu(rsp->CreateContextsLength),3603 le32_to_cpu(maximal_access));3604 le32_add_cpu(&rsp->CreateContextsLength,3605 conn->vals->create_mxac_size);3606 iov_len += conn->vals->create_mxac_size;3607 if (next_ptr)3608 *next_ptr = cpu_to_le32(next_off);3609 next_ptr = &mxac_ccontext->Next;3610 next_off = conn->vals->create_mxac_size;3611 }3612 3613 if (query_disk_id) {3614 struct create_context *disk_id_ccontext;3615 3616 disk_id_ccontext = (struct create_context *)(rsp->Buffer +3617 le32_to_cpu(rsp->CreateContextsLength));3618 contxt_cnt++;3619 create_disk_id_rsp_buf(rsp->Buffer +3620 le32_to_cpu(rsp->CreateContextsLength),3621 stat.ino, tcon->id);3622 le32_add_cpu(&rsp->CreateContextsLength,3623 conn->vals->create_disk_id_size);3624 iov_len += conn->vals->create_disk_id_size;3625 if (next_ptr)3626 *next_ptr = cpu_to_le32(next_off);3627 next_ptr = &disk_id_ccontext->Next;3628 next_off = conn->vals->create_disk_id_size;3629 }3630 3631 if (dh_info.type == DURABLE_REQ || dh_info.type == DURABLE_REQ_V2) {3632 struct create_context *durable_ccontext;3633 3634 durable_ccontext = (struct create_context *)(rsp->Buffer +3635 le32_to_cpu(rsp->CreateContextsLength));3636 contxt_cnt++;3637 if (dh_info.type == DURABLE_REQ) {3638 create_durable_rsp_buf(rsp->Buffer +3639 le32_to_cpu(rsp->CreateContextsLength));3640 le32_add_cpu(&rsp->CreateContextsLength,3641 conn->vals->create_durable_size);3642 iov_len += conn->vals->create_durable_size;3643 } else {3644 create_durable_v2_rsp_buf(rsp->Buffer +3645 le32_to_cpu(rsp->CreateContextsLength),3646 fp);3647 le32_add_cpu(&rsp->CreateContextsLength,3648 conn->vals->create_durable_v2_size);3649 iov_len += conn->vals->create_durable_v2_size;3650 }3651 3652 if (next_ptr)3653 *next_ptr = cpu_to_le32(next_off);3654 next_ptr = &durable_ccontext->Next;3655 next_off = conn->vals->create_durable_size;3656 }3657 3658 if (posix_ctxt) {3659 contxt_cnt++;3660 create_posix_rsp_buf(rsp->Buffer +3661 le32_to_cpu(rsp->CreateContextsLength),3662 fp);3663 le32_add_cpu(&rsp->CreateContextsLength,3664 conn->vals->create_posix_size);3665 iov_len += conn->vals->create_posix_size;3666 if (next_ptr)3667 *next_ptr = cpu_to_le32(next_off);3668 }3669 3670 if (contxt_cnt > 0) {3671 rsp->CreateContextsOffset =3672 cpu_to_le32(offsetof(struct smb2_create_rsp, Buffer));3673 }3674 3675err_out:3676 if (rc && (file_present || created))3677 ksmbd_vfs_kern_path_unlock(&parent_path, &path);3678 3679err_out1:3680 ksmbd_revert_fsids(work);3681 3682err_out2:3683 if (!rc) {3684 ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED);3685 rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);3686 }3687 if (rc) {3688 if (rc == -EINVAL)3689 rsp->hdr.Status = STATUS_INVALID_PARAMETER;3690 else if (rc == -EOPNOTSUPP)3691 rsp->hdr.Status = STATUS_NOT_SUPPORTED;3692 else if (rc == -EACCES || rc == -ESTALE || rc == -EXDEV)3693 rsp->hdr.Status = STATUS_ACCESS_DENIED;3694 else if (rc == -ENOENT)3695 rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID;3696 else if (rc == -EPERM)3697 rsp->hdr.Status = STATUS_SHARING_VIOLATION;3698 else if (rc == -EBUSY)3699 rsp->hdr.Status = STATUS_DELETE_PENDING;3700 else if (rc == -EBADF)3701 rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND;3702 else if (rc == -ENOEXEC)3703 rsp->hdr.Status = STATUS_DUPLICATE_OBJECTID;3704 else if (rc == -ENXIO)3705 rsp->hdr.Status = STATUS_NO_SUCH_DEVICE;3706 else if (rc == -EEXIST)3707 rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION;3708 else if (rc == -EMFILE)3709 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;3710 if (!rsp->hdr.Status)3711 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;3712 3713 if (fp)3714 ksmbd_fd_put(work, fp);3715 smb2_set_err_rsp(work);3716 ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status);3717 }3718 3719 kfree(name);3720 kfree(lc);3721 3722 return rc;3723}3724 3725static int readdir_info_level_struct_sz(int info_level)3726{3727 switch (info_level) {3728 case FILE_FULL_DIRECTORY_INFORMATION:3729 return sizeof(struct file_full_directory_info);3730 case FILE_BOTH_DIRECTORY_INFORMATION:3731 return sizeof(struct file_both_directory_info);3732 case FILE_DIRECTORY_INFORMATION:3733 return sizeof(struct file_directory_info);3734 case FILE_NAMES_INFORMATION:3735 return sizeof(struct file_names_info);3736 case FILEID_FULL_DIRECTORY_INFORMATION:3737 return sizeof(struct file_id_full_dir_info);3738 case FILEID_BOTH_DIRECTORY_INFORMATION:3739 return sizeof(struct file_id_both_directory_info);3740 case SMB_FIND_FILE_POSIX_INFO:3741 return sizeof(struct smb2_posix_info);3742 default:3743 return -EOPNOTSUPP;3744 }3745}3746 3747static int dentry_name(struct ksmbd_dir_info *d_info, int info_level)3748{3749 switch (info_level) {3750 case FILE_FULL_DIRECTORY_INFORMATION:3751 {3752 struct file_full_directory_info *ffdinfo;3753 3754 ffdinfo = (struct file_full_directory_info *)d_info->rptr;3755 d_info->rptr += le32_to_cpu(ffdinfo->NextEntryOffset);3756 d_info->name = ffdinfo->FileName;3757 d_info->name_len = le32_to_cpu(ffdinfo->FileNameLength);3758 return 0;3759 }3760 case FILE_BOTH_DIRECTORY_INFORMATION:3761 {3762 struct file_both_directory_info *fbdinfo;3763 3764 fbdinfo = (struct file_both_directory_info *)d_info->rptr;3765 d_info->rptr += le32_to_cpu(fbdinfo->NextEntryOffset);3766 d_info->name = fbdinfo->FileName;3767 d_info->name_len = le32_to_cpu(fbdinfo->FileNameLength);3768 return 0;3769 }3770 case FILE_DIRECTORY_INFORMATION:3771 {3772 struct file_directory_info *fdinfo;3773 3774 fdinfo = (struct file_directory_info *)d_info->rptr;3775 d_info->rptr += le32_to_cpu(fdinfo->NextEntryOffset);3776 d_info->name = fdinfo->FileName;3777 d_info->name_len = le32_to_cpu(fdinfo->FileNameLength);3778 return 0;3779 }3780 case FILE_NAMES_INFORMATION:3781 {3782 struct file_names_info *fninfo;3783 3784 fninfo = (struct file_names_info *)d_info->rptr;3785 d_info->rptr += le32_to_cpu(fninfo->NextEntryOffset);3786 d_info->name = fninfo->FileName;3787 d_info->name_len = le32_to_cpu(fninfo->FileNameLength);3788 return 0;3789 }3790 case FILEID_FULL_DIRECTORY_INFORMATION:3791 {3792 struct file_id_full_dir_info *dinfo;3793 3794 dinfo = (struct file_id_full_dir_info *)d_info->rptr;3795 d_info->rptr += le32_to_cpu(dinfo->NextEntryOffset);3796 d_info->name = dinfo->FileName;3797 d_info->name_len = le32_to_cpu(dinfo->FileNameLength);3798 return 0;3799 }3800 case FILEID_BOTH_DIRECTORY_INFORMATION:3801 {3802 struct file_id_both_directory_info *fibdinfo;3803 3804 fibdinfo = (struct file_id_both_directory_info *)d_info->rptr;3805 d_info->rptr += le32_to_cpu(fibdinfo->NextEntryOffset);3806 d_info->name = fibdinfo->FileName;3807 d_info->name_len = le32_to_cpu(fibdinfo->FileNameLength);3808 return 0;3809 }3810 case SMB_FIND_FILE_POSIX_INFO:3811 {3812 struct smb2_posix_info *posix_info;3813 3814 posix_info = (struct smb2_posix_info *)d_info->rptr;3815 d_info->rptr += le32_to_cpu(posix_info->NextEntryOffset);3816 d_info->name = posix_info->name;3817 d_info->name_len = le32_to_cpu(posix_info->name_len);3818 return 0;3819 }3820 default:3821 return -EINVAL;3822 }3823}3824 3825/**3826 * smb2_populate_readdir_entry() - encode directory entry in smb2 response3827 * buffer3828 * @conn: connection instance3829 * @info_level: smb information level3830 * @d_info: structure included variables for query dir3831 * @ksmbd_kstat: ksmbd wrapper of dirent stat information3832 *3833 * if directory has many entries, find first can't read it fully.3834 * find next might be called multiple times to read remaining dir entries3835 *3836 * Return: 0 on success, otherwise error3837 */3838static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,3839 struct ksmbd_dir_info *d_info,3840 struct ksmbd_kstat *ksmbd_kstat)3841{3842 int next_entry_offset = 0;3843 char *conv_name;3844 int conv_len;3845 void *kstat;3846 int struct_sz, rc = 0;3847 3848 conv_name = ksmbd_convert_dir_info_name(d_info,3849 conn->local_nls,3850 &conv_len);3851 if (!conv_name)3852 return -ENOMEM;3853 3854 /* Somehow the name has only terminating NULL bytes */3855 if (conv_len < 0) {3856 rc = -EINVAL;3857 goto free_conv_name;3858 }3859 3860 struct_sz = readdir_info_level_struct_sz(info_level) + conv_len;3861 next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT);3862 d_info->last_entry_off_align = next_entry_offset - struct_sz;3863 3864 if (next_entry_offset > d_info->out_buf_len) {3865 d_info->out_buf_len = 0;3866 rc = -ENOSPC;3867 goto free_conv_name;3868 }3869 3870 kstat = d_info->wptr;3871 if (info_level != FILE_NAMES_INFORMATION)3872 kstat = ksmbd_vfs_init_kstat(&d_info->wptr, ksmbd_kstat);3873 3874 switch (info_level) {3875 case FILE_FULL_DIRECTORY_INFORMATION:3876 {3877 struct file_full_directory_info *ffdinfo;3878 3879 ffdinfo = (struct file_full_directory_info *)kstat;3880 ffdinfo->FileNameLength = cpu_to_le32(conv_len);3881 ffdinfo->EaSize =3882 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);3883 if (ffdinfo->EaSize)3884 ffdinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE;3885 if (d_info->hide_dot_file && d_info->name[0] == '.')3886 ffdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;3887 memcpy(ffdinfo->FileName, conv_name, conv_len);3888 ffdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);3889 break;3890 }3891 case FILE_BOTH_DIRECTORY_INFORMATION:3892 {3893 struct file_both_directory_info *fbdinfo;3894 3895 fbdinfo = (struct file_both_directory_info *)kstat;3896 fbdinfo->FileNameLength = cpu_to_le32(conv_len);3897 fbdinfo->EaSize =3898 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);3899 if (fbdinfo->EaSize)3900 fbdinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE;3901 fbdinfo->ShortNameLength = 0;3902 fbdinfo->Reserved = 0;3903 if (d_info->hide_dot_file && d_info->name[0] == '.')3904 fbdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;3905 memcpy(fbdinfo->FileName, conv_name, conv_len);3906 fbdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);3907 break;3908 }3909 case FILE_DIRECTORY_INFORMATION:3910 {3911 struct file_directory_info *fdinfo;3912 3913 fdinfo = (struct file_directory_info *)kstat;3914 fdinfo->FileNameLength = cpu_to_le32(conv_len);3915 if (d_info->hide_dot_file && d_info->name[0] == '.')3916 fdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;3917 memcpy(fdinfo->FileName, conv_name, conv_len);3918 fdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);3919 break;3920 }3921 case FILE_NAMES_INFORMATION:3922 {3923 struct file_names_info *fninfo;3924 3925 fninfo = (struct file_names_info *)kstat;3926 fninfo->FileNameLength = cpu_to_le32(conv_len);3927 memcpy(fninfo->FileName, conv_name, conv_len);3928 fninfo->NextEntryOffset = cpu_to_le32(next_entry_offset);3929 break;3930 }3931 case FILEID_FULL_DIRECTORY_INFORMATION:3932 {3933 struct file_id_full_dir_info *dinfo;3934 3935 dinfo = (struct file_id_full_dir_info *)kstat;3936 dinfo->FileNameLength = cpu_to_le32(conv_len);3937 dinfo->EaSize =3938 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);3939 if (dinfo->EaSize)3940 dinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE;3941 dinfo->Reserved = 0;3942 dinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);3943 if (d_info->hide_dot_file && d_info->name[0] == '.')3944 dinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;3945 memcpy(dinfo->FileName, conv_name, conv_len);3946 dinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);3947 break;3948 }3949 case FILEID_BOTH_DIRECTORY_INFORMATION:3950 {3951 struct file_id_both_directory_info *fibdinfo;3952 3953 fibdinfo = (struct file_id_both_directory_info *)kstat;3954 fibdinfo->FileNameLength = cpu_to_le32(conv_len);3955 fibdinfo->EaSize =3956 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);3957 if (fibdinfo->EaSize)3958 fibdinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE;3959 fibdinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);3960 fibdinfo->ShortNameLength = 0;3961 fibdinfo->Reserved = 0;3962 fibdinfo->Reserved2 = cpu_to_le16(0);3963 if (d_info->hide_dot_file && d_info->name[0] == '.')3964 fibdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;3965 memcpy(fibdinfo->FileName, conv_name, conv_len);3966 fibdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);3967 break;3968 }3969 case SMB_FIND_FILE_POSIX_INFO:3970 {3971 struct smb2_posix_info *posix_info;3972 u64 time;3973 3974 posix_info = (struct smb2_posix_info *)kstat;3975 posix_info->Ignored = 0;3976 posix_info->CreationTime = cpu_to_le64(ksmbd_kstat->create_time);3977 time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime);3978 posix_info->ChangeTime = cpu_to_le64(time);3979 time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->atime);3980 posix_info->LastAccessTime = cpu_to_le64(time);3981 time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->mtime);3982 posix_info->LastWriteTime = cpu_to_le64(time);3983 posix_info->EndOfFile = cpu_to_le64(ksmbd_kstat->kstat->size);3984 posix_info->AllocationSize = cpu_to_le64(ksmbd_kstat->kstat->blocks << 9);3985 posix_info->DeviceId = cpu_to_le32(ksmbd_kstat->kstat->rdev);3986 posix_info->HardLinks = cpu_to_le32(ksmbd_kstat->kstat->nlink);3987 posix_info->Mode = cpu_to_le32(ksmbd_kstat->kstat->mode & 0777);3988 posix_info->Inode = cpu_to_le64(ksmbd_kstat->kstat->ino);3989 posix_info->DosAttributes =3990 S_ISDIR(ksmbd_kstat->kstat->mode) ?3991 FILE_ATTRIBUTE_DIRECTORY_LE : FILE_ATTRIBUTE_ARCHIVE_LE;3992 if (d_info->hide_dot_file && d_info->name[0] == '.')3993 posix_info->DosAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;3994 /*3995 * SidBuffer(32) contain two sids(Domain sid(16), UNIX group sid(16)).3996 * UNIX sid(16) = revision(1) + num_subauth(1) + authority(6) +3997 * sub_auth(4 * 1(num_subauth)) + RID(4).3998 */3999 id_to_sid(from_kuid_munged(&init_user_ns, ksmbd_kstat->kstat->uid),4000 SIDUNIX_USER, (struct smb_sid *)&posix_info->SidBuffer[0]);4001 id_to_sid(from_kgid_munged(&init_user_ns, ksmbd_kstat->kstat->gid),4002 SIDUNIX_GROUP, (struct smb_sid *)&posix_info->SidBuffer[16]);4003 memcpy(posix_info->name, conv_name, conv_len);4004 posix_info->name_len = cpu_to_le32(conv_len);4005 posix_info->NextEntryOffset = cpu_to_le32(next_entry_offset);4006 break;4007 }4008 4009 } /* switch (info_level) */4010 4011 d_info->last_entry_offset = d_info->data_count;4012 d_info->data_count += next_entry_offset;4013 d_info->out_buf_len -= next_entry_offset;4014 d_info->wptr += next_entry_offset;4015 4016 ksmbd_debug(SMB,4017 "info_level : %d, buf_len :%d, next_offset : %d, data_count : %d\n",4018 info_level, d_info->out_buf_len,4019 next_entry_offset, d_info->data_count);4020 4021free_conv_name:4022 kfree(conv_name);4023 return rc;4024}4025 4026struct smb2_query_dir_private {4027 struct ksmbd_work *work;4028 char *search_pattern;4029 struct ksmbd_file *dir_fp;4030 4031 struct ksmbd_dir_info *d_info;4032 int info_level;4033};4034 4035static void lock_dir(struct ksmbd_file *dir_fp)4036{4037 struct dentry *dir = dir_fp->filp->f_path.dentry;4038 4039 inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);4040}4041 4042static void unlock_dir(struct ksmbd_file *dir_fp)4043{4044 struct dentry *dir = dir_fp->filp->f_path.dentry;4045 4046 inode_unlock(d_inode(dir));4047}4048 4049static int process_query_dir_entries(struct smb2_query_dir_private *priv)4050{4051 struct mnt_idmap *idmap = file_mnt_idmap(priv->dir_fp->filp);4052 struct kstat kstat;4053 struct ksmbd_kstat ksmbd_kstat;4054 int rc;4055 int i;4056 4057 for (i = 0; i < priv->d_info->num_entry; i++) {4058 struct dentry *dent;4059 4060 if (dentry_name(priv->d_info, priv->info_level))4061 return -EINVAL;4062 4063 lock_dir(priv->dir_fp);4064 dent = lookup_one(idmap, priv->d_info->name,4065 priv->dir_fp->filp->f_path.dentry,4066 priv->d_info->name_len);4067 unlock_dir(priv->dir_fp);4068 4069 if (IS_ERR(dent)) {4070 ksmbd_debug(SMB, "Cannot lookup `%s' [%ld]\n",4071 priv->d_info->name,4072 PTR_ERR(dent));4073 continue;4074 }4075 if (unlikely(d_is_negative(dent))) {4076 dput(dent);4077 ksmbd_debug(SMB, "Negative dentry `%s'\n",4078 priv->d_info->name);4079 continue;4080 }4081 4082 ksmbd_kstat.kstat = &kstat;4083 if (priv->info_level != FILE_NAMES_INFORMATION) {4084 rc = ksmbd_vfs_fill_dentry_attrs(priv->work,4085 idmap,4086 dent,4087 &ksmbd_kstat);4088 if (rc) {4089 dput(dent);4090 continue;4091 }4092 }4093 4094 rc = smb2_populate_readdir_entry(priv->work->conn,4095 priv->info_level,4096 priv->d_info,4097 &ksmbd_kstat);4098 dput(dent);4099 if (rc)4100 return rc;4101 }4102 return 0;4103}4104 4105static int reserve_populate_dentry(struct ksmbd_dir_info *d_info,4106 int info_level)4107{4108 int struct_sz;4109 int conv_len;4110 int next_entry_offset;4111 4112 struct_sz = readdir_info_level_struct_sz(info_level);4113 if (struct_sz == -EOPNOTSUPP)4114 return -EOPNOTSUPP;4115 4116 conv_len = (d_info->name_len + 1) * 2;4117 next_entry_offset = ALIGN(struct_sz + conv_len,4118 KSMBD_DIR_INFO_ALIGNMENT);4119 4120 if (next_entry_offset > d_info->out_buf_len) {4121 d_info->out_buf_len = 0;4122 return -ENOSPC;4123 }4124 4125 switch (info_level) {4126 case FILE_FULL_DIRECTORY_INFORMATION:4127 {4128 struct file_full_directory_info *ffdinfo;4129 4130 ffdinfo = (struct file_full_directory_info *)d_info->wptr;4131 memcpy(ffdinfo->FileName, d_info->name, d_info->name_len);4132 ffdinfo->FileName[d_info->name_len] = 0x00;4133 ffdinfo->FileNameLength = cpu_to_le32(d_info->name_len);4134 ffdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);4135 break;4136 }4137 case FILE_BOTH_DIRECTORY_INFORMATION:4138 {4139 struct file_both_directory_info *fbdinfo;4140 4141 fbdinfo = (struct file_both_directory_info *)d_info->wptr;4142 memcpy(fbdinfo->FileName, d_info->name, d_info->name_len);4143 fbdinfo->FileName[d_info->name_len] = 0x00;4144 fbdinfo->FileNameLength = cpu_to_le32(d_info->name_len);4145 fbdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);4146 break;4147 }4148 case FILE_DIRECTORY_INFORMATION:4149 {4150 struct file_directory_info *fdinfo;4151 4152 fdinfo = (struct file_directory_info *)d_info->wptr;4153 memcpy(fdinfo->FileName, d_info->name, d_info->name_len);4154 fdinfo->FileName[d_info->name_len] = 0x00;4155 fdinfo->FileNameLength = cpu_to_le32(d_info->name_len);4156 fdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);4157 break;4158 }4159 case FILE_NAMES_INFORMATION:4160 {4161 struct file_names_info *fninfo;4162 4163 fninfo = (struct file_names_info *)d_info->wptr;4164 memcpy(fninfo->FileName, d_info->name, d_info->name_len);4165 fninfo->FileName[d_info->name_len] = 0x00;4166 fninfo->FileNameLength = cpu_to_le32(d_info->name_len);4167 fninfo->NextEntryOffset = cpu_to_le32(next_entry_offset);4168 break;4169 }4170 case FILEID_FULL_DIRECTORY_INFORMATION:4171 {4172 struct file_id_full_dir_info *dinfo;4173 4174 dinfo = (struct file_id_full_dir_info *)d_info->wptr;4175 memcpy(dinfo->FileName, d_info->name, d_info->name_len);4176 dinfo->FileName[d_info->name_len] = 0x00;4177 dinfo->FileNameLength = cpu_to_le32(d_info->name_len);4178 dinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);4179 break;4180 }4181 case FILEID_BOTH_DIRECTORY_INFORMATION:4182 {4183 struct file_id_both_directory_info *fibdinfo;4184 4185 fibdinfo = (struct file_id_both_directory_info *)d_info->wptr;4186 memcpy(fibdinfo->FileName, d_info->name, d_info->name_len);4187 fibdinfo->FileName[d_info->name_len] = 0x00;4188 fibdinfo->FileNameLength = cpu_to_le32(d_info->name_len);4189 fibdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);4190 break;4191 }4192 case SMB_FIND_FILE_POSIX_INFO:4193 {4194 struct smb2_posix_info *posix_info;4195 4196 posix_info = (struct smb2_posix_info *)d_info->wptr;4197 memcpy(posix_info->name, d_info->name, d_info->name_len);4198 posix_info->name[d_info->name_len] = 0x00;4199 posix_info->name_len = cpu_to_le32(d_info->name_len);4200 posix_info->NextEntryOffset =4201 cpu_to_le32(next_entry_offset);4202 break;4203 }4204 } /* switch (info_level) */4205 4206 d_info->num_entry++;4207 d_info->out_buf_len -= next_entry_offset;4208 d_info->wptr += next_entry_offset;4209 return 0;4210}4211 4212static bool __query_dir(struct dir_context *ctx, const char *name, int namlen,4213 loff_t offset, u64 ino, unsigned int d_type)4214{4215 struct ksmbd_readdir_data *buf;4216 struct smb2_query_dir_private *priv;4217 struct ksmbd_dir_info *d_info;4218 int rc;4219 4220 buf = container_of(ctx, struct ksmbd_readdir_data, ctx);4221 priv = buf->private;4222 d_info = priv->d_info;4223 4224 /* dot and dotdot entries are already reserved */4225 if (!strcmp(".", name) || !strcmp("..", name))4226 return true;4227 if (ksmbd_share_veto_filename(priv->work->tcon->share_conf, name))4228 return true;4229 if (!match_pattern(name, namlen, priv->search_pattern))4230 return true;4231 4232 d_info->name = name;4233 d_info->name_len = namlen;4234 rc = reserve_populate_dentry(d_info, priv->info_level);4235 if (rc)4236 return false;4237 if (d_info->flags & SMB2_RETURN_SINGLE_ENTRY)4238 d_info->out_buf_len = 0;4239 return true;4240}4241 4242static int verify_info_level(int info_level)4243{4244 switch (info_level) {4245 case FILE_FULL_DIRECTORY_INFORMATION:4246 case FILE_BOTH_DIRECTORY_INFORMATION:4247 case FILE_DIRECTORY_INFORMATION:4248 case FILE_NAMES_INFORMATION:4249 case FILEID_FULL_DIRECTORY_INFORMATION:4250 case FILEID_BOTH_DIRECTORY_INFORMATION:4251 case SMB_FIND_FILE_POSIX_INFO:4252 break;4253 default:4254 return -EOPNOTSUPP;4255 }4256 4257 return 0;4258}4259 4260static int smb2_resp_buf_len(struct ksmbd_work *work, unsigned short hdr2_len)4261{4262 int free_len;4263 4264 free_len = (int)(work->response_sz -4265 (get_rfc1002_len(work->response_buf) + 4)) - hdr2_len;4266 return free_len;4267}4268 4269static int smb2_calc_max_out_buf_len(struct ksmbd_work *work,4270 unsigned short hdr2_len,4271 unsigned int out_buf_len)4272{4273 int free_len;4274 4275 if (out_buf_len > work->conn->vals->max_trans_size)4276 return -EINVAL;4277 4278 free_len = smb2_resp_buf_len(work, hdr2_len);4279 if (free_len < 0)4280 return -EINVAL;4281 4282 return min_t(int, out_buf_len, free_len);4283}4284 4285int smb2_query_dir(struct ksmbd_work *work)4286{4287 struct ksmbd_conn *conn = work->conn;4288 struct smb2_query_directory_req *req;4289 struct smb2_query_directory_rsp *rsp;4290 struct ksmbd_share_config *share = work->tcon->share_conf;4291 struct ksmbd_file *dir_fp = NULL;4292 struct ksmbd_dir_info d_info;4293 int rc = 0;4294 char *srch_ptr = NULL;4295 unsigned char srch_flag;4296 int buffer_sz;4297 struct smb2_query_dir_private query_dir_private = {NULL, };4298 4299 WORK_BUFFERS(work, req, rsp);4300 4301 if (ksmbd_override_fsids(work)) {4302 rsp->hdr.Status = STATUS_NO_MEMORY;4303 smb2_set_err_rsp(work);4304 return -ENOMEM;4305 }4306 4307 rc = verify_info_level(req->FileInformationClass);4308 if (rc) {4309 rc = -EFAULT;4310 goto err_out2;4311 }4312 4313 dir_fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);4314 if (!dir_fp) {4315 rc = -EBADF;4316 goto err_out2;4317 }4318 4319 if (!(dir_fp->daccess & FILE_LIST_DIRECTORY_LE) ||4320 inode_permission(file_mnt_idmap(dir_fp->filp),4321 file_inode(dir_fp->filp),4322 MAY_READ | MAY_EXEC)) {4323 pr_err("no right to enumerate directory (%pD)\n", dir_fp->filp);4324 rc = -EACCES;4325 goto err_out2;4326 }4327 4328 if (!S_ISDIR(file_inode(dir_fp->filp)->i_mode)) {4329 pr_err("can't do query dir for a file\n");4330 rc = -EINVAL;4331 goto err_out2;4332 }4333 4334 srch_flag = req->Flags;4335 srch_ptr = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->FileNameOffset),4336 le16_to_cpu(req->FileNameLength), 1,4337 conn->local_nls);4338 if (IS_ERR(srch_ptr)) {4339 ksmbd_debug(SMB, "Search Pattern not found\n");4340 rc = -EINVAL;4341 goto err_out2;4342 } else {4343 ksmbd_debug(SMB, "Search pattern is %s\n", srch_ptr);4344 }4345 4346 if (srch_flag & SMB2_REOPEN || srch_flag & SMB2_RESTART_SCANS) {4347 ksmbd_debug(SMB, "Restart directory scan\n");4348 generic_file_llseek(dir_fp->filp, 0, SEEK_SET);4349 }4350 4351 memset(&d_info, 0, sizeof(struct ksmbd_dir_info));4352 d_info.wptr = (char *)rsp->Buffer;4353 d_info.rptr = (char *)rsp->Buffer;4354 d_info.out_buf_len =4355 smb2_calc_max_out_buf_len(work, 8,4356 le32_to_cpu(req->OutputBufferLength));4357 if (d_info.out_buf_len < 0) {4358 rc = -EINVAL;4359 goto err_out;4360 }4361 d_info.flags = srch_flag;4362 4363 /*4364 * reserve dot and dotdot entries in head of buffer4365 * in first response4366 */4367 rc = ksmbd_populate_dot_dotdot_entries(work, req->FileInformationClass,4368 dir_fp, &d_info, srch_ptr,4369 smb2_populate_readdir_entry);4370 if (rc == -ENOSPC)4371 rc = 0;4372 else if (rc)4373 goto err_out;4374 4375 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_HIDE_DOT_FILES))4376 d_info.hide_dot_file = true;4377 4378 buffer_sz = d_info.out_buf_len;4379 d_info.rptr = d_info.wptr;4380 query_dir_private.work = work;4381 query_dir_private.search_pattern = srch_ptr;4382 query_dir_private.dir_fp = dir_fp;4383 query_dir_private.d_info = &d_info;4384 query_dir_private.info_level = req->FileInformationClass;4385 dir_fp->readdir_data.private = &query_dir_private;4386 set_ctx_actor(&dir_fp->readdir_data.ctx, __query_dir);4387 4388 rc = iterate_dir(dir_fp->filp, &dir_fp->readdir_data.ctx);4389 /*4390 * req->OutputBufferLength is too small to contain even one entry.4391 * In this case, it immediately returns OutputBufferLength 0 to client.4392 */4393 if (!d_info.out_buf_len && !d_info.num_entry)4394 goto no_buf_len;4395 if (rc > 0 || rc == -ENOSPC)4396 rc = 0;4397 else if (rc)4398 goto err_out;4399 4400 d_info.wptr = d_info.rptr;4401 d_info.out_buf_len = buffer_sz;4402 rc = process_query_dir_entries(&query_dir_private);4403 if (rc)4404 goto err_out;4405 4406 if (!d_info.data_count && d_info.out_buf_len >= 0) {4407 if (srch_flag & SMB2_RETURN_SINGLE_ENTRY && !is_asterisk(srch_ptr)) {4408 rsp->hdr.Status = STATUS_NO_SUCH_FILE;4409 } else {4410 dir_fp->dot_dotdot[0] = dir_fp->dot_dotdot[1] = 0;4411 rsp->hdr.Status = STATUS_NO_MORE_FILES;4412 }4413 rsp->StructureSize = cpu_to_le16(9);4414 rsp->OutputBufferOffset = cpu_to_le16(0);4415 rsp->OutputBufferLength = cpu_to_le32(0);4416 rsp->Buffer[0] = 0;4417 rc = ksmbd_iov_pin_rsp(work, (void *)rsp,4418 offsetof(struct smb2_query_directory_rsp, Buffer)4419 + 1);4420 if (rc)4421 goto err_out;4422 } else {4423no_buf_len:4424 ((struct file_directory_info *)4425 ((char *)rsp->Buffer + d_info.last_entry_offset))4426 ->NextEntryOffset = 0;4427 if (d_info.data_count >= d_info.last_entry_off_align)4428 d_info.data_count -= d_info.last_entry_off_align;4429 4430 rsp->StructureSize = cpu_to_le16(9);4431 rsp->OutputBufferOffset = cpu_to_le16(72);4432 rsp->OutputBufferLength = cpu_to_le32(d_info.data_count);4433 rc = ksmbd_iov_pin_rsp(work, (void *)rsp,4434 offsetof(struct smb2_query_directory_rsp, Buffer) +4435 d_info.data_count);4436 if (rc)4437 goto err_out;4438 }4439 4440 kfree(srch_ptr);4441 ksmbd_fd_put(work, dir_fp);4442 ksmbd_revert_fsids(work);4443 return 0;4444 4445err_out:4446 pr_err("error while processing smb2 query dir rc = %d\n", rc);4447 kfree(srch_ptr);4448 4449err_out2:4450 if (rc == -EINVAL)4451 rsp->hdr.Status = STATUS_INVALID_PARAMETER;4452 else if (rc == -EACCES)4453 rsp->hdr.Status = STATUS_ACCESS_DENIED;4454 else if (rc == -ENOENT)4455 rsp->hdr.Status = STATUS_NO_SUCH_FILE;4456 else if (rc == -EBADF)4457 rsp->hdr.Status = STATUS_FILE_CLOSED;4458 else if (rc == -ENOMEM)4459 rsp->hdr.Status = STATUS_NO_MEMORY;4460 else if (rc == -EFAULT)4461 rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;4462 else if (rc == -EIO)4463 rsp->hdr.Status = STATUS_FILE_CORRUPT_ERROR;4464 if (!rsp->hdr.Status)4465 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;4466 4467 smb2_set_err_rsp(work);4468 ksmbd_fd_put(work, dir_fp);4469 ksmbd_revert_fsids(work);4470 return 0;4471}4472 4473/**4474 * buffer_check_err() - helper function to check buffer errors4475 * @reqOutputBufferLength: max buffer length expected in command response4476 * @rsp: query info response buffer contains output buffer length4477 * @rsp_org: base response buffer pointer in case of chained response4478 *4479 * Return: 0 on success, otherwise error4480 */4481static int buffer_check_err(int reqOutputBufferLength,4482 struct smb2_query_info_rsp *rsp,4483 void *rsp_org)4484{4485 if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) {4486 pr_err("Invalid Buffer Size Requested\n");4487 rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH;4488 *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr));4489 return -EINVAL;4490 }4491 return 0;4492}4493 4494static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp,4495 void *rsp_org)4496{4497 struct smb2_file_standard_info *sinfo;4498 4499 sinfo = (struct smb2_file_standard_info *)rsp->Buffer;4500 4501 sinfo->AllocationSize = cpu_to_le64(4096);4502 sinfo->EndOfFile = cpu_to_le64(0);4503 sinfo->NumberOfLinks = cpu_to_le32(1);4504 sinfo->DeletePending = 1;4505 sinfo->Directory = 0;4506 rsp->OutputBufferLength =4507 cpu_to_le32(sizeof(struct smb2_file_standard_info));4508}4509 4510static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num,4511 void *rsp_org)4512{4513 struct smb2_file_internal_info *file_info;4514 4515 file_info = (struct smb2_file_internal_info *)rsp->Buffer;4516 4517 /* any unique number */4518 file_info->IndexNumber = cpu_to_le64(num | (1ULL << 63));4519 rsp->OutputBufferLength =4520 cpu_to_le32(sizeof(struct smb2_file_internal_info));4521}4522 4523static int smb2_get_info_file_pipe(struct ksmbd_session *sess,4524 struct smb2_query_info_req *req,4525 struct smb2_query_info_rsp *rsp,4526 void *rsp_org)4527{4528 u64 id;4529 int rc;4530 4531 /*4532 * Windows can sometime send query file info request on4533 * pipe without opening it, checking error condition here4534 */4535 id = req->VolatileFileId;4536 if (!ksmbd_session_rpc_method(sess, id))4537 return -ENOENT;4538 4539 ksmbd_debug(SMB, "FileInfoClass %u, FileId 0x%llx\n",4540 req->FileInfoClass, req->VolatileFileId);4541 4542 switch (req->FileInfoClass) {4543 case FILE_STANDARD_INFORMATION:4544 get_standard_info_pipe(rsp, rsp_org);4545 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),4546 rsp, rsp_org);4547 break;4548 case FILE_INTERNAL_INFORMATION:4549 get_internal_info_pipe(rsp, id, rsp_org);4550 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),4551 rsp, rsp_org);4552 break;4553 default:4554 ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n",4555 req->FileInfoClass);4556 rc = -EOPNOTSUPP;4557 }4558 return rc;4559}4560 4561/**4562 * smb2_get_ea() - handler for smb2 get extended attribute command4563 * @work: smb work containing query info command buffer4564 * @fp: ksmbd_file pointer4565 * @req: get extended attribute request4566 * @rsp: response buffer pointer4567 * @rsp_org: base response buffer pointer in case of chained response4568 *4569 * Return: 0 on success, otherwise error4570 */4571static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,4572 struct smb2_query_info_req *req,4573 struct smb2_query_info_rsp *rsp, void *rsp_org)4574{4575 struct smb2_ea_info *eainfo, *prev_eainfo;4576 char *name, *ptr, *xattr_list = NULL, *buf;4577 int rc, name_len, value_len, xattr_list_len, idx;4578 ssize_t buf_free_len, alignment_bytes, next_offset, rsp_data_cnt = 0;4579 struct smb2_ea_info_req *ea_req = NULL;4580 const struct path *path;4581 struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);4582 4583 if (!(fp->daccess & FILE_READ_EA_LE)) {4584 pr_err("Not permitted to read ext attr : 0x%x\n",4585 fp->daccess);4586 return -EACCES;4587 }4588 4589 path = &fp->filp->f_path;4590 /* single EA entry is requested with given user.* name */4591 if (req->InputBufferLength) {4592 if (le32_to_cpu(req->InputBufferLength) <=4593 sizeof(struct smb2_ea_info_req))4594 return -EINVAL;4595 4596 ea_req = (struct smb2_ea_info_req *)((char *)req +4597 le16_to_cpu(req->InputBufferOffset));4598 } else {4599 /* need to send all EAs, if no specific EA is requested*/4600 if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY)4601 ksmbd_debug(SMB,4602 "All EAs are requested but need to send single EA entry in rsp flags 0x%x\n",4603 le32_to_cpu(req->Flags));4604 }4605 4606 buf_free_len =4607 smb2_calc_max_out_buf_len(work, 8,4608 le32_to_cpu(req->OutputBufferLength));4609 if (buf_free_len < 0)4610 return -EINVAL;4611 4612 rc = ksmbd_vfs_listxattr(path->dentry, &xattr_list);4613 if (rc < 0) {4614 rsp->hdr.Status = STATUS_INVALID_HANDLE;4615 goto out;4616 } else if (!rc) { /* there is no EA in the file */4617 ksmbd_debug(SMB, "no ea data in the file\n");4618 goto done;4619 }4620 xattr_list_len = rc;4621 4622 ptr = (char *)rsp->Buffer;4623 eainfo = (struct smb2_ea_info *)ptr;4624 prev_eainfo = eainfo;4625 idx = 0;4626 4627 while (idx < xattr_list_len) {4628 name = xattr_list + idx;4629 name_len = strlen(name);4630 4631 ksmbd_debug(SMB, "%s, len %d\n", name, name_len);4632 idx += name_len + 1;4633 4634 /*4635 * CIFS does not support EA other than user.* namespace,4636 * still keep the framework generic, to list other attrs4637 * in future.4638 */4639 if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))4640 continue;4641 4642 if (!strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,4643 STREAM_PREFIX_LEN))4644 continue;4645 4646 if (req->InputBufferLength &&4647 strncmp(&name[XATTR_USER_PREFIX_LEN], ea_req->name,4648 ea_req->EaNameLength))4649 continue;4650 4651 if (!strncmp(&name[XATTR_USER_PREFIX_LEN],4652 DOS_ATTRIBUTE_PREFIX, DOS_ATTRIBUTE_PREFIX_LEN))4653 continue;4654 4655 if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))4656 name_len -= XATTR_USER_PREFIX_LEN;4657 4658 ptr = eainfo->name + name_len + 1;4659 buf_free_len -= (offsetof(struct smb2_ea_info, name) +4660 name_len + 1);4661 /* bailout if xattr can't fit in buf_free_len */4662 value_len = ksmbd_vfs_getxattr(idmap, path->dentry,4663 name, &buf);4664 if (value_len <= 0) {4665 rc = -ENOENT;4666 rsp->hdr.Status = STATUS_INVALID_HANDLE;4667 goto out;4668 }4669 4670 buf_free_len -= value_len;4671 if (buf_free_len < 0) {4672 kfree(buf);4673 break;4674 }4675 4676 memcpy(ptr, buf, value_len);4677 kfree(buf);4678 4679 ptr += value_len;4680 eainfo->Flags = 0;4681 eainfo->EaNameLength = name_len;4682 4683 if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))4684 memcpy(eainfo->name, &name[XATTR_USER_PREFIX_LEN],4685 name_len);4686 else4687 memcpy(eainfo->name, name, name_len);4688 4689 eainfo->name[name_len] = '\0';4690 eainfo->EaValueLength = cpu_to_le16(value_len);4691 next_offset = offsetof(struct smb2_ea_info, name) +4692 name_len + 1 + value_len;4693 4694 /* align next xattr entry at 4 byte bundary */4695 alignment_bytes = ((next_offset + 3) & ~3) - next_offset;4696 if (alignment_bytes) {4697 memset(ptr, '\0', alignment_bytes);4698 ptr += alignment_bytes;4699 next_offset += alignment_bytes;4700 buf_free_len -= alignment_bytes;4701 }4702 eainfo->NextEntryOffset = cpu_to_le32(next_offset);4703 prev_eainfo = eainfo;4704 eainfo = (struct smb2_ea_info *)ptr;4705 rsp_data_cnt += next_offset;4706 4707 if (req->InputBufferLength) {4708 ksmbd_debug(SMB, "single entry requested\n");4709 break;4710 }4711 }4712 4713 /* no more ea entries */4714 prev_eainfo->NextEntryOffset = 0;4715done:4716 rc = 0;4717 if (rsp_data_cnt == 0)4718 rsp->hdr.Status = STATUS_NO_EAS_ON_FILE;4719 rsp->OutputBufferLength = cpu_to_le32(rsp_data_cnt);4720out:4721 kvfree(xattr_list);4722 return rc;4723}4724 4725static void get_file_access_info(struct smb2_query_info_rsp *rsp,4726 struct ksmbd_file *fp, void *rsp_org)4727{4728 struct smb2_file_access_info *file_info;4729 4730 file_info = (struct smb2_file_access_info *)rsp->Buffer;4731 file_info->AccessFlags = fp->daccess;4732 rsp->OutputBufferLength =4733 cpu_to_le32(sizeof(struct smb2_file_access_info));4734}4735 4736static int get_file_basic_info(struct smb2_query_info_rsp *rsp,4737 struct ksmbd_file *fp, void *rsp_org)4738{4739 struct smb2_file_basic_info *basic_info;4740 struct kstat stat;4741 u64 time;4742 int ret;4743 4744 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {4745 pr_err("no right to read the attributes : 0x%x\n",4746 fp->daccess);4747 return -EACCES;4748 }4749 4750 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,4751 AT_STATX_SYNC_AS_STAT);4752 if (ret)4753 return ret;4754 4755 basic_info = (struct smb2_file_basic_info *)rsp->Buffer;4756 basic_info->CreationTime = cpu_to_le64(fp->create_time);4757 time = ksmbd_UnixTimeToNT(stat.atime);4758 basic_info->LastAccessTime = cpu_to_le64(time);4759 time = ksmbd_UnixTimeToNT(stat.mtime);4760 basic_info->LastWriteTime = cpu_to_le64(time);4761 time = ksmbd_UnixTimeToNT(stat.ctime);4762 basic_info->ChangeTime = cpu_to_le64(time);4763 basic_info->Attributes = fp->f_ci->m_fattr;4764 basic_info->Pad1 = 0;4765 rsp->OutputBufferLength =4766 cpu_to_le32(sizeof(struct smb2_file_basic_info));4767 return 0;4768}4769 4770static int get_file_standard_info(struct smb2_query_info_rsp *rsp,4771 struct ksmbd_file *fp, void *rsp_org)4772{4773 struct smb2_file_standard_info *sinfo;4774 unsigned int delete_pending;4775 struct kstat stat;4776 int ret;4777 4778 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,4779 AT_STATX_SYNC_AS_STAT);4780 if (ret)4781 return ret;4782 4783 sinfo = (struct smb2_file_standard_info *)rsp->Buffer;4784 delete_pending = ksmbd_inode_pending_delete(fp);4785 4786 sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);4787 sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);4788 sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);4789 sinfo->DeletePending = delete_pending;4790 sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0;4791 rsp->OutputBufferLength =4792 cpu_to_le32(sizeof(struct smb2_file_standard_info));4793 4794 return 0;4795}4796 4797static void get_file_alignment_info(struct smb2_query_info_rsp *rsp,4798 void *rsp_org)4799{4800 struct smb2_file_alignment_info *file_info;4801 4802 file_info = (struct smb2_file_alignment_info *)rsp->Buffer;4803 file_info->AlignmentRequirement = 0;4804 rsp->OutputBufferLength =4805 cpu_to_le32(sizeof(struct smb2_file_alignment_info));4806}4807 4808static int get_file_all_info(struct ksmbd_work *work,4809 struct smb2_query_info_rsp *rsp,4810 struct ksmbd_file *fp,4811 void *rsp_org)4812{4813 struct ksmbd_conn *conn = work->conn;4814 struct smb2_file_all_info *file_info;4815 unsigned int delete_pending;4816 struct kstat stat;4817 int conv_len;4818 char *filename;4819 u64 time;4820 int ret;4821 4822 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {4823 ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n",4824 fp->daccess);4825 return -EACCES;4826 }4827 4828 filename = convert_to_nt_pathname(work->tcon->share_conf, &fp->filp->f_path);4829 if (IS_ERR(filename))4830 return PTR_ERR(filename);4831 4832 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,4833 AT_STATX_SYNC_AS_STAT);4834 if (ret)4835 return ret;4836 4837 ksmbd_debug(SMB, "filename = %s\n", filename);4838 delete_pending = ksmbd_inode_pending_delete(fp);4839 file_info = (struct smb2_file_all_info *)rsp->Buffer;4840 4841 file_info->CreationTime = cpu_to_le64(fp->create_time);4842 time = ksmbd_UnixTimeToNT(stat.atime);4843 file_info->LastAccessTime = cpu_to_le64(time);4844 time = ksmbd_UnixTimeToNT(stat.mtime);4845 file_info->LastWriteTime = cpu_to_le64(time);4846 time = ksmbd_UnixTimeToNT(stat.ctime);4847 file_info->ChangeTime = cpu_to_le64(time);4848 file_info->Attributes = fp->f_ci->m_fattr;4849 file_info->Pad1 = 0;4850 file_info->AllocationSize =4851 cpu_to_le64(stat.blocks << 9);4852 file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);4853 file_info->NumberOfLinks =4854 cpu_to_le32(get_nlink(&stat) - delete_pending);4855 file_info->DeletePending = delete_pending;4856 file_info->Directory = S_ISDIR(stat.mode) ? 1 : 0;4857 file_info->Pad2 = 0;4858 file_info->IndexNumber = cpu_to_le64(stat.ino);4859 file_info->EASize = 0;4860 file_info->AccessFlags = fp->daccess;4861 file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);4862 file_info->Mode = fp->coption;4863 file_info->AlignmentRequirement = 0;4864 conv_len = smbConvertToUTF16((__le16 *)file_info->FileName, filename,4865 PATH_MAX, conn->local_nls, 0);4866 conv_len *= 2;4867 file_info->FileNameLength = cpu_to_le32(conv_len);4868 rsp->OutputBufferLength =4869 cpu_to_le32(sizeof(struct smb2_file_all_info) + conv_len - 1);4870 kfree(filename);4871 return 0;4872}4873 4874static void get_file_alternate_info(struct ksmbd_work *work,4875 struct smb2_query_info_rsp *rsp,4876 struct ksmbd_file *fp,4877 void *rsp_org)4878{4879 struct ksmbd_conn *conn = work->conn;4880 struct smb2_file_alt_name_info *file_info;4881 struct dentry *dentry = fp->filp->f_path.dentry;4882 int conv_len;4883 4884 spin_lock(&dentry->d_lock);4885 file_info = (struct smb2_file_alt_name_info *)rsp->Buffer;4886 conv_len = ksmbd_extract_shortname(conn,4887 dentry->d_name.name,4888 file_info->FileName);4889 spin_unlock(&dentry->d_lock);4890 file_info->FileNameLength = cpu_to_le32(conv_len);4891 rsp->OutputBufferLength =4892 cpu_to_le32(struct_size(file_info, FileName, conv_len));4893}4894 4895static int get_file_stream_info(struct ksmbd_work *work,4896 struct smb2_query_info_rsp *rsp,4897 struct ksmbd_file *fp,4898 void *rsp_org)4899{4900 struct ksmbd_conn *conn = work->conn;4901 struct smb2_file_stream_info *file_info;4902 char *stream_name, *xattr_list = NULL, *stream_buf;4903 struct kstat stat;4904 const struct path *path = &fp->filp->f_path;4905 ssize_t xattr_list_len;4906 int nbytes = 0, streamlen, stream_name_len, next, idx = 0;4907 int buf_free_len;4908 struct smb2_query_info_req *req = ksmbd_req_buf_next(work);4909 int ret;4910 4911 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,4912 AT_STATX_SYNC_AS_STAT);4913 if (ret)4914 return ret;4915 4916 file_info = (struct smb2_file_stream_info *)rsp->Buffer;4917 4918 buf_free_len =4919 smb2_calc_max_out_buf_len(work, 8,4920 le32_to_cpu(req->OutputBufferLength));4921 if (buf_free_len < 0)4922 goto out;4923 4924 xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);4925 if (xattr_list_len < 0) {4926 goto out;4927 } else if (!xattr_list_len) {4928 ksmbd_debug(SMB, "empty xattr in the file\n");4929 goto out;4930 }4931 4932 while (idx < xattr_list_len) {4933 stream_name = xattr_list + idx;4934 streamlen = strlen(stream_name);4935 idx += streamlen + 1;4936 4937 ksmbd_debug(SMB, "%s, len %d\n", stream_name, streamlen);4938 4939 if (strncmp(&stream_name[XATTR_USER_PREFIX_LEN],4940 STREAM_PREFIX, STREAM_PREFIX_LEN))4941 continue;4942 4943 stream_name_len = streamlen - (XATTR_USER_PREFIX_LEN +4944 STREAM_PREFIX_LEN);4945 streamlen = stream_name_len;4946 4947 /* plus : size */4948 streamlen += 1;4949 stream_buf = kmalloc(streamlen + 1, GFP_KERNEL);4950 if (!stream_buf)4951 break;4952 4953 streamlen = snprintf(stream_buf, streamlen + 1,4954 ":%s", &stream_name[XATTR_NAME_STREAM_LEN]);4955 4956 next = sizeof(struct smb2_file_stream_info) + streamlen * 2;4957 if (next > buf_free_len) {4958 kfree(stream_buf);4959 break;4960 }4961 4962 file_info = (struct smb2_file_stream_info *)&rsp->Buffer[nbytes];4963 streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName,4964 stream_buf, streamlen,4965 conn->local_nls, 0);4966 streamlen *= 2;4967 kfree(stream_buf);4968 file_info->StreamNameLength = cpu_to_le32(streamlen);4969 file_info->StreamSize = cpu_to_le64(stream_name_len);4970 file_info->StreamAllocationSize = cpu_to_le64(stream_name_len);4971 4972 nbytes += next;4973 buf_free_len -= next;4974 file_info->NextEntryOffset = cpu_to_le32(next);4975 }4976 4977out:4978 if (!S_ISDIR(stat.mode) &&4979 buf_free_len >= sizeof(struct smb2_file_stream_info) + 7 * 2) {4980 file_info = (struct smb2_file_stream_info *)4981 &rsp->Buffer[nbytes];4982 streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName,4983 "::$DATA", 7, conn->local_nls, 0);4984 streamlen *= 2;4985 file_info->StreamNameLength = cpu_to_le32(streamlen);4986 file_info->StreamSize = cpu_to_le64(stat.size);4987 file_info->StreamAllocationSize = cpu_to_le64(stat.blocks << 9);4988 nbytes += sizeof(struct smb2_file_stream_info) + streamlen;4989 }4990 4991 /* last entry offset should be 0 */4992 file_info->NextEntryOffset = 0;4993 kvfree(xattr_list);4994 4995 rsp->OutputBufferLength = cpu_to_le32(nbytes);4996 4997 return 0;4998}4999 5000static int get_file_internal_info(struct smb2_query_info_rsp *rsp,5001 struct ksmbd_file *fp, void *rsp_org)5002{5003 struct smb2_file_internal_info *file_info;5004 struct kstat stat;5005 int ret;5006 5007 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,5008 AT_STATX_SYNC_AS_STAT);5009 if (ret)5010 return ret;5011 5012 file_info = (struct smb2_file_internal_info *)rsp->Buffer;5013 file_info->IndexNumber = cpu_to_le64(stat.ino);5014 rsp->OutputBufferLength =5015 cpu_to_le32(sizeof(struct smb2_file_internal_info));5016 5017 return 0;5018}5019 5020static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,5021 struct ksmbd_file *fp, void *rsp_org)5022{5023 struct smb2_file_ntwrk_info *file_info;5024 struct kstat stat;5025 u64 time;5026 int ret;5027 5028 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {5029 pr_err("no right to read the attributes : 0x%x\n",5030 fp->daccess);5031 return -EACCES;5032 }5033 5034 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,5035 AT_STATX_SYNC_AS_STAT);5036 if (ret)5037 return ret;5038 5039 file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;5040 5041 file_info->CreationTime = cpu_to_le64(fp->create_time);5042 time = ksmbd_UnixTimeToNT(stat.atime);5043 file_info->LastAccessTime = cpu_to_le64(time);5044 time = ksmbd_UnixTimeToNT(stat.mtime);5045 file_info->LastWriteTime = cpu_to_le64(time);5046 time = ksmbd_UnixTimeToNT(stat.ctime);5047 file_info->ChangeTime = cpu_to_le64(time);5048 file_info->Attributes = fp->f_ci->m_fattr;5049 file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);5050 file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);5051 file_info->Reserved = cpu_to_le32(0);5052 rsp->OutputBufferLength =5053 cpu_to_le32(sizeof(struct smb2_file_ntwrk_info));5054 return 0;5055}5056 5057static void get_file_ea_info(struct smb2_query_info_rsp *rsp, void *rsp_org)5058{5059 struct smb2_file_ea_info *file_info;5060 5061 file_info = (struct smb2_file_ea_info *)rsp->Buffer;5062 file_info->EASize = 0;5063 rsp->OutputBufferLength =5064 cpu_to_le32(sizeof(struct smb2_file_ea_info));5065}5066 5067static void get_file_position_info(struct smb2_query_info_rsp *rsp,5068 struct ksmbd_file *fp, void *rsp_org)5069{5070 struct smb2_file_pos_info *file_info;5071 5072 file_info = (struct smb2_file_pos_info *)rsp->Buffer;5073 file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);5074 rsp->OutputBufferLength =5075 cpu_to_le32(sizeof(struct smb2_file_pos_info));5076}5077 5078static void get_file_mode_info(struct smb2_query_info_rsp *rsp,5079 struct ksmbd_file *fp, void *rsp_org)5080{5081 struct smb2_file_mode_info *file_info;5082 5083 file_info = (struct smb2_file_mode_info *)rsp->Buffer;5084 file_info->Mode = fp->coption & FILE_MODE_INFO_MASK;5085 rsp->OutputBufferLength =5086 cpu_to_le32(sizeof(struct smb2_file_mode_info));5087}5088 5089static int get_file_compression_info(struct smb2_query_info_rsp *rsp,5090 struct ksmbd_file *fp, void *rsp_org)5091{5092 struct smb2_file_comp_info *file_info;5093 struct kstat stat;5094 int ret;5095 5096 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,5097 AT_STATX_SYNC_AS_STAT);5098 if (ret)5099 return ret;5100 5101 file_info = (struct smb2_file_comp_info *)rsp->Buffer;5102 file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9);5103 file_info->CompressionFormat = COMPRESSION_FORMAT_NONE;5104 file_info->CompressionUnitShift = 0;5105 file_info->ChunkShift = 0;5106 file_info->ClusterShift = 0;5107 memset(&file_info->Reserved[0], 0, 3);5108 5109 rsp->OutputBufferLength =5110 cpu_to_le32(sizeof(struct smb2_file_comp_info));5111 5112 return 0;5113}5114 5115static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,5116 struct ksmbd_file *fp, void *rsp_org)5117{5118 struct smb2_file_attr_tag_info *file_info;5119 5120 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {5121 pr_err("no right to read the attributes : 0x%x\n",5122 fp->daccess);5123 return -EACCES;5124 }5125 5126 file_info = (struct smb2_file_attr_tag_info *)rsp->Buffer;5127 file_info->FileAttributes = fp->f_ci->m_fattr;5128 file_info->ReparseTag = 0;5129 rsp->OutputBufferLength =5130 cpu_to_le32(sizeof(struct smb2_file_attr_tag_info));5131 return 0;5132}5133 5134static int find_file_posix_info(struct smb2_query_info_rsp *rsp,5135 struct ksmbd_file *fp, void *rsp_org)5136{5137 struct smb311_posix_qinfo *file_info;5138 struct inode *inode = file_inode(fp->filp);5139 struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);5140 vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);5141 vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);5142 struct kstat stat;5143 u64 time;5144 int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32;5145 int ret;5146 5147 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,5148 AT_STATX_SYNC_AS_STAT);5149 if (ret)5150 return ret;5151 5152 file_info = (struct smb311_posix_qinfo *)rsp->Buffer;5153 file_info->CreationTime = cpu_to_le64(fp->create_time);5154 time = ksmbd_UnixTimeToNT(stat.atime);5155 file_info->LastAccessTime = cpu_to_le64(time);5156 time = ksmbd_UnixTimeToNT(stat.mtime);5157 file_info->LastWriteTime = cpu_to_le64(time);5158 time = ksmbd_UnixTimeToNT(stat.ctime);5159 file_info->ChangeTime = cpu_to_le64(time);5160 file_info->DosAttributes = fp->f_ci->m_fattr;5161 file_info->Inode = cpu_to_le64(stat.ino);5162 file_info->EndOfFile = cpu_to_le64(stat.size);5163 file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);5164 file_info->HardLinks = cpu_to_le32(stat.nlink);5165 file_info->Mode = cpu_to_le32(stat.mode & 0777);5166 file_info->DeviceId = cpu_to_le32(stat.rdev);5167 5168 /*5169 * Sids(32) contain two sids(Domain sid(16), UNIX group sid(16)).5170 * UNIX sid(16) = revision(1) + num_subauth(1) + authority(6) +5171 * sub_auth(4 * 1(num_subauth)) + RID(4).5172 */5173 id_to_sid(from_kuid_munged(&init_user_ns, vfsuid_into_kuid(vfsuid)),5174 SIDUNIX_USER, (struct smb_sid *)&file_info->Sids[0]);5175 id_to_sid(from_kgid_munged(&init_user_ns, vfsgid_into_kgid(vfsgid)),5176 SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]);5177 5178 rsp->OutputBufferLength = cpu_to_le32(out_buf_len);5179 5180 return 0;5181}5182 5183static int smb2_get_info_file(struct ksmbd_work *work,5184 struct smb2_query_info_req *req,5185 struct smb2_query_info_rsp *rsp)5186{5187 struct ksmbd_file *fp;5188 int fileinfoclass = 0;5189 int rc = 0;5190 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;5191 5192 if (test_share_config_flag(work->tcon->share_conf,5193 KSMBD_SHARE_FLAG_PIPE)) {5194 /* smb2 info file called for pipe */5195 return smb2_get_info_file_pipe(work->sess, req, rsp,5196 work->response_buf);5197 }5198 5199 if (work->next_smb2_rcv_hdr_off) {5200 if (!has_file_id(req->VolatileFileId)) {5201 ksmbd_debug(SMB, "Compound request set FID = %llu\n",5202 work->compound_fid);5203 id = work->compound_fid;5204 pid = work->compound_pfid;5205 }5206 }5207 5208 if (!has_file_id(id)) {5209 id = req->VolatileFileId;5210 pid = req->PersistentFileId;5211 }5212 5213 fp = ksmbd_lookup_fd_slow(work, id, pid);5214 if (!fp)5215 return -ENOENT;5216 5217 fileinfoclass = req->FileInfoClass;5218 5219 switch (fileinfoclass) {5220 case FILE_ACCESS_INFORMATION:5221 get_file_access_info(rsp, fp, work->response_buf);5222 break;5223 5224 case FILE_BASIC_INFORMATION:5225 rc = get_file_basic_info(rsp, fp, work->response_buf);5226 break;5227 5228 case FILE_STANDARD_INFORMATION:5229 rc = get_file_standard_info(rsp, fp, work->response_buf);5230 break;5231 5232 case FILE_ALIGNMENT_INFORMATION:5233 get_file_alignment_info(rsp, work->response_buf);5234 break;5235 5236 case FILE_ALL_INFORMATION:5237 rc = get_file_all_info(work, rsp, fp, work->response_buf);5238 break;5239 5240 case FILE_ALTERNATE_NAME_INFORMATION:5241 get_file_alternate_info(work, rsp, fp, work->response_buf);5242 break;5243 5244 case FILE_STREAM_INFORMATION:5245 rc = get_file_stream_info(work, rsp, fp, work->response_buf);5246 break;5247 5248 case FILE_INTERNAL_INFORMATION:5249 rc = get_file_internal_info(rsp, fp, work->response_buf);5250 break;5251 5252 case FILE_NETWORK_OPEN_INFORMATION:5253 rc = get_file_network_open_info(rsp, fp, work->response_buf);5254 break;5255 5256 case FILE_EA_INFORMATION:5257 get_file_ea_info(rsp, work->response_buf);5258 break;5259 5260 case FILE_FULL_EA_INFORMATION:5261 rc = smb2_get_ea(work, fp, req, rsp, work->response_buf);5262 break;5263 5264 case FILE_POSITION_INFORMATION:5265 get_file_position_info(rsp, fp, work->response_buf);5266 break;5267 5268 case FILE_MODE_INFORMATION:5269 get_file_mode_info(rsp, fp, work->response_buf);5270 break;5271 5272 case FILE_COMPRESSION_INFORMATION:5273 rc = get_file_compression_info(rsp, fp, work->response_buf);5274 break;5275 5276 case FILE_ATTRIBUTE_TAG_INFORMATION:5277 rc = get_file_attribute_tag_info(rsp, fp, work->response_buf);5278 break;5279 case SMB_FIND_FILE_POSIX_INFO:5280 if (!work->tcon->posix_extensions) {5281 pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");5282 rc = -EOPNOTSUPP;5283 } else {5284 rc = find_file_posix_info(rsp, fp, work->response_buf);5285 }5286 break;5287 default:5288 ksmbd_debug(SMB, "fileinfoclass %d not supported yet\n",5289 fileinfoclass);5290 rc = -EOPNOTSUPP;5291 }5292 if (!rc)5293 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),5294 rsp, work->response_buf);5295 ksmbd_fd_put(work, fp);5296 return rc;5297}5298 5299static int smb2_get_info_filesystem(struct ksmbd_work *work,5300 struct smb2_query_info_req *req,5301 struct smb2_query_info_rsp *rsp)5302{5303 struct ksmbd_session *sess = work->sess;5304 struct ksmbd_conn *conn = work->conn;5305 struct ksmbd_share_config *share = work->tcon->share_conf;5306 int fsinfoclass = 0;5307 struct kstatfs stfs;5308 struct path path;5309 int rc = 0, len;5310 5311 if (!share->path)5312 return -EIO;5313 5314 rc = kern_path(share->path, LOOKUP_NO_SYMLINKS, &path);5315 if (rc) {5316 pr_err("cannot create vfs path\n");5317 return -EIO;5318 }5319 5320 rc = vfs_statfs(&path, &stfs);5321 if (rc) {5322 pr_err("cannot do stat of path %s\n", share->path);5323 path_put(&path);5324 return -EIO;5325 }5326 5327 fsinfoclass = req->FileInfoClass;5328 5329 switch (fsinfoclass) {5330 case FS_DEVICE_INFORMATION:5331 {5332 struct filesystem_device_info *info;5333 5334 info = (struct filesystem_device_info *)rsp->Buffer;5335 5336 info->DeviceType = cpu_to_le32(FILE_DEVICE_DISK);5337 info->DeviceCharacteristics =5338 cpu_to_le32(FILE_DEVICE_IS_MOUNTED);5339 if (!test_tree_conn_flag(work->tcon,5340 KSMBD_TREE_CONN_FLAG_WRITABLE))5341 info->DeviceCharacteristics |=5342 cpu_to_le32(FILE_READ_ONLY_DEVICE);5343 rsp->OutputBufferLength = cpu_to_le32(8);5344 break;5345 }5346 case FS_ATTRIBUTE_INFORMATION:5347 {5348 struct filesystem_attribute_info *info;5349 size_t sz;5350 5351 info = (struct filesystem_attribute_info *)rsp->Buffer;5352 info->Attributes = cpu_to_le32(FILE_SUPPORTS_OBJECT_IDS |5353 FILE_PERSISTENT_ACLS |5354 FILE_UNICODE_ON_DISK |5355 FILE_CASE_PRESERVED_NAMES |5356 FILE_CASE_SENSITIVE_SEARCH |5357 FILE_SUPPORTS_BLOCK_REFCOUNTING);5358 5359 info->Attributes |= cpu_to_le32(server_conf.share_fake_fscaps);5360 5361 if (test_share_config_flag(work->tcon->share_conf,5362 KSMBD_SHARE_FLAG_STREAMS))5363 info->Attributes |= cpu_to_le32(FILE_NAMED_STREAMS);5364 5365 info->MaxPathNameComponentLength = cpu_to_le32(stfs.f_namelen);5366 len = smbConvertToUTF16((__le16 *)info->FileSystemName,5367 "NTFS", PATH_MAX, conn->local_nls, 0);5368 len = len * 2;5369 info->FileSystemNameLen = cpu_to_le32(len);5370 sz = sizeof(struct filesystem_attribute_info) + len;5371 rsp->OutputBufferLength = cpu_to_le32(sz);5372 break;5373 }5374 case FS_VOLUME_INFORMATION:5375 {5376 struct filesystem_vol_info *info;5377 size_t sz;5378 unsigned int serial_crc = 0;5379 5380 info = (struct filesystem_vol_info *)(rsp->Buffer);5381 info->VolumeCreationTime = 0;5382 serial_crc = crc32_le(serial_crc, share->name,5383 strlen(share->name));5384 serial_crc = crc32_le(serial_crc, share->path,5385 strlen(share->path));5386 serial_crc = crc32_le(serial_crc, ksmbd_netbios_name(),5387 strlen(ksmbd_netbios_name()));5388 /* Taking dummy value of serial number*/5389 info->SerialNumber = cpu_to_le32(serial_crc);5390 len = smbConvertToUTF16((__le16 *)info->VolumeLabel,5391 share->name, PATH_MAX,5392 conn->local_nls, 0);5393 len = len * 2;5394 info->VolumeLabelSize = cpu_to_le32(len);5395 info->Reserved = 0;5396 sz = sizeof(struct filesystem_vol_info) + len;5397 rsp->OutputBufferLength = cpu_to_le32(sz);5398 break;5399 }5400 case FS_SIZE_INFORMATION:5401 {5402 struct filesystem_info *info;5403 5404 info = (struct filesystem_info *)(rsp->Buffer);5405 info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks);5406 info->FreeAllocationUnits = cpu_to_le64(stfs.f_bfree);5407 info->SectorsPerAllocationUnit = cpu_to_le32(1);5408 info->BytesPerSector = cpu_to_le32(stfs.f_bsize);5409 rsp->OutputBufferLength = cpu_to_le32(24);5410 break;5411 }5412 case FS_FULL_SIZE_INFORMATION:5413 {5414 struct smb2_fs_full_size_info *info;5415 5416 info = (struct smb2_fs_full_size_info *)(rsp->Buffer);5417 info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks);5418 info->CallerAvailableAllocationUnits =5419 cpu_to_le64(stfs.f_bavail);5420 info->ActualAvailableAllocationUnits =5421 cpu_to_le64(stfs.f_bfree);5422 info->SectorsPerAllocationUnit = cpu_to_le32(1);5423 info->BytesPerSector = cpu_to_le32(stfs.f_bsize);5424 rsp->OutputBufferLength = cpu_to_le32(32);5425 break;5426 }5427 case FS_OBJECT_ID_INFORMATION:5428 {5429 struct object_id_info *info;5430 5431 info = (struct object_id_info *)(rsp->Buffer);5432 5433 if (!user_guest(sess->user))5434 memcpy(info->objid, user_passkey(sess->user), 16);5435 else5436 memset(info->objid, 0, 16);5437 5438 info->extended_info.magic = cpu_to_le32(EXTENDED_INFO_MAGIC);5439 info->extended_info.version = cpu_to_le32(1);5440 info->extended_info.release = cpu_to_le32(1);5441 info->extended_info.rel_date = 0;5442 memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0"));5443 rsp->OutputBufferLength = cpu_to_le32(64);5444 break;5445 }5446 case FS_SECTOR_SIZE_INFORMATION:5447 {5448 struct smb3_fs_ss_info *info;5449 unsigned int sector_size =5450 min_t(unsigned int, path.mnt->mnt_sb->s_blocksize, 4096);5451 5452 info = (struct smb3_fs_ss_info *)(rsp->Buffer);5453 5454 info->LogicalBytesPerSector = cpu_to_le32(sector_size);5455 info->PhysicalBytesPerSectorForAtomicity =5456 cpu_to_le32(sector_size);5457 info->PhysicalBytesPerSectorForPerf = cpu_to_le32(sector_size);5458 info->FSEffPhysicalBytesPerSectorForAtomicity =5459 cpu_to_le32(sector_size);5460 info->Flags = cpu_to_le32(SSINFO_FLAGS_ALIGNED_DEVICE |5461 SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE);5462 info->ByteOffsetForSectorAlignment = 0;5463 info->ByteOffsetForPartitionAlignment = 0;5464 rsp->OutputBufferLength = cpu_to_le32(28);5465 break;5466 }5467 case FS_CONTROL_INFORMATION:5468 {5469 /*5470 * TODO : The current implementation is based on5471 * test result with win7(NTFS) server. It's need to5472 * modify this to get valid Quota values5473 * from Linux kernel5474 */5475 struct smb2_fs_control_info *info;5476 5477 info = (struct smb2_fs_control_info *)(rsp->Buffer);5478 info->FreeSpaceStartFiltering = 0;5479 info->FreeSpaceThreshold = 0;5480 info->FreeSpaceStopFiltering = 0;5481 info->DefaultQuotaThreshold = cpu_to_le64(SMB2_NO_FID);5482 info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID);5483 info->Padding = 0;5484 rsp->OutputBufferLength = cpu_to_le32(48);5485 break;5486 }5487 case FS_POSIX_INFORMATION:5488 {5489 struct filesystem_posix_info *info;5490 5491 if (!work->tcon->posix_extensions) {5492 pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");5493 rc = -EOPNOTSUPP;5494 } else {5495 info = (struct filesystem_posix_info *)(rsp->Buffer);5496 info->OptimalTransferSize = cpu_to_le32(stfs.f_bsize);5497 info->BlockSize = cpu_to_le32(stfs.f_bsize);5498 info->TotalBlocks = cpu_to_le64(stfs.f_blocks);5499 info->BlocksAvail = cpu_to_le64(stfs.f_bfree);5500 info->UserBlocksAvail = cpu_to_le64(stfs.f_bavail);5501 info->TotalFileNodes = cpu_to_le64(stfs.f_files);5502 info->FreeFileNodes = cpu_to_le64(stfs.f_ffree);5503 rsp->OutputBufferLength = cpu_to_le32(56);5504 }5505 break;5506 }5507 default:5508 path_put(&path);5509 return -EOPNOTSUPP;5510 }5511 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),5512 rsp, work->response_buf);5513 path_put(&path);5514 return rc;5515}5516 5517static int smb2_get_info_sec(struct ksmbd_work *work,5518 struct smb2_query_info_req *req,5519 struct smb2_query_info_rsp *rsp)5520{5521 struct ksmbd_file *fp;5522 struct mnt_idmap *idmap;5523 struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL;5524 struct smb_fattr fattr = {{0}};5525 struct inode *inode;5526 __u32 secdesclen = 0;5527 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;5528 int addition_info = le32_to_cpu(req->AdditionalInformation);5529 int rc = 0, ppntsd_size = 0;5530 5531 if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |5532 PROTECTED_DACL_SECINFO |5533 UNPROTECTED_DACL_SECINFO)) {5534 ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n",5535 addition_info);5536 5537 pntsd->revision = cpu_to_le16(1);5538 pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED);5539 pntsd->osidoffset = 0;5540 pntsd->gsidoffset = 0;5541 pntsd->sacloffset = 0;5542 pntsd->dacloffset = 0;5543 5544 secdesclen = sizeof(struct smb_ntsd);5545 rsp->OutputBufferLength = cpu_to_le32(secdesclen);5546 5547 return 0;5548 }5549 5550 if (work->next_smb2_rcv_hdr_off) {5551 if (!has_file_id(req->VolatileFileId)) {5552 ksmbd_debug(SMB, "Compound request set FID = %llu\n",5553 work->compound_fid);5554 id = work->compound_fid;5555 pid = work->compound_pfid;5556 }5557 }5558 5559 if (!has_file_id(id)) {5560 id = req->VolatileFileId;5561 pid = req->PersistentFileId;5562 }5563 5564 fp = ksmbd_lookup_fd_slow(work, id, pid);5565 if (!fp)5566 return -ENOENT;5567 5568 idmap = file_mnt_idmap(fp->filp);5569 inode = file_inode(fp->filp);5570 ksmbd_acls_fattr(&fattr, idmap, inode);5571 5572 if (test_share_config_flag(work->tcon->share_conf,5573 KSMBD_SHARE_FLAG_ACL_XATTR))5574 ppntsd_size = ksmbd_vfs_get_sd_xattr(work->conn, idmap,5575 fp->filp->f_path.dentry,5576 &ppntsd);5577 5578 /* Check if sd buffer size exceeds response buffer size */5579 if (smb2_resp_buf_len(work, 8) > ppntsd_size)5580 rc = build_sec_desc(idmap, pntsd, ppntsd, ppntsd_size,5581 addition_info, &secdesclen, &fattr);5582 posix_acl_release(fattr.cf_acls);5583 posix_acl_release(fattr.cf_dacls);5584 kfree(ppntsd);5585 ksmbd_fd_put(work, fp);5586 if (rc)5587 return rc;5588 5589 rsp->OutputBufferLength = cpu_to_le32(secdesclen);5590 return 0;5591}5592 5593/**5594 * smb2_query_info() - handler for smb2 query info command5595 * @work: smb work containing query info request buffer5596 *5597 * Return: 0 on success, otherwise error5598 */5599int smb2_query_info(struct ksmbd_work *work)5600{5601 struct smb2_query_info_req *req;5602 struct smb2_query_info_rsp *rsp;5603 int rc = 0;5604 5605 WORK_BUFFERS(work, req, rsp);5606 5607 ksmbd_debug(SMB, "GOT query info request\n");5608 5609 if (ksmbd_override_fsids(work)) {5610 rc = -ENOMEM;5611 goto err_out;5612 }5613 5614 switch (req->InfoType) {5615 case SMB2_O_INFO_FILE:5616 ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n");5617 rc = smb2_get_info_file(work, req, rsp);5618 break;5619 case SMB2_O_INFO_FILESYSTEM:5620 ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILESYSTEM\n");5621 rc = smb2_get_info_filesystem(work, req, rsp);5622 break;5623 case SMB2_O_INFO_SECURITY:5624 ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n");5625 rc = smb2_get_info_sec(work, req, rsp);5626 break;5627 default:5628 ksmbd_debug(SMB, "InfoType %d not supported yet\n",5629 req->InfoType);5630 rc = -EOPNOTSUPP;5631 }5632 ksmbd_revert_fsids(work);5633 5634 if (!rc) {5635 rsp->StructureSize = cpu_to_le16(9);5636 rsp->OutputBufferOffset = cpu_to_le16(72);5637 rc = ksmbd_iov_pin_rsp(work, (void *)rsp,5638 offsetof(struct smb2_query_info_rsp, Buffer) +5639 le32_to_cpu(rsp->OutputBufferLength));5640 }5641 5642err_out:5643 if (rc < 0) {5644 if (rc == -EACCES)5645 rsp->hdr.Status = STATUS_ACCESS_DENIED;5646 else if (rc == -ENOENT)5647 rsp->hdr.Status = STATUS_FILE_CLOSED;5648 else if (rc == -EIO)5649 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;5650 else if (rc == -ENOMEM)5651 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;5652 else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0)5653 rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;5654 smb2_set_err_rsp(work);5655 5656 ksmbd_debug(SMB, "error while processing smb2 query rc = %d\n",5657 rc);5658 return rc;5659 }5660 return 0;5661}5662 5663/**5664 * smb2_close_pipe() - handler for closing IPC pipe5665 * @work: smb work containing close request buffer5666 *5667 * Return: 05668 */5669static noinline int smb2_close_pipe(struct ksmbd_work *work)5670{5671 u64 id;5672 struct smb2_close_req *req;5673 struct smb2_close_rsp *rsp;5674 5675 WORK_BUFFERS(work, req, rsp);5676 5677 id = req->VolatileFileId;5678 ksmbd_session_rpc_close(work->sess, id);5679 5680 rsp->StructureSize = cpu_to_le16(60);5681 rsp->Flags = 0;5682 rsp->Reserved = 0;5683 rsp->CreationTime = 0;5684 rsp->LastAccessTime = 0;5685 rsp->LastWriteTime = 0;5686 rsp->ChangeTime = 0;5687 rsp->AllocationSize = 0;5688 rsp->EndOfFile = 0;5689 rsp->Attributes = 0;5690 5691 return ksmbd_iov_pin_rsp(work, (void *)rsp,5692 sizeof(struct smb2_close_rsp));5693}5694 5695/**5696 * smb2_close() - handler for smb2 close file command5697 * @work: smb work containing close request buffer5698 *5699 * Return: 05700 */5701int smb2_close(struct ksmbd_work *work)5702{5703 u64 volatile_id = KSMBD_NO_FID;5704 u64 sess_id;5705 struct smb2_close_req *req;5706 struct smb2_close_rsp *rsp;5707 struct ksmbd_conn *conn = work->conn;5708 struct ksmbd_file *fp;5709 u64 time;5710 int err = 0;5711 5712 WORK_BUFFERS(work, req, rsp);5713 5714 if (test_share_config_flag(work->tcon->share_conf,5715 KSMBD_SHARE_FLAG_PIPE)) {5716 ksmbd_debug(SMB, "IPC pipe close request\n");5717 return smb2_close_pipe(work);5718 }5719 5720 sess_id = le64_to_cpu(req->hdr.SessionId);5721 if (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS)5722 sess_id = work->compound_sid;5723 5724 work->compound_sid = 0;5725 if (check_session_id(conn, sess_id)) {5726 work->compound_sid = sess_id;5727 } else {5728 rsp->hdr.Status = STATUS_USER_SESSION_DELETED;5729 if (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS)5730 rsp->hdr.Status = STATUS_INVALID_PARAMETER;5731 err = -EBADF;5732 goto out;5733 }5734 5735 if (work->next_smb2_rcv_hdr_off &&5736 !has_file_id(req->VolatileFileId)) {5737 if (!has_file_id(work->compound_fid)) {5738 /* file already closed, return FILE_CLOSED */5739 ksmbd_debug(SMB, "file already closed\n");5740 rsp->hdr.Status = STATUS_FILE_CLOSED;5741 err = -EBADF;5742 goto out;5743 } else {5744 ksmbd_debug(SMB,5745 "Compound request set FID = %llu:%llu\n",5746 work->compound_fid,5747 work->compound_pfid);5748 volatile_id = work->compound_fid;5749 5750 /* file closed, stored id is not valid anymore */5751 work->compound_fid = KSMBD_NO_FID;5752 work->compound_pfid = KSMBD_NO_FID;5753 }5754 } else {5755 volatile_id = req->VolatileFileId;5756 }5757 ksmbd_debug(SMB, "volatile_id = %llu\n", volatile_id);5758 5759 rsp->StructureSize = cpu_to_le16(60);5760 rsp->Reserved = 0;5761 5762 if (req->Flags == SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB) {5763 struct kstat stat;5764 int ret;5765 5766 fp = ksmbd_lookup_fd_fast(work, volatile_id);5767 if (!fp) {5768 err = -ENOENT;5769 goto out;5770 }5771 5772 ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,5773 AT_STATX_SYNC_AS_STAT);5774 if (ret) {5775 ksmbd_fd_put(work, fp);5776 goto out;5777 }5778 5779 rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;5780 rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :5781 cpu_to_le64(stat.blocks << 9);5782 rsp->EndOfFile = cpu_to_le64(stat.size);5783 rsp->Attributes = fp->f_ci->m_fattr;5784 rsp->CreationTime = cpu_to_le64(fp->create_time);5785 time = ksmbd_UnixTimeToNT(stat.atime);5786 rsp->LastAccessTime = cpu_to_le64(time);5787 time = ksmbd_UnixTimeToNT(stat.mtime);5788 rsp->LastWriteTime = cpu_to_le64(time);5789 time = ksmbd_UnixTimeToNT(stat.ctime);5790 rsp->ChangeTime = cpu_to_le64(time);5791 ksmbd_fd_put(work, fp);5792 } else {5793 rsp->Flags = 0;5794 rsp->AllocationSize = 0;5795 rsp->EndOfFile = 0;5796 rsp->Attributes = 0;5797 rsp->CreationTime = 0;5798 rsp->LastAccessTime = 0;5799 rsp->LastWriteTime = 0;5800 rsp->ChangeTime = 0;5801 }5802 5803 err = ksmbd_close_fd(work, volatile_id);5804out:5805 if (!err)5806 err = ksmbd_iov_pin_rsp(work, (void *)rsp,5807 sizeof(struct smb2_close_rsp));5808 5809 if (err) {5810 if (rsp->hdr.Status == 0)5811 rsp->hdr.Status = STATUS_FILE_CLOSED;5812 smb2_set_err_rsp(work);5813 }5814 5815 return err;5816}5817 5818/**5819 * smb2_echo() - handler for smb2 echo(ping) command5820 * @work: smb work containing echo request buffer5821 *5822 * Return: 05823 */5824int smb2_echo(struct ksmbd_work *work)5825{5826 struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf);5827 5828 if (work->next_smb2_rcv_hdr_off)5829 rsp = ksmbd_resp_buf_next(work);5830 5831 rsp->StructureSize = cpu_to_le16(4);5832 rsp->Reserved = 0;5833 return ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_echo_rsp));5834}5835 5836static int smb2_rename(struct ksmbd_work *work,5837 struct ksmbd_file *fp,5838 struct smb2_file_rename_info *file_info,5839 struct nls_table *local_nls)5840{5841 struct ksmbd_share_config *share = fp->tcon->share_conf;5842 char *new_name = NULL;5843 int rc, flags = 0;5844 5845 ksmbd_debug(SMB, "setting FILE_RENAME_INFO\n");5846 new_name = smb2_get_name(file_info->FileName,5847 le32_to_cpu(file_info->FileNameLength),5848 local_nls);5849 if (IS_ERR(new_name))5850 return PTR_ERR(new_name);5851 5852 if (strchr(new_name, ':')) {5853 int s_type;5854 char *xattr_stream_name, *stream_name = NULL;5855 size_t xattr_stream_size;5856 int len;5857 5858 rc = parse_stream_name(new_name, &stream_name, &s_type);5859 if (rc < 0)5860 goto out;5861 5862 len = strlen(new_name);5863 if (len > 0 && new_name[len - 1] != '/') {5864 pr_err("not allow base filename in rename\n");5865 rc = -ESHARE;5866 goto out;5867 }5868 5869 rc = ksmbd_vfs_xattr_stream_name(stream_name,5870 &xattr_stream_name,5871 &xattr_stream_size,5872 s_type);5873 if (rc)5874 goto out;5875 5876 rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp),5877 &fp->filp->f_path,5878 xattr_stream_name,5879 NULL, 0, 0, true);5880 if (rc < 0) {5881 pr_err("failed to store stream name in xattr: %d\n",5882 rc);5883 rc = -EINVAL;5884 goto out;5885 }5886 5887 goto out;5888 }5889 5890 ksmbd_debug(SMB, "new name %s\n", new_name);5891 if (ksmbd_share_veto_filename(share, new_name)) {5892 rc = -ENOENT;5893 ksmbd_debug(SMB, "Can't rename vetoed file: %s\n", new_name);5894 goto out;5895 }5896 5897 if (!file_info->ReplaceIfExists)5898 flags = RENAME_NOREPLACE;5899 5900 rc = ksmbd_vfs_rename(work, &fp->filp->f_path, new_name, flags);5901 if (!rc)5902 smb_break_all_levII_oplock(work, fp, 0);5903out:5904 kfree(new_name);5905 return rc;5906}5907 5908static int smb2_create_link(struct ksmbd_work *work,5909 struct ksmbd_share_config *share,5910 struct smb2_file_link_info *file_info,5911 unsigned int buf_len, struct file *filp,5912 struct nls_table *local_nls)5913{5914 char *link_name = NULL, *target_name = NULL, *pathname = NULL;5915 struct path path, parent_path;5916 bool file_present = false;5917 int rc;5918 5919 if (buf_len < (u64)sizeof(struct smb2_file_link_info) +5920 le32_to_cpu(file_info->FileNameLength))5921 return -EINVAL;5922 5923 ksmbd_debug(SMB, "setting FILE_LINK_INFORMATION\n");5924 pathname = kmalloc(PATH_MAX, GFP_KERNEL);5925 if (!pathname)5926 return -ENOMEM;5927 5928 link_name = smb2_get_name(file_info->FileName,5929 le32_to_cpu(file_info->FileNameLength),5930 local_nls);5931 if (IS_ERR(link_name) || S_ISDIR(file_inode(filp)->i_mode)) {5932 rc = -EINVAL;5933 goto out;5934 }5935 5936 ksmbd_debug(SMB, "link name is %s\n", link_name);5937 target_name = file_path(filp, pathname, PATH_MAX);5938 if (IS_ERR(target_name)) {5939 rc = -EINVAL;5940 goto out;5941 }5942 5943 ksmbd_debug(SMB, "target name is %s\n", target_name);5944 rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS,5945 &parent_path, &path, 0);5946 if (rc) {5947 if (rc != -ENOENT)5948 goto out;5949 } else5950 file_present = true;5951 5952 if (file_info->ReplaceIfExists) {5953 if (file_present) {5954 rc = ksmbd_vfs_remove_file(work, &path);5955 if (rc) {5956 rc = -EINVAL;5957 ksmbd_debug(SMB, "cannot delete %s\n",5958 link_name);5959 goto out;5960 }5961 }5962 } else {5963 if (file_present) {5964 rc = -EEXIST;5965 ksmbd_debug(SMB, "link already exists\n");5966 goto out;5967 }5968 }5969 5970 rc = ksmbd_vfs_link(work, target_name, link_name);5971 if (rc)5972 rc = -EINVAL;5973out:5974 if (file_present)5975 ksmbd_vfs_kern_path_unlock(&parent_path, &path);5976 5977 if (!IS_ERR(link_name))5978 kfree(link_name);5979 kfree(pathname);5980 return rc;5981}5982 5983static int set_file_basic_info(struct ksmbd_file *fp,5984 struct smb2_file_basic_info *file_info,5985 struct ksmbd_share_config *share)5986{5987 struct iattr attrs;5988 struct file *filp;5989 struct inode *inode;5990 struct mnt_idmap *idmap;5991 int rc = 0;5992 5993 if (!(fp->daccess & FILE_WRITE_ATTRIBUTES_LE))5994 return -EACCES;5995 5996 attrs.ia_valid = 0;5997 filp = fp->filp;5998 inode = file_inode(filp);5999 idmap = file_mnt_idmap(filp);6000 6001 if (file_info->CreationTime)6002 fp->create_time = le64_to_cpu(file_info->CreationTime);6003 6004 if (file_info->LastAccessTime) {6005 attrs.ia_atime = ksmbd_NTtimeToUnix(file_info->LastAccessTime);6006 attrs.ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);6007 }6008 6009 attrs.ia_valid |= ATTR_CTIME;6010 if (file_info->ChangeTime)6011 attrs.ia_ctime = ksmbd_NTtimeToUnix(file_info->ChangeTime);6012 else6013 attrs.ia_ctime = inode_get_ctime(inode);6014 6015 if (file_info->LastWriteTime) {6016 attrs.ia_mtime = ksmbd_NTtimeToUnix(file_info->LastWriteTime);6017 attrs.ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);6018 }6019 6020 if (file_info->Attributes) {6021 if (!S_ISDIR(inode->i_mode) &&6022 file_info->Attributes & FILE_ATTRIBUTE_DIRECTORY_LE) {6023 pr_err("can't change a file to a directory\n");6024 return -EINVAL;6025 }6026 6027 if (!(S_ISDIR(inode->i_mode) && file_info->Attributes == FILE_ATTRIBUTE_NORMAL_LE))6028 fp->f_ci->m_fattr = file_info->Attributes |6029 (fp->f_ci->m_fattr & FILE_ATTRIBUTE_DIRECTORY_LE);6030 }6031 6032 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS) &&6033 (file_info->CreationTime || file_info->Attributes)) {6034 struct xattr_dos_attrib da = {0};6035 6036 da.version = 4;6037 da.itime = fp->itime;6038 da.create_time = fp->create_time;6039 da.attr = le32_to_cpu(fp->f_ci->m_fattr);6040 da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |6041 XATTR_DOSINFO_ITIME;6042 6043 rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, &filp->f_path, &da,6044 true);6045 if (rc)6046 ksmbd_debug(SMB,6047 "failed to restore file attribute in EA\n");6048 rc = 0;6049 }6050 6051 if (attrs.ia_valid) {6052 struct dentry *dentry = filp->f_path.dentry;6053 struct inode *inode = d_inode(dentry);6054 6055 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))6056 return -EACCES;6057 6058 inode_lock(inode);6059 inode_set_ctime_to_ts(inode, attrs.ia_ctime);6060 attrs.ia_valid &= ~ATTR_CTIME;6061 rc = notify_change(idmap, dentry, &attrs, NULL);6062 inode_unlock(inode);6063 }6064 return rc;6065}6066 6067static int set_file_allocation_info(struct ksmbd_work *work,6068 struct ksmbd_file *fp,6069 struct smb2_file_alloc_info *file_alloc_info)6070{6071 /*6072 * TODO : It's working fine only when store dos attributes6073 * is not yes. need to implement a logic which works6074 * properly with any smb.conf option6075 */6076 6077 loff_t alloc_blks;6078 struct inode *inode;6079 struct kstat stat;6080 int rc;6081 6082 if (!(fp->daccess & FILE_WRITE_DATA_LE))6083 return -EACCES;6084 6085 rc = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,6086 AT_STATX_SYNC_AS_STAT);6087 if (rc)6088 return rc;6089 6090 alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9;6091 inode = file_inode(fp->filp);6092 6093 if (alloc_blks > stat.blocks) {6094 smb_break_all_levII_oplock(work, fp, 1);6095 rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,6096 alloc_blks * 512);6097 if (rc && rc != -EOPNOTSUPP) {6098 pr_err("vfs_fallocate is failed : %d\n", rc);6099 return rc;6100 }6101 } else if (alloc_blks < stat.blocks) {6102 loff_t size;6103 6104 /*6105 * Allocation size could be smaller than original one6106 * which means allocated blocks in file should be6107 * deallocated. use truncate to cut out it, but inode6108 * size is also updated with truncate offset.6109 * inode size is retained by backup inode size.6110 */6111 size = i_size_read(inode);6112 rc = ksmbd_vfs_truncate(work, fp, alloc_blks * 512);6113 if (rc) {6114 pr_err("truncate failed!, err %d\n", rc);6115 return rc;6116 }6117 if (size < alloc_blks * 512)6118 i_size_write(inode, size);6119 }6120 return 0;6121}6122 6123static int set_end_of_file_info(struct ksmbd_work *work, struct ksmbd_file *fp,6124 struct smb2_file_eof_info *file_eof_info)6125{6126 loff_t newsize;6127 struct inode *inode;6128 int rc;6129 6130 if (!(fp->daccess & FILE_WRITE_DATA_LE))6131 return -EACCES;6132 6133 newsize = le64_to_cpu(file_eof_info->EndOfFile);6134 inode = file_inode(fp->filp);6135 6136 /*6137 * If FILE_END_OF_FILE_INFORMATION of set_info_file is called6138 * on FAT32 shared device, truncate execution time is too long6139 * and network error could cause from windows client. because6140 * truncate of some filesystem like FAT32 fill zero data in6141 * truncated range.6142 */6143 if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) {6144 ksmbd_debug(SMB, "truncated to newsize %lld\n", newsize);6145 rc = ksmbd_vfs_truncate(work, fp, newsize);6146 if (rc) {6147 ksmbd_debug(SMB, "truncate failed!, err %d\n", rc);6148 if (rc != -EAGAIN)6149 rc = -EBADF;6150 return rc;6151 }6152 }6153 return 0;6154}6155 6156static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,6157 struct smb2_file_rename_info *rename_info,6158 unsigned int buf_len)6159{6160 if (!(fp->daccess & FILE_DELETE_LE)) {6161 pr_err("no right to delete : 0x%x\n", fp->daccess);6162 return -EACCES;6163 }6164 6165 if (buf_len < (u64)sizeof(struct smb2_file_rename_info) +6166 le32_to_cpu(rename_info->FileNameLength))6167 return -EINVAL;6168 6169 if (!le32_to_cpu(rename_info->FileNameLength))6170 return -EINVAL;6171 6172 return smb2_rename(work, fp, rename_info, work->conn->local_nls);6173}6174 6175static int set_file_disposition_info(struct ksmbd_file *fp,6176 struct smb2_file_disposition_info *file_info)6177{6178 struct inode *inode;6179 6180 if (!(fp->daccess & FILE_DELETE_LE)) {6181 pr_err("no right to delete : 0x%x\n", fp->daccess);6182 return -EACCES;6183 }6184 6185 inode = file_inode(fp->filp);6186 if (file_info->DeletePending) {6187 if (S_ISDIR(inode->i_mode) &&6188 ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY)6189 return -EBUSY;6190 ksmbd_set_inode_pending_delete(fp);6191 } else {6192 ksmbd_clear_inode_pending_delete(fp);6193 }6194 return 0;6195}6196 6197static int set_file_position_info(struct ksmbd_file *fp,6198 struct smb2_file_pos_info *file_info)6199{6200 loff_t current_byte_offset;6201 unsigned long sector_size;6202 struct inode *inode;6203 6204 inode = file_inode(fp->filp);6205 current_byte_offset = le64_to_cpu(file_info->CurrentByteOffset);6206 sector_size = inode->i_sb->s_blocksize;6207 6208 if (current_byte_offset < 0 ||6209 (fp->coption == FILE_NO_INTERMEDIATE_BUFFERING_LE &&6210 current_byte_offset & (sector_size - 1))) {6211 pr_err("CurrentByteOffset is not valid : %llu\n",6212 current_byte_offset);6213 return -EINVAL;6214 }6215 6216 fp->filp->f_pos = current_byte_offset;6217 return 0;6218}6219 6220static int set_file_mode_info(struct ksmbd_file *fp,6221 struct smb2_file_mode_info *file_info)6222{6223 __le32 mode;6224 6225 mode = file_info->Mode;6226 6227 if ((mode & ~FILE_MODE_INFO_MASK)) {6228 pr_err("Mode is not valid : 0x%x\n", le32_to_cpu(mode));6229 return -EINVAL;6230 }6231 6232 /*6233 * TODO : need to implement consideration for6234 * FILE_SYNCHRONOUS_IO_ALERT and FILE_SYNCHRONOUS_IO_NONALERT6235 */6236 ksmbd_vfs_set_fadvise(fp->filp, mode);6237 fp->coption = mode;6238 return 0;6239}6240 6241/**6242 * smb2_set_info_file() - handler for smb2 set info command6243 * @work: smb work containing set info command buffer6244 * @fp: ksmbd_file pointer6245 * @req: request buffer pointer6246 * @share: ksmbd_share_config pointer6247 *6248 * Return: 0 on success, otherwise error6249 * TODO: need to implement an error handling for STATUS_INFO_LENGTH_MISMATCH6250 */6251static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,6252 struct smb2_set_info_req *req,6253 struct ksmbd_share_config *share)6254{6255 unsigned int buf_len = le32_to_cpu(req->BufferLength);6256 char *buffer = (char *)req + le16_to_cpu(req->BufferOffset);6257 6258 switch (req->FileInfoClass) {6259 case FILE_BASIC_INFORMATION:6260 {6261 if (buf_len < sizeof(struct smb2_file_basic_info))6262 return -EINVAL;6263 6264 return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share);6265 }6266 case FILE_ALLOCATION_INFORMATION:6267 {6268 if (buf_len < sizeof(struct smb2_file_alloc_info))6269 return -EINVAL;6270 6271 return set_file_allocation_info(work, fp,6272 (struct smb2_file_alloc_info *)buffer);6273 }6274 case FILE_END_OF_FILE_INFORMATION:6275 {6276 if (buf_len < sizeof(struct smb2_file_eof_info))6277 return -EINVAL;6278 6279 return set_end_of_file_info(work, fp,6280 (struct smb2_file_eof_info *)buffer);6281 }6282 case FILE_RENAME_INFORMATION:6283 {6284 if (buf_len < sizeof(struct smb2_file_rename_info))6285 return -EINVAL;6286 6287 return set_rename_info(work, fp,6288 (struct smb2_file_rename_info *)buffer,6289 buf_len);6290 }6291 case FILE_LINK_INFORMATION:6292 {6293 if (buf_len < sizeof(struct smb2_file_link_info))6294 return -EINVAL;6295 6296 return smb2_create_link(work, work->tcon->share_conf,6297 (struct smb2_file_link_info *)buffer,6298 buf_len, fp->filp,6299 work->conn->local_nls);6300 }6301 case FILE_DISPOSITION_INFORMATION:6302 {6303 if (buf_len < sizeof(struct smb2_file_disposition_info))6304 return -EINVAL;6305 6306 return set_file_disposition_info(fp,6307 (struct smb2_file_disposition_info *)buffer);6308 }6309 case FILE_FULL_EA_INFORMATION:6310 {6311 if (!(fp->daccess & FILE_WRITE_EA_LE)) {6312 pr_err("Not permitted to write ext attr: 0x%x\n",6313 fp->daccess);6314 return -EACCES;6315 }6316 6317 if (buf_len < sizeof(struct smb2_ea_info))6318 return -EINVAL;6319 6320 return smb2_set_ea((struct smb2_ea_info *)buffer,6321 buf_len, &fp->filp->f_path, true);6322 }6323 case FILE_POSITION_INFORMATION:6324 {6325 if (buf_len < sizeof(struct smb2_file_pos_info))6326 return -EINVAL;6327 6328 return set_file_position_info(fp, (struct smb2_file_pos_info *)buffer);6329 }6330 case FILE_MODE_INFORMATION:6331 {6332 if (buf_len < sizeof(struct smb2_file_mode_info))6333 return -EINVAL;6334 6335 return set_file_mode_info(fp, (struct smb2_file_mode_info *)buffer);6336 }6337 }6338 6339 pr_err("Unimplemented Fileinfoclass :%d\n", req->FileInfoClass);6340 return -EOPNOTSUPP;6341}6342 6343static int smb2_set_info_sec(struct ksmbd_file *fp, int addition_info,6344 char *buffer, int buf_len)6345{6346 struct smb_ntsd *pntsd = (struct smb_ntsd *)buffer;6347 6348 fp->saccess |= FILE_SHARE_DELETE_LE;6349 6350 return set_info_sec(fp->conn, fp->tcon, &fp->filp->f_path, pntsd,6351 buf_len, false, true);6352}6353 6354/**6355 * smb2_set_info() - handler for smb2 set info command handler6356 * @work: smb work containing set info request buffer6357 *6358 * Return: 0 on success, otherwise error6359 */6360int smb2_set_info(struct ksmbd_work *work)6361{6362 struct smb2_set_info_req *req;6363 struct smb2_set_info_rsp *rsp;6364 struct ksmbd_file *fp = NULL;6365 int rc = 0;6366 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;6367 6368 ksmbd_debug(SMB, "Received set info request\n");6369 6370 if (work->next_smb2_rcv_hdr_off) {6371 req = ksmbd_req_buf_next(work);6372 rsp = ksmbd_resp_buf_next(work);6373 if (!has_file_id(req->VolatileFileId)) {6374 ksmbd_debug(SMB, "Compound request set FID = %llu\n",6375 work->compound_fid);6376 id = work->compound_fid;6377 pid = work->compound_pfid;6378 }6379 } else {6380 req = smb2_get_msg(work->request_buf);6381 rsp = smb2_get_msg(work->response_buf);6382 }6383 6384 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {6385 ksmbd_debug(SMB, "User does not have write permission\n");6386 pr_err("User does not have write permission\n");6387 rc = -EACCES;6388 goto err_out;6389 }6390 6391 if (!has_file_id(id)) {6392 id = req->VolatileFileId;6393 pid = req->PersistentFileId;6394 }6395 6396 fp = ksmbd_lookup_fd_slow(work, id, pid);6397 if (!fp) {6398 ksmbd_debug(SMB, "Invalid id for close: %u\n", id);6399 rc = -ENOENT;6400 goto err_out;6401 }6402 6403 switch (req->InfoType) {6404 case SMB2_O_INFO_FILE:6405 ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n");6406 rc = smb2_set_info_file(work, fp, req, work->tcon->share_conf);6407 break;6408 case SMB2_O_INFO_SECURITY:6409 ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n");6410 if (ksmbd_override_fsids(work)) {6411 rc = -ENOMEM;6412 goto err_out;6413 }6414 rc = smb2_set_info_sec(fp,6415 le32_to_cpu(req->AdditionalInformation),6416 (char *)req + le16_to_cpu(req->BufferOffset),6417 le32_to_cpu(req->BufferLength));6418 ksmbd_revert_fsids(work);6419 break;6420 default:6421 rc = -EOPNOTSUPP;6422 }6423 6424 if (rc < 0)6425 goto err_out;6426 6427 rsp->StructureSize = cpu_to_le16(2);6428 rc = ksmbd_iov_pin_rsp(work, (void *)rsp,6429 sizeof(struct smb2_set_info_rsp));6430 if (rc)6431 goto err_out;6432 ksmbd_fd_put(work, fp);6433 return 0;6434 6435err_out:6436 if (rc == -EACCES || rc == -EPERM || rc == -EXDEV)6437 rsp->hdr.Status = STATUS_ACCESS_DENIED;6438 else if (rc == -EINVAL)6439 rsp->hdr.Status = STATUS_INVALID_PARAMETER;6440 else if (rc == -ESHARE)6441 rsp->hdr.Status = STATUS_SHARING_VIOLATION;6442 else if (rc == -ENOENT)6443 rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID;6444 else if (rc == -EBUSY || rc == -ENOTEMPTY)6445 rsp->hdr.Status = STATUS_DIRECTORY_NOT_EMPTY;6446 else if (rc == -EAGAIN)6447 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;6448 else if (rc == -EBADF || rc == -ESTALE)6449 rsp->hdr.Status = STATUS_INVALID_HANDLE;6450 else if (rc == -EEXIST)6451 rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION;6452 else if (rsp->hdr.Status == 0 || rc == -EOPNOTSUPP)6453 rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;6454 smb2_set_err_rsp(work);6455 ksmbd_fd_put(work, fp);6456 ksmbd_debug(SMB, "error while processing smb2 query rc = %d\n", rc);6457 return rc;6458}6459 6460/**6461 * smb2_read_pipe() - handler for smb2 read from IPC pipe6462 * @work: smb work containing read IPC pipe command buffer6463 *6464 * Return: 0 on success, otherwise error6465 */6466static noinline int smb2_read_pipe(struct ksmbd_work *work)6467{6468 int nbytes = 0, err;6469 u64 id;6470 struct ksmbd_rpc_command *rpc_resp;6471 struct smb2_read_req *req;6472 struct smb2_read_rsp *rsp;6473 6474 WORK_BUFFERS(work, req, rsp);6475 6476 id = req->VolatileFileId;6477 6478 rpc_resp = ksmbd_rpc_read(work->sess, id);6479 if (rpc_resp) {6480 void *aux_payload_buf;6481 6482 if (rpc_resp->flags != KSMBD_RPC_OK) {6483 err = -EINVAL;6484 goto out;6485 }6486 6487 aux_payload_buf =6488 kvmalloc(rpc_resp->payload_sz, GFP_KERNEL);6489 if (!aux_payload_buf) {6490 err = -ENOMEM;6491 goto out;6492 }6493 6494 memcpy(aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz);6495 6496 nbytes = rpc_resp->payload_sz;6497 err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,6498 offsetof(struct smb2_read_rsp, Buffer),6499 aux_payload_buf, nbytes);6500 if (err) {6501 kvfree(aux_payload_buf);6502 goto out;6503 }6504 kvfree(rpc_resp);6505 } else {6506 err = ksmbd_iov_pin_rsp(work, (void *)rsp,6507 offsetof(struct smb2_read_rsp, Buffer));6508 if (err)6509 goto out;6510 }6511 6512 rsp->StructureSize = cpu_to_le16(17);6513 rsp->DataOffset = 80;6514 rsp->Reserved = 0;6515 rsp->DataLength = cpu_to_le32(nbytes);6516 rsp->DataRemaining = 0;6517 rsp->Flags = 0;6518 return 0;6519 6520out:6521 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;6522 smb2_set_err_rsp(work);6523 kvfree(rpc_resp);6524 return err;6525}6526 6527static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work,6528 struct smb2_buffer_desc_v1 *desc,6529 __le32 Channel,6530 __le16 ChannelInfoLength)6531{6532 unsigned int i, ch_count;6533 6534 if (work->conn->dialect == SMB30_PROT_ID &&6535 Channel != SMB2_CHANNEL_RDMA_V1)6536 return -EINVAL;6537 6538 ch_count = le16_to_cpu(ChannelInfoLength) / sizeof(*desc);6539 if (ksmbd_debug_types & KSMBD_DEBUG_RDMA) {6540 for (i = 0; i < ch_count; i++) {6541 pr_info("RDMA r/w request %#x: token %#x, length %#x\n",6542 i,6543 le32_to_cpu(desc[i].token),6544 le32_to_cpu(desc[i].length));6545 }6546 }6547 if (!ch_count)6548 return -EINVAL;6549 6550 work->need_invalidate_rkey =6551 (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);6552 if (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE)6553 work->remote_key = le32_to_cpu(desc->token);6554 return 0;6555}6556 6557static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work,6558 struct smb2_read_req *req, void *data_buf,6559 size_t length)6560{6561 int err;6562 6563 err = ksmbd_conn_rdma_write(work->conn, data_buf, length,6564 (struct smb2_buffer_desc_v1 *)6565 ((char *)req + le16_to_cpu(req->ReadChannelInfoOffset)),6566 le16_to_cpu(req->ReadChannelInfoLength));6567 if (err)6568 return err;6569 6570 return length;6571}6572 6573/**6574 * smb2_read() - handler for smb2 read from file6575 * @work: smb work containing read command buffer6576 *6577 * Return: 0 on success, otherwise error6578 */6579int smb2_read(struct ksmbd_work *work)6580{6581 struct ksmbd_conn *conn = work->conn;6582 struct smb2_read_req *req;6583 struct smb2_read_rsp *rsp;6584 struct ksmbd_file *fp = NULL;6585 loff_t offset;6586 size_t length, mincount;6587 ssize_t nbytes = 0, remain_bytes = 0;6588 int err = 0;6589 bool is_rdma_channel = false;6590 unsigned int max_read_size = conn->vals->max_read_size;6591 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;6592 void *aux_payload_buf;6593 6594 if (test_share_config_flag(work->tcon->share_conf,6595 KSMBD_SHARE_FLAG_PIPE)) {6596 ksmbd_debug(SMB, "IPC pipe read request\n");6597 return smb2_read_pipe(work);6598 }6599 6600 if (work->next_smb2_rcv_hdr_off) {6601 req = ksmbd_req_buf_next(work);6602 rsp = ksmbd_resp_buf_next(work);6603 if (!has_file_id(req->VolatileFileId)) {6604 ksmbd_debug(SMB, "Compound request set FID = %llu\n",6605 work->compound_fid);6606 id = work->compound_fid;6607 pid = work->compound_pfid;6608 }6609 } else {6610 req = smb2_get_msg(work->request_buf);6611 rsp = smb2_get_msg(work->response_buf);6612 }6613 6614 if (!has_file_id(id)) {6615 id = req->VolatileFileId;6616 pid = req->PersistentFileId;6617 }6618 6619 if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE ||6620 req->Channel == SMB2_CHANNEL_RDMA_V1) {6621 is_rdma_channel = true;6622 max_read_size = get_smbd_max_read_write_size();6623 }6624 6625 if (is_rdma_channel == true) {6626 unsigned int ch_offset = le16_to_cpu(req->ReadChannelInfoOffset);6627 6628 if (ch_offset < offsetof(struct smb2_read_req, Buffer)) {6629 err = -EINVAL;6630 goto out;6631 }6632 err = smb2_set_remote_key_for_rdma(work,6633 (struct smb2_buffer_desc_v1 *)6634 ((char *)req + ch_offset),6635 req->Channel,6636 req->ReadChannelInfoLength);6637 if (err)6638 goto out;6639 }6640 6641 fp = ksmbd_lookup_fd_slow(work, id, pid);6642 if (!fp) {6643 err = -ENOENT;6644 goto out;6645 }6646 6647 if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_READ_ATTRIBUTES_LE))) {6648 pr_err("Not permitted to read : 0x%x\n", fp->daccess);6649 err = -EACCES;6650 goto out;6651 }6652 6653 offset = le64_to_cpu(req->Offset);6654 length = le32_to_cpu(req->Length);6655 mincount = le32_to_cpu(req->MinimumCount);6656 6657 if (length > max_read_size) {6658 ksmbd_debug(SMB, "limiting read size to max size(%u)\n",6659 max_read_size);6660 err = -EINVAL;6661 goto out;6662 }6663 6664 ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n",6665 fp->filp, offset, length);6666 6667 aux_payload_buf = kvzalloc(length, GFP_KERNEL);6668 if (!aux_payload_buf) {6669 err = -ENOMEM;6670 goto out;6671 }6672 6673 nbytes = ksmbd_vfs_read(work, fp, length, &offset, aux_payload_buf);6674 if (nbytes < 0) {6675 err = nbytes;6676 goto out;6677 }6678 6679 if ((nbytes == 0 && length != 0) || nbytes < mincount) {6680 kvfree(aux_payload_buf);6681 rsp->hdr.Status = STATUS_END_OF_FILE;6682 smb2_set_err_rsp(work);6683 ksmbd_fd_put(work, fp);6684 return 0;6685 }6686 6687 ksmbd_debug(SMB, "nbytes %zu, offset %lld mincount %zu\n",6688 nbytes, offset, mincount);6689 6690 if (is_rdma_channel == true) {6691 /* write data to the client using rdma channel */6692 remain_bytes = smb2_read_rdma_channel(work, req,6693 aux_payload_buf,6694 nbytes);6695 kvfree(aux_payload_buf);6696 aux_payload_buf = NULL;6697 nbytes = 0;6698 if (remain_bytes < 0) {6699 err = (int)remain_bytes;6700 goto out;6701 }6702 }6703 6704 rsp->StructureSize = cpu_to_le16(17);6705 rsp->DataOffset = 80;6706 rsp->Reserved = 0;6707 rsp->DataLength = cpu_to_le32(nbytes);6708 rsp->DataRemaining = cpu_to_le32(remain_bytes);6709 rsp->Flags = 0;6710 err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,6711 offsetof(struct smb2_read_rsp, Buffer),6712 aux_payload_buf, nbytes);6713 if (err) {6714 kvfree(aux_payload_buf);6715 goto out;6716 }6717 ksmbd_fd_put(work, fp);6718 return 0;6719 6720out:6721 if (err) {6722 if (err == -EISDIR)6723 rsp->hdr.Status = STATUS_INVALID_DEVICE_REQUEST;6724 else if (err == -EAGAIN)6725 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;6726 else if (err == -ENOENT)6727 rsp->hdr.Status = STATUS_FILE_CLOSED;6728 else if (err == -EACCES)6729 rsp->hdr.Status = STATUS_ACCESS_DENIED;6730 else if (err == -ESHARE)6731 rsp->hdr.Status = STATUS_SHARING_VIOLATION;6732 else if (err == -EINVAL)6733 rsp->hdr.Status = STATUS_INVALID_PARAMETER;6734 else6735 rsp->hdr.Status = STATUS_INVALID_HANDLE;6736 6737 smb2_set_err_rsp(work);6738 }6739 ksmbd_fd_put(work, fp);6740 return err;6741}6742 6743/**6744 * smb2_write_pipe() - handler for smb2 write on IPC pipe6745 * @work: smb work containing write IPC pipe command buffer6746 *6747 * Return: 0 on success, otherwise error6748 */6749static noinline int smb2_write_pipe(struct ksmbd_work *work)6750{6751 struct smb2_write_req *req;6752 struct smb2_write_rsp *rsp;6753 struct ksmbd_rpc_command *rpc_resp;6754 u64 id = 0;6755 int err = 0, ret = 0;6756 char *data_buf;6757 size_t length;6758 6759 WORK_BUFFERS(work, req, rsp);6760 6761 length = le32_to_cpu(req->Length);6762 id = req->VolatileFileId;6763 6764 if ((u64)le16_to_cpu(req->DataOffset) + length >6765 get_rfc1002_len(work->request_buf)) {6766 pr_err("invalid write data offset %u, smb_len %u\n",6767 le16_to_cpu(req->DataOffset),6768 get_rfc1002_len(work->request_buf));6769 err = -EINVAL;6770 goto out;6771 }6772 6773 data_buf = (char *)(((char *)&req->hdr.ProtocolId) +6774 le16_to_cpu(req->DataOffset));6775 6776 rpc_resp = ksmbd_rpc_write(work->sess, id, data_buf, length);6777 if (rpc_resp) {6778 if (rpc_resp->flags == KSMBD_RPC_ENOTIMPLEMENTED) {6779 rsp->hdr.Status = STATUS_NOT_SUPPORTED;6780 kvfree(rpc_resp);6781 smb2_set_err_rsp(work);6782 return -EOPNOTSUPP;6783 }6784 if (rpc_resp->flags != KSMBD_RPC_OK) {6785 rsp->hdr.Status = STATUS_INVALID_HANDLE;6786 smb2_set_err_rsp(work);6787 kvfree(rpc_resp);6788 return ret;6789 }6790 kvfree(rpc_resp);6791 }6792 6793 rsp->StructureSize = cpu_to_le16(17);6794 rsp->DataOffset = 0;6795 rsp->Reserved = 0;6796 rsp->DataLength = cpu_to_le32(length);6797 rsp->DataRemaining = 0;6798 rsp->Reserved2 = 0;6799 err = ksmbd_iov_pin_rsp(work, (void *)rsp,6800 offsetof(struct smb2_write_rsp, Buffer));6801out:6802 if (err) {6803 rsp->hdr.Status = STATUS_INVALID_HANDLE;6804 smb2_set_err_rsp(work);6805 }6806 6807 return err;6808}6809 6810static ssize_t smb2_write_rdma_channel(struct ksmbd_work *work,6811 struct smb2_write_req *req,6812 struct ksmbd_file *fp,6813 loff_t offset, size_t length, bool sync)6814{6815 char *data_buf;6816 int ret;6817 ssize_t nbytes;6818 6819 data_buf = kvzalloc(length, GFP_KERNEL);6820 if (!data_buf)6821 return -ENOMEM;6822 6823 ret = ksmbd_conn_rdma_read(work->conn, data_buf, length,6824 (struct smb2_buffer_desc_v1 *)6825 ((char *)req + le16_to_cpu(req->WriteChannelInfoOffset)),6826 le16_to_cpu(req->WriteChannelInfoLength));6827 if (ret < 0) {6828 kvfree(data_buf);6829 return ret;6830 }6831 6832 ret = ksmbd_vfs_write(work, fp, data_buf, length, &offset, sync, &nbytes);6833 kvfree(data_buf);6834 if (ret < 0)6835 return ret;6836 6837 return nbytes;6838}6839 6840/**6841 * smb2_write() - handler for smb2 write from file6842 * @work: smb work containing write command buffer6843 *6844 * Return: 0 on success, otherwise error6845 */6846int smb2_write(struct ksmbd_work *work)6847{6848 struct smb2_write_req *req;6849 struct smb2_write_rsp *rsp;6850 struct ksmbd_file *fp = NULL;6851 loff_t offset;6852 size_t length;6853 ssize_t nbytes;6854 char *data_buf;6855 bool writethrough = false, is_rdma_channel = false;6856 int err = 0;6857 unsigned int max_write_size = work->conn->vals->max_write_size;6858 6859 WORK_BUFFERS(work, req, rsp);6860 6861 if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) {6862 ksmbd_debug(SMB, "IPC pipe write request\n");6863 return smb2_write_pipe(work);6864 }6865 6866 offset = le64_to_cpu(req->Offset);6867 length = le32_to_cpu(req->Length);6868 6869 if (req->Channel == SMB2_CHANNEL_RDMA_V1 ||6870 req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) {6871 is_rdma_channel = true;6872 max_write_size = get_smbd_max_read_write_size();6873 length = le32_to_cpu(req->RemainingBytes);6874 }6875 6876 if (is_rdma_channel == true) {6877 unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset);6878 6879 if (req->Length != 0 || req->DataOffset != 0 ||6880 ch_offset < offsetof(struct smb2_write_req, Buffer)) {6881 err = -EINVAL;6882 goto out;6883 }6884 err = smb2_set_remote_key_for_rdma(work,6885 (struct smb2_buffer_desc_v1 *)6886 ((char *)req + ch_offset),6887 req->Channel,6888 req->WriteChannelInfoLength);6889 if (err)6890 goto out;6891 }6892 6893 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {6894 ksmbd_debug(SMB, "User does not have write permission\n");6895 err = -EACCES;6896 goto out;6897 }6898 6899 fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);6900 if (!fp) {6901 err = -ENOENT;6902 goto out;6903 }6904 6905 if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_READ_ATTRIBUTES_LE))) {6906 pr_err("Not permitted to write : 0x%x\n", fp->daccess);6907 err = -EACCES;6908 goto out;6909 }6910 6911 if (length > max_write_size) {6912 ksmbd_debug(SMB, "limiting write size to max size(%u)\n",6913 max_write_size);6914 err = -EINVAL;6915 goto out;6916 }6917 6918 ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags));6919 if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH)6920 writethrough = true;6921 6922 if (is_rdma_channel == false) {6923 if (le16_to_cpu(req->DataOffset) <6924 offsetof(struct smb2_write_req, Buffer)) {6925 err = -EINVAL;6926 goto out;6927 }6928 6929 data_buf = (char *)(((char *)&req->hdr.ProtocolId) +6930 le16_to_cpu(req->DataOffset));6931 6932 ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n",6933 fp->filp, offset, length);6934 err = ksmbd_vfs_write(work, fp, data_buf, length, &offset,6935 writethrough, &nbytes);6936 if (err < 0)6937 goto out;6938 } else {6939 /* read data from the client using rdma channel, and6940 * write the data.6941 */6942 nbytes = smb2_write_rdma_channel(work, req, fp, offset, length,6943 writethrough);6944 if (nbytes < 0) {6945 err = (int)nbytes;6946 goto out;6947 }6948 }6949 6950 rsp->StructureSize = cpu_to_le16(17);6951 rsp->DataOffset = 0;6952 rsp->Reserved = 0;6953 rsp->DataLength = cpu_to_le32(nbytes);6954 rsp->DataRemaining = 0;6955 rsp->Reserved2 = 0;6956 err = ksmbd_iov_pin_rsp(work, rsp, offsetof(struct smb2_write_rsp, Buffer));6957 if (err)6958 goto out;6959 ksmbd_fd_put(work, fp);6960 return 0;6961 6962out:6963 if (err == -EAGAIN)6964 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;6965 else if (err == -ENOSPC || err == -EFBIG)6966 rsp->hdr.Status = STATUS_DISK_FULL;6967 else if (err == -ENOENT)6968 rsp->hdr.Status = STATUS_FILE_CLOSED;6969 else if (err == -EACCES)6970 rsp->hdr.Status = STATUS_ACCESS_DENIED;6971 else if (err == -ESHARE)6972 rsp->hdr.Status = STATUS_SHARING_VIOLATION;6973 else if (err == -EINVAL)6974 rsp->hdr.Status = STATUS_INVALID_PARAMETER;6975 else6976 rsp->hdr.Status = STATUS_INVALID_HANDLE;6977 6978 smb2_set_err_rsp(work);6979 ksmbd_fd_put(work, fp);6980 return err;6981}6982 6983/**6984 * smb2_flush() - handler for smb2 flush file - fsync6985 * @work: smb work containing flush command buffer6986 *6987 * Return: 0 on success, otherwise error6988 */6989int smb2_flush(struct ksmbd_work *work)6990{6991 struct smb2_flush_req *req;6992 struct smb2_flush_rsp *rsp;6993 int err;6994 6995 WORK_BUFFERS(work, req, rsp);6996 6997 ksmbd_debug(SMB, "SMB2_FLUSH called for fid %llu\n", req->VolatileFileId);6998 6999 err = ksmbd_vfs_fsync(work, req->VolatileFileId, req->PersistentFileId);7000 if (err)7001 goto out;7002 7003 rsp->StructureSize = cpu_to_le16(4);7004 rsp->Reserved = 0;7005 return ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_flush_rsp));7006 7007out:7008 rsp->hdr.Status = STATUS_INVALID_HANDLE;7009 smb2_set_err_rsp(work);7010 return err;7011}7012 7013/**7014 * smb2_cancel() - handler for smb2 cancel command7015 * @work: smb work containing cancel command buffer7016 *7017 * Return: 0 on success, otherwise error7018 */7019int smb2_cancel(struct ksmbd_work *work)7020{7021 struct ksmbd_conn *conn = work->conn;7022 struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);7023 struct smb2_hdr *chdr;7024 struct ksmbd_work *iter;7025 struct list_head *command_list;7026 7027 if (work->next_smb2_rcv_hdr_off)7028 hdr = ksmbd_resp_buf_next(work);7029 7030 ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n",7031 hdr->MessageId, hdr->Flags);7032 7033 if (hdr->Flags & SMB2_FLAGS_ASYNC_COMMAND) {7034 command_list = &conn->async_requests;7035 7036 spin_lock(&conn->request_lock);7037 list_for_each_entry(iter, command_list,7038 async_request_entry) {7039 chdr = smb2_get_msg(iter->request_buf);7040 7041 if (iter->async_id !=7042 le64_to_cpu(hdr->Id.AsyncId))7043 continue;7044 7045 ksmbd_debug(SMB,7046 "smb2 with AsyncId %llu cancelled command = 0x%x\n",7047 le64_to_cpu(hdr->Id.AsyncId),7048 le16_to_cpu(chdr->Command));7049 iter->state = KSMBD_WORK_CANCELLED;7050 if (iter->cancel_fn)7051 iter->cancel_fn(iter->cancel_argv);7052 break;7053 }7054 spin_unlock(&conn->request_lock);7055 } else {7056 command_list = &conn->requests;7057 7058 spin_lock(&conn->request_lock);7059 list_for_each_entry(iter, command_list, request_entry) {7060 chdr = smb2_get_msg(iter->request_buf);7061 7062 if (chdr->MessageId != hdr->MessageId ||7063 iter == work)7064 continue;7065 7066 ksmbd_debug(SMB,7067 "smb2 with mid %llu cancelled command = 0x%x\n",7068 le64_to_cpu(hdr->MessageId),7069 le16_to_cpu(chdr->Command));7070 iter->state = KSMBD_WORK_CANCELLED;7071 break;7072 }7073 spin_unlock(&conn->request_lock);7074 }7075 7076 /* For SMB2_CANCEL command itself send no response*/7077 work->send_no_response = 1;7078 return 0;7079}7080 7081struct file_lock *smb_flock_init(struct file *f)7082{7083 struct file_lock *fl;7084 7085 fl = locks_alloc_lock();7086 if (!fl)7087 goto out;7088 7089 locks_init_lock(fl);7090 7091 fl->c.flc_owner = f;7092 fl->c.flc_pid = current->tgid;7093 fl->c.flc_file = f;7094 fl->c.flc_flags = FL_POSIX;7095 fl->fl_ops = NULL;7096 fl->fl_lmops = NULL;7097 7098out:7099 return fl;7100}7101 7102static int smb2_set_flock_flags(struct file_lock *flock, int flags)7103{7104 int cmd = -EINVAL;7105 7106 /* Checking for wrong flag combination during lock request*/7107 switch (flags) {7108 case SMB2_LOCKFLAG_SHARED:7109 ksmbd_debug(SMB, "received shared request\n");7110 cmd = F_SETLKW;7111 flock->c.flc_type = F_RDLCK;7112 flock->c.flc_flags |= FL_SLEEP;7113 break;7114 case SMB2_LOCKFLAG_EXCLUSIVE:7115 ksmbd_debug(SMB, "received exclusive request\n");7116 cmd = F_SETLKW;7117 flock->c.flc_type = F_WRLCK;7118 flock->c.flc_flags |= FL_SLEEP;7119 break;7120 case SMB2_LOCKFLAG_SHARED | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:7121 ksmbd_debug(SMB,7122 "received shared & fail immediately request\n");7123 cmd = F_SETLK;7124 flock->c.flc_type = F_RDLCK;7125 break;7126 case SMB2_LOCKFLAG_EXCLUSIVE | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:7127 ksmbd_debug(SMB,7128 "received exclusive & fail immediately request\n");7129 cmd = F_SETLK;7130 flock->c.flc_type = F_WRLCK;7131 break;7132 case SMB2_LOCKFLAG_UNLOCK:7133 ksmbd_debug(SMB, "received unlock request\n");7134 flock->c.flc_type = F_UNLCK;7135 cmd = F_SETLK;7136 break;7137 }7138 7139 return cmd;7140}7141 7142static struct ksmbd_lock *smb2_lock_init(struct file_lock *flock,7143 unsigned int cmd, int flags,7144 struct list_head *lock_list)7145{7146 struct ksmbd_lock *lock;7147 7148 lock = kzalloc(sizeof(struct ksmbd_lock), GFP_KERNEL);7149 if (!lock)7150 return NULL;7151 7152 lock->cmd = cmd;7153 lock->fl = flock;7154 lock->start = flock->fl_start;7155 lock->end = flock->fl_end;7156 lock->flags = flags;7157 if (lock->start == lock->end)7158 lock->zero_len = 1;7159 INIT_LIST_HEAD(&lock->clist);7160 INIT_LIST_HEAD(&lock->flist);7161 INIT_LIST_HEAD(&lock->llist);7162 list_add_tail(&lock->llist, lock_list);7163 7164 return lock;7165}7166 7167static void smb2_remove_blocked_lock(void **argv)7168{7169 struct file_lock *flock = (struct file_lock *)argv[0];7170 7171 ksmbd_vfs_posix_lock_unblock(flock);7172 locks_wake_up(flock);7173}7174 7175static inline bool lock_defer_pending(struct file_lock *fl)7176{7177 /* check pending lock waiters */7178 return waitqueue_active(&fl->c.flc_wait);7179}7180 7181/**7182 * smb2_lock() - handler for smb2 file lock command7183 * @work: smb work containing lock command buffer7184 *7185 * Return: 0 on success, otherwise error7186 */7187int smb2_lock(struct ksmbd_work *work)7188{7189 struct smb2_lock_req *req;7190 struct smb2_lock_rsp *rsp;7191 struct smb2_lock_element *lock_ele;7192 struct ksmbd_file *fp = NULL;7193 struct file_lock *flock = NULL;7194 struct file *filp = NULL;7195 int lock_count;7196 int flags = 0;7197 int cmd = 0;7198 int err = -EIO, i, rc = 0;7199 u64 lock_start, lock_length;7200 struct ksmbd_lock *smb_lock = NULL, *cmp_lock, *tmp, *tmp2;7201 struct ksmbd_conn *conn;7202 int nolock = 0;7203 LIST_HEAD(lock_list);7204 LIST_HEAD(rollback_list);7205 int prior_lock = 0;7206 7207 WORK_BUFFERS(work, req, rsp);7208 7209 ksmbd_debug(SMB, "Received lock request\n");7210 fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);7211 if (!fp) {7212 ksmbd_debug(SMB, "Invalid file id for lock : %llu\n", req->VolatileFileId);7213 err = -ENOENT;7214 goto out2;7215 }7216 7217 filp = fp->filp;7218 lock_count = le16_to_cpu(req->LockCount);7219 lock_ele = req->locks;7220 7221 ksmbd_debug(SMB, "lock count is %d\n", lock_count);7222 if (!lock_count) {7223 err = -EINVAL;7224 goto out2;7225 }7226 7227 for (i = 0; i < lock_count; i++) {7228 flags = le32_to_cpu(lock_ele[i].Flags);7229 7230 flock = smb_flock_init(filp);7231 if (!flock)7232 goto out;7233 7234 cmd = smb2_set_flock_flags(flock, flags);7235 7236 lock_start = le64_to_cpu(lock_ele[i].Offset);7237 lock_length = le64_to_cpu(lock_ele[i].Length);7238 if (lock_start > U64_MAX - lock_length) {7239 pr_err("Invalid lock range requested\n");7240 rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE;7241 locks_free_lock(flock);7242 goto out;7243 }7244 7245 if (lock_start > OFFSET_MAX)7246 flock->fl_start = OFFSET_MAX;7247 else7248 flock->fl_start = lock_start;7249 7250 lock_length = le64_to_cpu(lock_ele[i].Length);7251 if (lock_length > OFFSET_MAX - flock->fl_start)7252 lock_length = OFFSET_MAX - flock->fl_start;7253 7254 flock->fl_end = flock->fl_start + lock_length;7255 7256 if (flock->fl_end < flock->fl_start) {7257 ksmbd_debug(SMB,7258 "the end offset(%llx) is smaller than the start offset(%llx)\n",7259 flock->fl_end, flock->fl_start);7260 rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE;7261 locks_free_lock(flock);7262 goto out;7263 }7264 7265 /* Check conflict locks in one request */7266 list_for_each_entry(cmp_lock, &lock_list, llist) {7267 if (cmp_lock->fl->fl_start <= flock->fl_start &&7268 cmp_lock->fl->fl_end >= flock->fl_end) {7269 if (cmp_lock->fl->c.flc_type != F_UNLCK &&7270 flock->c.flc_type != F_UNLCK) {7271 pr_err("conflict two locks in one request\n");7272 err = -EINVAL;7273 locks_free_lock(flock);7274 goto out;7275 }7276 }7277 }7278 7279 smb_lock = smb2_lock_init(flock, cmd, flags, &lock_list);7280 if (!smb_lock) {7281 err = -EINVAL;7282 locks_free_lock(flock);7283 goto out;7284 }7285 }7286 7287 list_for_each_entry_safe(smb_lock, tmp, &lock_list, llist) {7288 if (smb_lock->cmd < 0) {7289 err = -EINVAL;7290 goto out;7291 }7292 7293 if (!(smb_lock->flags & SMB2_LOCKFLAG_MASK)) {7294 err = -EINVAL;7295 goto out;7296 }7297 7298 if ((prior_lock & (SMB2_LOCKFLAG_EXCLUSIVE | SMB2_LOCKFLAG_SHARED) &&7299 smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) ||7300 (prior_lock == SMB2_LOCKFLAG_UNLOCK &&7301 !(smb_lock->flags & SMB2_LOCKFLAG_UNLOCK))) {7302 err = -EINVAL;7303 goto out;7304 }7305 7306 prior_lock = smb_lock->flags;7307 7308 if (!(smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) &&7309 !(smb_lock->flags & SMB2_LOCKFLAG_FAIL_IMMEDIATELY))7310 goto no_check_cl;7311 7312 nolock = 1;7313 /* check locks in connection list */7314 down_read(&conn_list_lock);7315 list_for_each_entry(conn, &conn_list, conns_list) {7316 spin_lock(&conn->llist_lock);7317 list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) {7318 if (file_inode(cmp_lock->fl->c.flc_file) !=7319 file_inode(smb_lock->fl->c.flc_file))7320 continue;7321 7322 if (lock_is_unlock(smb_lock->fl)) {7323 if (cmp_lock->fl->c.flc_file == smb_lock->fl->c.flc_file &&7324 cmp_lock->start == smb_lock->start &&7325 cmp_lock->end == smb_lock->end &&7326 !lock_defer_pending(cmp_lock->fl)) {7327 nolock = 0;7328 list_del(&cmp_lock->flist);7329 list_del(&cmp_lock->clist);7330 spin_unlock(&conn->llist_lock);7331 up_read(&conn_list_lock);7332 7333 locks_free_lock(cmp_lock->fl);7334 kfree(cmp_lock);7335 goto out_check_cl;7336 }7337 continue;7338 }7339 7340 if (cmp_lock->fl->c.flc_file == smb_lock->fl->c.flc_file) {7341 if (smb_lock->flags & SMB2_LOCKFLAG_SHARED)7342 continue;7343 } else {7344 if (cmp_lock->flags & SMB2_LOCKFLAG_SHARED)7345 continue;7346 }7347 7348 /* check zero byte lock range */7349 if (cmp_lock->zero_len && !smb_lock->zero_len &&7350 cmp_lock->start > smb_lock->start &&7351 cmp_lock->start < smb_lock->end) {7352 spin_unlock(&conn->llist_lock);7353 up_read(&conn_list_lock);7354 pr_err("previous lock conflict with zero byte lock range\n");7355 goto out;7356 }7357 7358 if (smb_lock->zero_len && !cmp_lock->zero_len &&7359 smb_lock->start > cmp_lock->start &&7360 smb_lock->start < cmp_lock->end) {7361 spin_unlock(&conn->llist_lock);7362 up_read(&conn_list_lock);7363 pr_err("current lock conflict with zero byte lock range\n");7364 goto out;7365 }7366 7367 if (((cmp_lock->start <= smb_lock->start &&7368 cmp_lock->end > smb_lock->start) ||7369 (cmp_lock->start < smb_lock->end &&7370 cmp_lock->end >= smb_lock->end)) &&7371 !cmp_lock->zero_len && !smb_lock->zero_len) {7372 spin_unlock(&conn->llist_lock);7373 up_read(&conn_list_lock);7374 pr_err("Not allow lock operation on exclusive lock range\n");7375 goto out;7376 }7377 }7378 spin_unlock(&conn->llist_lock);7379 }7380 up_read(&conn_list_lock);7381out_check_cl:7382 if (lock_is_unlock(smb_lock->fl) && nolock) {7383 pr_err("Try to unlock nolocked range\n");7384 rsp->hdr.Status = STATUS_RANGE_NOT_LOCKED;7385 goto out;7386 }7387 7388no_check_cl:7389 if (smb_lock->zero_len) {7390 err = 0;7391 goto skip;7392 }7393 7394 flock = smb_lock->fl;7395 list_del(&smb_lock->llist);7396retry:7397 rc = vfs_lock_file(filp, smb_lock->cmd, flock, NULL);7398skip:7399 if (flags & SMB2_LOCKFLAG_UNLOCK) {7400 if (!rc) {7401 ksmbd_debug(SMB, "File unlocked\n");7402 } else if (rc == -ENOENT) {7403 rsp->hdr.Status = STATUS_NOT_LOCKED;7404 goto out;7405 }7406 locks_free_lock(flock);7407 kfree(smb_lock);7408 } else {7409 if (rc == FILE_LOCK_DEFERRED) {7410 void **argv;7411 7412 ksmbd_debug(SMB,7413 "would have to wait for getting lock\n");7414 list_add(&smb_lock->llist, &rollback_list);7415 7416 argv = kmalloc(sizeof(void *), GFP_KERNEL);7417 if (!argv) {7418 err = -ENOMEM;7419 goto out;7420 }7421 argv[0] = flock;7422 7423 rc = setup_async_work(work,7424 smb2_remove_blocked_lock,7425 argv);7426 if (rc) {7427 kfree(argv);7428 err = -ENOMEM;7429 goto out;7430 }7431 spin_lock(&fp->f_lock);7432 list_add(&work->fp_entry, &fp->blocked_works);7433 spin_unlock(&fp->f_lock);7434 7435 smb2_send_interim_resp(work, STATUS_PENDING);7436 7437 ksmbd_vfs_posix_lock_wait(flock);7438 7439 spin_lock(&fp->f_lock);7440 list_del(&work->fp_entry);7441 spin_unlock(&fp->f_lock);7442 7443 if (work->state != KSMBD_WORK_ACTIVE) {7444 list_del(&smb_lock->llist);7445 locks_free_lock(flock);7446 7447 if (work->state == KSMBD_WORK_CANCELLED) {7448 rsp->hdr.Status =7449 STATUS_CANCELLED;7450 kfree(smb_lock);7451 smb2_send_interim_resp(work,7452 STATUS_CANCELLED);7453 work->send_no_response = 1;7454 goto out;7455 }7456 7457 rsp->hdr.Status =7458 STATUS_RANGE_NOT_LOCKED;7459 kfree(smb_lock);7460 goto out2;7461 }7462 7463 list_del(&smb_lock->llist);7464 release_async_work(work);7465 goto retry;7466 } else if (!rc) {7467 list_add(&smb_lock->llist, &rollback_list);7468 spin_lock(&work->conn->llist_lock);7469 list_add_tail(&smb_lock->clist,7470 &work->conn->lock_list);7471 list_add_tail(&smb_lock->flist,7472 &fp->lock_list);7473 spin_unlock(&work->conn->llist_lock);7474 ksmbd_debug(SMB, "successful in taking lock\n");7475 } else {7476 goto out;7477 }7478 }7479 }7480 7481 if (atomic_read(&fp->f_ci->op_count) > 1)7482 smb_break_all_oplock(work, fp);7483 7484 rsp->StructureSize = cpu_to_le16(4);7485 ksmbd_debug(SMB, "successful in taking lock\n");7486 rsp->hdr.Status = STATUS_SUCCESS;7487 rsp->Reserved = 0;7488 err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lock_rsp));7489 if (err)7490 goto out;7491 7492 ksmbd_fd_put(work, fp);7493 return 0;7494 7495out:7496 list_for_each_entry_safe(smb_lock, tmp, &lock_list, llist) {7497 locks_free_lock(smb_lock->fl);7498 list_del(&smb_lock->llist);7499 kfree(smb_lock);7500 }7501 7502 list_for_each_entry_safe(smb_lock, tmp, &rollback_list, llist) {7503 struct file_lock *rlock = NULL;7504 7505 rlock = smb_flock_init(filp);7506 rlock->c.flc_type = F_UNLCK;7507 rlock->fl_start = smb_lock->start;7508 rlock->fl_end = smb_lock->end;7509 7510 rc = vfs_lock_file(filp, F_SETLK, rlock, NULL);7511 if (rc)7512 pr_err("rollback unlock fail : %d\n", rc);7513 7514 list_del(&smb_lock->llist);7515 spin_lock(&work->conn->llist_lock);7516 if (!list_empty(&smb_lock->flist))7517 list_del(&smb_lock->flist);7518 list_del(&smb_lock->clist);7519 spin_unlock(&work->conn->llist_lock);7520 7521 locks_free_lock(smb_lock->fl);7522 locks_free_lock(rlock);7523 kfree(smb_lock);7524 }7525out2:7526 ksmbd_debug(SMB, "failed in taking lock(flags : %x), err : %d\n", flags, err);7527 7528 if (!rsp->hdr.Status) {7529 if (err == -EINVAL)7530 rsp->hdr.Status = STATUS_INVALID_PARAMETER;7531 else if (err == -ENOMEM)7532 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;7533 else if (err == -ENOENT)7534 rsp->hdr.Status = STATUS_FILE_CLOSED;7535 else7536 rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED;7537 }7538 7539 smb2_set_err_rsp(work);7540 ksmbd_fd_put(work, fp);7541 return err;7542}7543 7544static int fsctl_copychunk(struct ksmbd_work *work,7545 struct copychunk_ioctl_req *ci_req,7546 unsigned int cnt_code,7547 unsigned int input_count,7548 unsigned long long volatile_id,7549 unsigned long long persistent_id,7550 struct smb2_ioctl_rsp *rsp)7551{7552 struct copychunk_ioctl_rsp *ci_rsp;7553 struct ksmbd_file *src_fp = NULL, *dst_fp = NULL;7554 struct srv_copychunk *chunks;7555 unsigned int i, chunk_count, chunk_count_written = 0;7556 unsigned int chunk_size_written = 0;7557 loff_t total_size_written = 0;7558 int ret = 0;7559 7560 ci_rsp = (struct copychunk_ioctl_rsp *)&rsp->Buffer[0];7561 7562 rsp->VolatileFileId = volatile_id;7563 rsp->PersistentFileId = persistent_id;7564 ci_rsp->ChunksWritten =7565 cpu_to_le32(ksmbd_server_side_copy_max_chunk_count());7566 ci_rsp->ChunkBytesWritten =7567 cpu_to_le32(ksmbd_server_side_copy_max_chunk_size());7568 ci_rsp->TotalBytesWritten =7569 cpu_to_le32(ksmbd_server_side_copy_max_total_size());7570 7571 chunk_count = le32_to_cpu(ci_req->ChunkCount);7572 if (chunk_count == 0)7573 goto out;7574 total_size_written = 0;7575 7576 /* verify the SRV_COPYCHUNK_COPY packet */7577 if (chunk_count > ksmbd_server_side_copy_max_chunk_count() ||7578 input_count < struct_size(ci_req, Chunks, chunk_count)) {7579 rsp->hdr.Status = STATUS_INVALID_PARAMETER;7580 return -EINVAL;7581 }7582 7583 chunks = &ci_req->Chunks[0];7584 for (i = 0; i < chunk_count; i++) {7585 if (le32_to_cpu(chunks[i].Length) == 0 ||7586 le32_to_cpu(chunks[i].Length) > ksmbd_server_side_copy_max_chunk_size())7587 break;7588 total_size_written += le32_to_cpu(chunks[i].Length);7589 }7590 7591 if (i < chunk_count ||7592 total_size_written > ksmbd_server_side_copy_max_total_size()) {7593 rsp->hdr.Status = STATUS_INVALID_PARAMETER;7594 return -EINVAL;7595 }7596 7597 src_fp = ksmbd_lookup_foreign_fd(work,7598 le64_to_cpu(ci_req->ResumeKey[0]));7599 dst_fp = ksmbd_lookup_fd_slow(work, volatile_id, persistent_id);7600 ret = -EINVAL;7601 if (!src_fp ||7602 src_fp->persistent_id != le64_to_cpu(ci_req->ResumeKey[1])) {7603 rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND;7604 goto out;7605 }7606 7607 if (!dst_fp) {7608 rsp->hdr.Status = STATUS_FILE_CLOSED;7609 goto out;7610 }7611 7612 /*7613 * FILE_READ_DATA should only be included in7614 * the FSCTL_COPYCHUNK case7615 */7616 if (cnt_code == FSCTL_COPYCHUNK &&7617 !(dst_fp->daccess & (FILE_READ_DATA_LE | FILE_GENERIC_READ_LE))) {7618 rsp->hdr.Status = STATUS_ACCESS_DENIED;7619 goto out;7620 }7621 7622 ret = ksmbd_vfs_copy_file_ranges(work, src_fp, dst_fp,7623 chunks, chunk_count,7624 &chunk_count_written,7625 &chunk_size_written,7626 &total_size_written);7627 if (ret < 0) {7628 if (ret == -EACCES)7629 rsp->hdr.Status = STATUS_ACCESS_DENIED;7630 if (ret == -EAGAIN)7631 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;7632 else if (ret == -EBADF)7633 rsp->hdr.Status = STATUS_INVALID_HANDLE;7634 else if (ret == -EFBIG || ret == -ENOSPC)7635 rsp->hdr.Status = STATUS_DISK_FULL;7636 else if (ret == -EINVAL)7637 rsp->hdr.Status = STATUS_INVALID_PARAMETER;7638 else if (ret == -EISDIR)7639 rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;7640 else if (ret == -E2BIG)7641 rsp->hdr.Status = STATUS_INVALID_VIEW_SIZE;7642 else7643 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;7644 }7645 7646 ci_rsp->ChunksWritten = cpu_to_le32(chunk_count_written);7647 ci_rsp->ChunkBytesWritten = cpu_to_le32(chunk_size_written);7648 ci_rsp->TotalBytesWritten = cpu_to_le32(total_size_written);7649out:7650 ksmbd_fd_put(work, src_fp);7651 ksmbd_fd_put(work, dst_fp);7652 return ret;7653}7654 7655static __be32 idev_ipv4_address(struct in_device *idev)7656{7657 __be32 addr = 0;7658 7659 struct in_ifaddr *ifa;7660 7661 rcu_read_lock();7662 in_dev_for_each_ifa_rcu(ifa, idev) {7663 if (ifa->ifa_flags & IFA_F_SECONDARY)7664 continue;7665 7666 addr = ifa->ifa_address;7667 break;7668 }7669 rcu_read_unlock();7670 return addr;7671}7672 7673static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn,7674 struct smb2_ioctl_rsp *rsp,7675 unsigned int out_buf_len)7676{7677 struct network_interface_info_ioctl_rsp *nii_rsp = NULL;7678 int nbytes = 0;7679 struct net_device *netdev;7680 struct sockaddr_storage_rsp *sockaddr_storage;7681 unsigned int flags;7682 unsigned long long speed;7683 7684 rtnl_lock();7685 for_each_netdev(&init_net, netdev) {7686 bool ipv4_set = false;7687 7688 if (netdev->type == ARPHRD_LOOPBACK)7689 continue;7690 7691 flags = dev_get_flags(netdev);7692 if (!(flags & IFF_RUNNING))7693 continue;7694ipv6_retry:7695 if (out_buf_len <7696 nbytes + sizeof(struct network_interface_info_ioctl_rsp)) {7697 rtnl_unlock();7698 return -ENOSPC;7699 }7700 7701 nii_rsp = (struct network_interface_info_ioctl_rsp *)7702 &rsp->Buffer[nbytes];7703 nii_rsp->IfIndex = cpu_to_le32(netdev->ifindex);7704 7705 nii_rsp->Capability = 0;7706 if (netdev->real_num_tx_queues > 1)7707 nii_rsp->Capability |= cpu_to_le32(RSS_CAPABLE);7708 if (ksmbd_rdma_capable_netdev(netdev))7709 nii_rsp->Capability |= cpu_to_le32(RDMA_CAPABLE);7710 7711 nii_rsp->Next = cpu_to_le32(152);7712 nii_rsp->Reserved = 0;7713 7714 if (netdev->ethtool_ops->get_link_ksettings) {7715 struct ethtool_link_ksettings cmd;7716 7717 netdev->ethtool_ops->get_link_ksettings(netdev, &cmd);7718 speed = cmd.base.speed;7719 } else {7720 ksmbd_debug(SMB, "%s %s\n", netdev->name,7721 "speed is unknown, defaulting to 1Gb/sec");7722 speed = SPEED_1000;7723 }7724 7725 speed *= 1000000;7726 nii_rsp->LinkSpeed = cpu_to_le64(speed);7727 7728 sockaddr_storage = (struct sockaddr_storage_rsp *)7729 nii_rsp->SockAddr_Storage;7730 memset(sockaddr_storage, 0, 128);7731 7732 if (!ipv4_set) {7733 struct in_device *idev;7734 7735 sockaddr_storage->Family = cpu_to_le16(INTERNETWORK);7736 sockaddr_storage->addr4.Port = 0;7737 7738 idev = __in_dev_get_rtnl(netdev);7739 if (!idev)7740 continue;7741 sockaddr_storage->addr4.IPv4address =7742 idev_ipv4_address(idev);7743 nbytes += sizeof(struct network_interface_info_ioctl_rsp);7744 ipv4_set = true;7745 goto ipv6_retry;7746 } else {7747 struct inet6_dev *idev6;7748 struct inet6_ifaddr *ifa;7749 __u8 *ipv6_addr = sockaddr_storage->addr6.IPv6address;7750 7751 sockaddr_storage->Family = cpu_to_le16(INTERNETWORKV6);7752 sockaddr_storage->addr6.Port = 0;7753 sockaddr_storage->addr6.FlowInfo = 0;7754 7755 idev6 = __in6_dev_get(netdev);7756 if (!idev6)7757 continue;7758 7759 list_for_each_entry(ifa, &idev6->addr_list, if_list) {7760 if (ifa->flags & (IFA_F_TENTATIVE |7761 IFA_F_DEPRECATED))7762 continue;7763 memcpy(ipv6_addr, ifa->addr.s6_addr, 16);7764 break;7765 }7766 sockaddr_storage->addr6.ScopeId = 0;7767 nbytes += sizeof(struct network_interface_info_ioctl_rsp);7768 }7769 }7770 rtnl_unlock();7771 7772 /* zero if this is last one */7773 if (nii_rsp)7774 nii_rsp->Next = 0;7775 7776 rsp->PersistentFileId = SMB2_NO_FID;7777 rsp->VolatileFileId = SMB2_NO_FID;7778 return nbytes;7779}7780 7781static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn,7782 struct validate_negotiate_info_req *neg_req,7783 struct validate_negotiate_info_rsp *neg_rsp,7784 unsigned int in_buf_len)7785{7786 int ret = 0;7787 int dialect;7788 7789 if (in_buf_len < offsetof(struct validate_negotiate_info_req, Dialects) +7790 le16_to_cpu(neg_req->DialectCount) * sizeof(__le16))7791 return -EINVAL;7792 7793 dialect = ksmbd_lookup_dialect_by_id(neg_req->Dialects,7794 neg_req->DialectCount);7795 if (dialect == BAD_PROT_ID || dialect != conn->dialect) {7796 ret = -EINVAL;7797 goto err_out;7798 }7799 7800 if (strncmp(neg_req->Guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE)) {7801 ret = -EINVAL;7802 goto err_out;7803 }7804 7805 if (le16_to_cpu(neg_req->SecurityMode) != conn->cli_sec_mode) {7806 ret = -EINVAL;7807 goto err_out;7808 }7809 7810 if (le32_to_cpu(neg_req->Capabilities) != conn->cli_cap) {7811 ret = -EINVAL;7812 goto err_out;7813 }7814 7815 neg_rsp->Capabilities = cpu_to_le32(conn->vals->capabilities);7816 memset(neg_rsp->Guid, 0, SMB2_CLIENT_GUID_SIZE);7817 neg_rsp->SecurityMode = cpu_to_le16(conn->srv_sec_mode);7818 neg_rsp->Dialect = cpu_to_le16(conn->dialect);7819err_out:7820 return ret;7821}7822 7823static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id,7824 struct file_allocated_range_buffer *qar_req,7825 struct file_allocated_range_buffer *qar_rsp,7826 unsigned int in_count, unsigned int *out_count)7827{7828 struct ksmbd_file *fp;7829 loff_t start, length;7830 int ret = 0;7831 7832 *out_count = 0;7833 if (in_count == 0)7834 return -EINVAL;7835 7836 start = le64_to_cpu(qar_req->file_offset);7837 length = le64_to_cpu(qar_req->length);7838 7839 if (start < 0 || length < 0)7840 return -EINVAL;7841 7842 fp = ksmbd_lookup_fd_fast(work, id);7843 if (!fp)7844 return -ENOENT;7845 7846 ret = ksmbd_vfs_fqar_lseek(fp, start, length,7847 qar_rsp, in_count, out_count);7848 if (ret && ret != -E2BIG)7849 *out_count = 0;7850 7851 ksmbd_fd_put(work, fp);7852 return ret;7853}7854 7855static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id,7856 unsigned int out_buf_len,7857 struct smb2_ioctl_req *req,7858 struct smb2_ioctl_rsp *rsp)7859{7860 struct ksmbd_rpc_command *rpc_resp;7861 char *data_buf = (char *)req + le32_to_cpu(req->InputOffset);7862 int nbytes = 0;7863 7864 rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf,7865 le32_to_cpu(req->InputCount));7866 if (rpc_resp) {7867 if (rpc_resp->flags == KSMBD_RPC_SOME_NOT_MAPPED) {7868 /*7869 * set STATUS_SOME_NOT_MAPPED response7870 * for unknown domain sid.7871 */7872 rsp->hdr.Status = STATUS_SOME_NOT_MAPPED;7873 } else if (rpc_resp->flags == KSMBD_RPC_ENOTIMPLEMENTED) {7874 rsp->hdr.Status = STATUS_NOT_SUPPORTED;7875 goto out;7876 } else if (rpc_resp->flags != KSMBD_RPC_OK) {7877 rsp->hdr.Status = STATUS_INVALID_PARAMETER;7878 goto out;7879 }7880 7881 nbytes = rpc_resp->payload_sz;7882 if (rpc_resp->payload_sz > out_buf_len) {7883 rsp->hdr.Status = STATUS_BUFFER_OVERFLOW;7884 nbytes = out_buf_len;7885 }7886 7887 if (!rpc_resp->payload_sz) {7888 rsp->hdr.Status =7889 STATUS_UNEXPECTED_IO_ERROR;7890 goto out;7891 }7892 7893 memcpy((char *)rsp->Buffer, rpc_resp->payload, nbytes);7894 }7895out:7896 kvfree(rpc_resp);7897 return nbytes;7898}7899 7900static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,7901 struct file_sparse *sparse)7902{7903 struct ksmbd_file *fp;7904 struct mnt_idmap *idmap;7905 int ret = 0;7906 __le32 old_fattr;7907 7908 fp = ksmbd_lookup_fd_fast(work, id);7909 if (!fp)7910 return -ENOENT;7911 idmap = file_mnt_idmap(fp->filp);7912 7913 old_fattr = fp->f_ci->m_fattr;7914 if (sparse->SetSparse)7915 fp->f_ci->m_fattr |= FILE_ATTRIBUTE_SPARSE_FILE_LE;7916 else7917 fp->f_ci->m_fattr &= ~FILE_ATTRIBUTE_SPARSE_FILE_LE;7918 7919 if (fp->f_ci->m_fattr != old_fattr &&7920 test_share_config_flag(work->tcon->share_conf,7921 KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) {7922 struct xattr_dos_attrib da;7923 7924 ret = ksmbd_vfs_get_dos_attrib_xattr(idmap,7925 fp->filp->f_path.dentry, &da);7926 if (ret <= 0)7927 goto out;7928 7929 da.attr = le32_to_cpu(fp->f_ci->m_fattr);7930 ret = ksmbd_vfs_set_dos_attrib_xattr(idmap,7931 &fp->filp->f_path,7932 &da, true);7933 if (ret)7934 fp->f_ci->m_fattr = old_fattr;7935 }7936 7937out:7938 ksmbd_fd_put(work, fp);7939 return ret;7940}7941 7942static int fsctl_request_resume_key(struct ksmbd_work *work,7943 struct smb2_ioctl_req *req,7944 struct resume_key_ioctl_rsp *key_rsp)7945{7946 struct ksmbd_file *fp;7947 7948 fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);7949 if (!fp)7950 return -ENOENT;7951 7952 memset(key_rsp, 0, sizeof(*key_rsp));7953 key_rsp->ResumeKey[0] = req->VolatileFileId;7954 key_rsp->ResumeKey[1] = req->PersistentFileId;7955 ksmbd_fd_put(work, fp);7956 7957 return 0;7958}7959 7960/**7961 * smb2_ioctl() - handler for smb2 ioctl command7962 * @work: smb work containing ioctl command buffer7963 *7964 * Return: 0 on success, otherwise error7965 */7966int smb2_ioctl(struct ksmbd_work *work)7967{7968 struct smb2_ioctl_req *req;7969 struct smb2_ioctl_rsp *rsp;7970 unsigned int cnt_code, nbytes = 0, out_buf_len, in_buf_len;7971 u64 id = KSMBD_NO_FID;7972 struct ksmbd_conn *conn = work->conn;7973 int ret = 0;7974 char *buffer;7975 7976 if (work->next_smb2_rcv_hdr_off) {7977 req = ksmbd_req_buf_next(work);7978 rsp = ksmbd_resp_buf_next(work);7979 if (!has_file_id(req->VolatileFileId)) {7980 ksmbd_debug(SMB, "Compound request set FID = %llu\n",7981 work->compound_fid);7982 id = work->compound_fid;7983 }7984 } else {7985 req = smb2_get_msg(work->request_buf);7986 rsp = smb2_get_msg(work->response_buf);7987 }7988 7989 if (!has_file_id(id))7990 id = req->VolatileFileId;7991 7992 if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) {7993 rsp->hdr.Status = STATUS_NOT_SUPPORTED;7994 goto out;7995 }7996 7997 buffer = (char *)req + le32_to_cpu(req->InputOffset);7998 7999 cnt_code = le32_to_cpu(req->CtlCode);8000 ret = smb2_calc_max_out_buf_len(work, 48,8001 le32_to_cpu(req->MaxOutputResponse));8002 if (ret < 0) {8003 rsp->hdr.Status = STATUS_INVALID_PARAMETER;8004 goto out;8005 }8006 out_buf_len = (unsigned int)ret;8007 in_buf_len = le32_to_cpu(req->InputCount);8008 8009 switch (cnt_code) {8010 case FSCTL_DFS_GET_REFERRALS:8011 case FSCTL_DFS_GET_REFERRALS_EX:8012 /* Not support DFS yet */8013 rsp->hdr.Status = STATUS_FS_DRIVER_REQUIRED;8014 goto out;8015 case FSCTL_CREATE_OR_GET_OBJECT_ID:8016 {8017 struct file_object_buf_type1_ioctl_rsp *obj_buf;8018 8019 nbytes = sizeof(struct file_object_buf_type1_ioctl_rsp);8020 obj_buf = (struct file_object_buf_type1_ioctl_rsp *)8021 &rsp->Buffer[0];8022 8023 /*8024 * TODO: This is dummy implementation to pass smbtorture8025 * Need to check correct response later8026 */8027 memset(obj_buf->ObjectId, 0x0, 16);8028 memset(obj_buf->BirthVolumeId, 0x0, 16);8029 memset(obj_buf->BirthObjectId, 0x0, 16);8030 memset(obj_buf->DomainId, 0x0, 16);8031 8032 break;8033 }8034 case FSCTL_PIPE_TRANSCEIVE:8035 out_buf_len = min_t(u32, KSMBD_IPC_MAX_PAYLOAD, out_buf_len);8036 nbytes = fsctl_pipe_transceive(work, id, out_buf_len, req, rsp);8037 break;8038 case FSCTL_VALIDATE_NEGOTIATE_INFO:8039 if (conn->dialect < SMB30_PROT_ID) {8040 ret = -EOPNOTSUPP;8041 goto out;8042 }8043 8044 if (in_buf_len < offsetof(struct validate_negotiate_info_req,8045 Dialects)) {8046 ret = -EINVAL;8047 goto out;8048 }8049 8050 if (out_buf_len < sizeof(struct validate_negotiate_info_rsp)) {8051 ret = -EINVAL;8052 goto out;8053 }8054 8055 ret = fsctl_validate_negotiate_info(conn,8056 (struct validate_negotiate_info_req *)buffer,8057 (struct validate_negotiate_info_rsp *)&rsp->Buffer[0],8058 in_buf_len);8059 if (ret < 0)8060 goto out;8061 8062 nbytes = sizeof(struct validate_negotiate_info_rsp);8063 rsp->PersistentFileId = SMB2_NO_FID;8064 rsp->VolatileFileId = SMB2_NO_FID;8065 break;8066 case FSCTL_QUERY_NETWORK_INTERFACE_INFO:8067 ret = fsctl_query_iface_info_ioctl(conn, rsp, out_buf_len);8068 if (ret < 0)8069 goto out;8070 nbytes = ret;8071 break;8072 case FSCTL_REQUEST_RESUME_KEY:8073 if (out_buf_len < sizeof(struct resume_key_ioctl_rsp)) {8074 ret = -EINVAL;8075 goto out;8076 }8077 8078 ret = fsctl_request_resume_key(work, req,8079 (struct resume_key_ioctl_rsp *)&rsp->Buffer[0]);8080 if (ret < 0)8081 goto out;8082 rsp->PersistentFileId = req->PersistentFileId;8083 rsp->VolatileFileId = req->VolatileFileId;8084 nbytes = sizeof(struct resume_key_ioctl_rsp);8085 break;8086 case FSCTL_COPYCHUNK:8087 case FSCTL_COPYCHUNK_WRITE:8088 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {8089 ksmbd_debug(SMB,8090 "User does not have write permission\n");8091 ret = -EACCES;8092 goto out;8093 }8094 8095 if (in_buf_len <= sizeof(struct copychunk_ioctl_req)) {8096 ret = -EINVAL;8097 goto out;8098 }8099 8100 if (out_buf_len < sizeof(struct copychunk_ioctl_rsp)) {8101 ret = -EINVAL;8102 goto out;8103 }8104 8105 nbytes = sizeof(struct copychunk_ioctl_rsp);8106 rsp->VolatileFileId = req->VolatileFileId;8107 rsp->PersistentFileId = req->PersistentFileId;8108 fsctl_copychunk(work,8109 (struct copychunk_ioctl_req *)buffer,8110 le32_to_cpu(req->CtlCode),8111 le32_to_cpu(req->InputCount),8112 req->VolatileFileId,8113 req->PersistentFileId,8114 rsp);8115 break;8116 case FSCTL_SET_SPARSE:8117 if (in_buf_len < sizeof(struct file_sparse)) {8118 ret = -EINVAL;8119 goto out;8120 }8121 8122 ret = fsctl_set_sparse(work, id, (struct file_sparse *)buffer);8123 if (ret < 0)8124 goto out;8125 break;8126 case FSCTL_SET_ZERO_DATA:8127 {8128 struct file_zero_data_information *zero_data;8129 struct ksmbd_file *fp;8130 loff_t off, len, bfz;8131 8132 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {8133 ksmbd_debug(SMB,8134 "User does not have write permission\n");8135 ret = -EACCES;8136 goto out;8137 }8138 8139 if (in_buf_len < sizeof(struct file_zero_data_information)) {8140 ret = -EINVAL;8141 goto out;8142 }8143 8144 zero_data =8145 (struct file_zero_data_information *)buffer;8146 8147 off = le64_to_cpu(zero_data->FileOffset);8148 bfz = le64_to_cpu(zero_data->BeyondFinalZero);8149 if (off < 0 || bfz < 0 || off > bfz) {8150 ret = -EINVAL;8151 goto out;8152 }8153 8154 len = bfz - off;8155 if (len) {8156 fp = ksmbd_lookup_fd_fast(work, id);8157 if (!fp) {8158 ret = -ENOENT;8159 goto out;8160 }8161 8162 ret = ksmbd_vfs_zero_data(work, fp, off, len);8163 ksmbd_fd_put(work, fp);8164 if (ret < 0)8165 goto out;8166 }8167 break;8168 }8169 case FSCTL_QUERY_ALLOCATED_RANGES:8170 if (in_buf_len < sizeof(struct file_allocated_range_buffer)) {8171 ret = -EINVAL;8172 goto out;8173 }8174 8175 ret = fsctl_query_allocated_ranges(work, id,8176 (struct file_allocated_range_buffer *)buffer,8177 (struct file_allocated_range_buffer *)&rsp->Buffer[0],8178 out_buf_len /8179 sizeof(struct file_allocated_range_buffer), &nbytes);8180 if (ret == -E2BIG) {8181 rsp->hdr.Status = STATUS_BUFFER_OVERFLOW;8182 } else if (ret < 0) {8183 nbytes = 0;8184 goto out;8185 }8186 8187 nbytes *= sizeof(struct file_allocated_range_buffer);8188 break;8189 case FSCTL_GET_REPARSE_POINT:8190 {8191 struct reparse_data_buffer *reparse_ptr;8192 struct ksmbd_file *fp;8193 8194 reparse_ptr = (struct reparse_data_buffer *)&rsp->Buffer[0];8195 fp = ksmbd_lookup_fd_fast(work, id);8196 if (!fp) {8197 pr_err("not found fp!!\n");8198 ret = -ENOENT;8199 goto out;8200 }8201 8202 reparse_ptr->ReparseTag =8203 smb2_get_reparse_tag_special_file(file_inode(fp->filp)->i_mode);8204 reparse_ptr->ReparseDataLength = 0;8205 ksmbd_fd_put(work, fp);8206 nbytes = sizeof(struct reparse_data_buffer);8207 break;8208 }8209 case FSCTL_DUPLICATE_EXTENTS_TO_FILE:8210 {8211 struct ksmbd_file *fp_in, *fp_out = NULL;8212 struct duplicate_extents_to_file *dup_ext;8213 loff_t src_off, dst_off, length, cloned;8214 8215 if (in_buf_len < sizeof(struct duplicate_extents_to_file)) {8216 ret = -EINVAL;8217 goto out;8218 }8219 8220 dup_ext = (struct duplicate_extents_to_file *)buffer;8221 8222 fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle,8223 dup_ext->PersistentFileHandle);8224 if (!fp_in) {8225 pr_err("not found file handle in duplicate extent to file\n");8226 ret = -ENOENT;8227 goto out;8228 }8229 8230 fp_out = ksmbd_lookup_fd_fast(work, id);8231 if (!fp_out) {8232 pr_err("not found fp\n");8233 ret = -ENOENT;8234 goto dup_ext_out;8235 }8236 8237 src_off = le64_to_cpu(dup_ext->SourceFileOffset);8238 dst_off = le64_to_cpu(dup_ext->TargetFileOffset);8239 length = le64_to_cpu(dup_ext->ByteCount);8240 /*8241 * XXX: It is not clear if FSCTL_DUPLICATE_EXTENTS_TO_FILE8242 * should fall back to vfs_copy_file_range(). This could be8243 * beneficial when re-exporting nfs/smb mount, but note that8244 * this can result in partial copy that returns an error status.8245 * If/when FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX is implemented,8246 * fall back to vfs_copy_file_range(), should be avoided when8247 * the flag DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC is set.8248 */8249 cloned = vfs_clone_file_range(fp_in->filp, src_off,8250 fp_out->filp, dst_off, length, 0);8251 if (cloned == -EXDEV || cloned == -EOPNOTSUPP) {8252 ret = -EOPNOTSUPP;8253 goto dup_ext_out;8254 } else if (cloned != length) {8255 cloned = vfs_copy_file_range(fp_in->filp, src_off,8256 fp_out->filp, dst_off,8257 length, 0);8258 if (cloned != length) {8259 if (cloned < 0)8260 ret = cloned;8261 else8262 ret = -EINVAL;8263 }8264 }8265 8266dup_ext_out:8267 ksmbd_fd_put(work, fp_in);8268 ksmbd_fd_put(work, fp_out);8269 if (ret < 0)8270 goto out;8271 break;8272 }8273 default:8274 ksmbd_debug(SMB, "not implemented yet ioctl command 0x%x\n",8275 cnt_code);8276 ret = -EOPNOTSUPP;8277 goto out;8278 }8279 8280 rsp->CtlCode = cpu_to_le32(cnt_code);8281 rsp->InputCount = cpu_to_le32(0);8282 rsp->InputOffset = cpu_to_le32(112);8283 rsp->OutputOffset = cpu_to_le32(112);8284 rsp->OutputCount = cpu_to_le32(nbytes);8285 rsp->StructureSize = cpu_to_le16(49);8286 rsp->Reserved = cpu_to_le16(0);8287 rsp->Flags = cpu_to_le32(0);8288 rsp->Reserved2 = cpu_to_le32(0);8289 ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_ioctl_rsp) + nbytes);8290 if (!ret)8291 return ret;8292 8293out:8294 if (ret == -EACCES)8295 rsp->hdr.Status = STATUS_ACCESS_DENIED;8296 else if (ret == -ENOENT)8297 rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND;8298 else if (ret == -EOPNOTSUPP)8299 rsp->hdr.Status = STATUS_NOT_SUPPORTED;8300 else if (ret == -ENOSPC)8301 rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL;8302 else if (ret < 0 || rsp->hdr.Status == 0)8303 rsp->hdr.Status = STATUS_INVALID_PARAMETER;8304 smb2_set_err_rsp(work);8305 return 0;8306}8307 8308/**8309 * smb20_oplock_break_ack() - handler for smb2.0 oplock break command8310 * @work: smb work containing oplock break command buffer8311 *8312 * Return: 08313 */8314static void smb20_oplock_break_ack(struct ksmbd_work *work)8315{8316 struct smb2_oplock_break *req;8317 struct smb2_oplock_break *rsp;8318 struct ksmbd_file *fp;8319 struct oplock_info *opinfo = NULL;8320 __le32 err = 0;8321 int ret = 0;8322 u64 volatile_id, persistent_id;8323 char req_oplevel = 0, rsp_oplevel = 0;8324 unsigned int oplock_change_type;8325 8326 WORK_BUFFERS(work, req, rsp);8327 8328 volatile_id = req->VolatileFid;8329 persistent_id = req->PersistentFid;8330 req_oplevel = req->OplockLevel;8331 ksmbd_debug(OPLOCK, "v_id %llu, p_id %llu request oplock level %d\n",8332 volatile_id, persistent_id, req_oplevel);8333 8334 fp = ksmbd_lookup_fd_slow(work, volatile_id, persistent_id);8335 if (!fp) {8336 rsp->hdr.Status = STATUS_FILE_CLOSED;8337 smb2_set_err_rsp(work);8338 return;8339 }8340 8341 opinfo = opinfo_get(fp);8342 if (!opinfo) {8343 pr_err("unexpected null oplock_info\n");8344 rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL;8345 smb2_set_err_rsp(work);8346 ksmbd_fd_put(work, fp);8347 return;8348 }8349 8350 if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE) {8351 rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL;8352 goto err_out;8353 }8354 8355 if (opinfo->op_state == OPLOCK_STATE_NONE) {8356 ksmbd_debug(SMB, "unexpected oplock state 0x%x\n", opinfo->op_state);8357 rsp->hdr.Status = STATUS_UNSUCCESSFUL;8358 goto err_out;8359 }8360 8361 if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||8362 opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&8363 (req_oplevel != SMB2_OPLOCK_LEVEL_II &&8364 req_oplevel != SMB2_OPLOCK_LEVEL_NONE)) {8365 err = STATUS_INVALID_OPLOCK_PROTOCOL;8366 oplock_change_type = OPLOCK_WRITE_TO_NONE;8367 } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&8368 req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {8369 err = STATUS_INVALID_OPLOCK_PROTOCOL;8370 oplock_change_type = OPLOCK_READ_TO_NONE;8371 } else if (req_oplevel == SMB2_OPLOCK_LEVEL_II ||8372 req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {8373 err = STATUS_INVALID_DEVICE_STATE;8374 if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||8375 opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&8376 req_oplevel == SMB2_OPLOCK_LEVEL_II) {8377 oplock_change_type = OPLOCK_WRITE_TO_READ;8378 } else if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||8379 opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&8380 req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {8381 oplock_change_type = OPLOCK_WRITE_TO_NONE;8382 } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&8383 req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {8384 oplock_change_type = OPLOCK_READ_TO_NONE;8385 } else {8386 oplock_change_type = 0;8387 }8388 } else {8389 oplock_change_type = 0;8390 }8391 8392 switch (oplock_change_type) {8393 case OPLOCK_WRITE_TO_READ:8394 ret = opinfo_write_to_read(opinfo);8395 rsp_oplevel = SMB2_OPLOCK_LEVEL_II;8396 break;8397 case OPLOCK_WRITE_TO_NONE:8398 ret = opinfo_write_to_none(opinfo);8399 rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;8400 break;8401 case OPLOCK_READ_TO_NONE:8402 ret = opinfo_read_to_none(opinfo);8403 rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;8404 break;8405 default:8406 pr_err("unknown oplock change 0x%x -> 0x%x\n",8407 opinfo->level, rsp_oplevel);8408 }8409 8410 if (ret < 0) {8411 rsp->hdr.Status = err;8412 goto err_out;8413 }8414 8415 opinfo->op_state = OPLOCK_STATE_NONE;8416 wake_up_interruptible_all(&opinfo->oplock_q);8417 opinfo_put(opinfo);8418 ksmbd_fd_put(work, fp);8419 8420 rsp->StructureSize = cpu_to_le16(24);8421 rsp->OplockLevel = rsp_oplevel;8422 rsp->Reserved = 0;8423 rsp->Reserved2 = 0;8424 rsp->VolatileFid = volatile_id;8425 rsp->PersistentFid = persistent_id;8426 ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_oplock_break));8427 if (!ret)8428 return;8429 8430err_out:8431 opinfo->op_state = OPLOCK_STATE_NONE;8432 wake_up_interruptible_all(&opinfo->oplock_q);8433 8434 opinfo_put(opinfo);8435 ksmbd_fd_put(work, fp);8436 smb2_set_err_rsp(work);8437}8438 8439static int check_lease_state(struct lease *lease, __le32 req_state)8440{8441 if ((lease->new_state ==8442 (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE)) &&8443 !(req_state & SMB2_LEASE_WRITE_CACHING_LE)) {8444 lease->new_state = req_state;8445 return 0;8446 }8447 8448 if (lease->new_state == req_state)8449 return 0;8450 8451 return 1;8452}8453 8454/**8455 * smb21_lease_break_ack() - handler for smb2.1 lease break command8456 * @work: smb work containing lease break command buffer8457 *8458 * Return: 08459 */8460static void smb21_lease_break_ack(struct ksmbd_work *work)8461{8462 struct ksmbd_conn *conn = work->conn;8463 struct smb2_lease_ack *req;8464 struct smb2_lease_ack *rsp;8465 struct oplock_info *opinfo;8466 __le32 err = 0;8467 int ret = 0;8468 unsigned int lease_change_type;8469 __le32 lease_state;8470 struct lease *lease;8471 8472 WORK_BUFFERS(work, req, rsp);8473 8474 ksmbd_debug(OPLOCK, "smb21 lease break, lease state(0x%x)\n",8475 le32_to_cpu(req->LeaseState));8476 opinfo = lookup_lease_in_table(conn, req->LeaseKey);8477 if (!opinfo) {8478 ksmbd_debug(OPLOCK, "file not opened\n");8479 smb2_set_err_rsp(work);8480 rsp->hdr.Status = STATUS_UNSUCCESSFUL;8481 return;8482 }8483 lease = opinfo->o_lease;8484 8485 if (opinfo->op_state == OPLOCK_STATE_NONE) {8486 pr_err("unexpected lease break state 0x%x\n",8487 opinfo->op_state);8488 rsp->hdr.Status = STATUS_UNSUCCESSFUL;8489 goto err_out;8490 }8491 8492 if (check_lease_state(lease, req->LeaseState)) {8493 rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;8494 ksmbd_debug(OPLOCK,8495 "req lease state: 0x%x, expected state: 0x%x\n",8496 req->LeaseState, lease->new_state);8497 goto err_out;8498 }8499 8500 if (!atomic_read(&opinfo->breaking_cnt)) {8501 rsp->hdr.Status = STATUS_UNSUCCESSFUL;8502 goto err_out;8503 }8504 8505 /* check for bad lease state */8506 if (req->LeaseState &8507 (~(SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE))) {8508 err = STATUS_INVALID_OPLOCK_PROTOCOL;8509 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)8510 lease_change_type = OPLOCK_WRITE_TO_NONE;8511 else8512 lease_change_type = OPLOCK_READ_TO_NONE;8513 ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",8514 le32_to_cpu(lease->state),8515 le32_to_cpu(req->LeaseState));8516 } else if (lease->state == SMB2_LEASE_READ_CACHING_LE &&8517 req->LeaseState != SMB2_LEASE_NONE_LE) {8518 err = STATUS_INVALID_OPLOCK_PROTOCOL;8519 lease_change_type = OPLOCK_READ_TO_NONE;8520 ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",8521 le32_to_cpu(lease->state),8522 le32_to_cpu(req->LeaseState));8523 } else {8524 /* valid lease state changes */8525 err = STATUS_INVALID_DEVICE_STATE;8526 if (req->LeaseState == SMB2_LEASE_NONE_LE) {8527 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)8528 lease_change_type = OPLOCK_WRITE_TO_NONE;8529 else8530 lease_change_type = OPLOCK_READ_TO_NONE;8531 } else if (req->LeaseState & SMB2_LEASE_READ_CACHING_LE) {8532 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)8533 lease_change_type = OPLOCK_WRITE_TO_READ;8534 else8535 lease_change_type = OPLOCK_READ_HANDLE_TO_READ;8536 } else {8537 lease_change_type = 0;8538 }8539 }8540 8541 switch (lease_change_type) {8542 case OPLOCK_WRITE_TO_READ:8543 ret = opinfo_write_to_read(opinfo);8544 break;8545 case OPLOCK_READ_HANDLE_TO_READ:8546 ret = opinfo_read_handle_to_read(opinfo);8547 break;8548 case OPLOCK_WRITE_TO_NONE:8549 ret = opinfo_write_to_none(opinfo);8550 break;8551 case OPLOCK_READ_TO_NONE:8552 ret = opinfo_read_to_none(opinfo);8553 break;8554 default:8555 ksmbd_debug(OPLOCK, "unknown lease change 0x%x -> 0x%x\n",8556 le32_to_cpu(lease->state),8557 le32_to_cpu(req->LeaseState));8558 }8559 8560 if (ret < 0) {8561 rsp->hdr.Status = err;8562 goto err_out;8563 }8564 8565 lease_state = lease->state;8566 opinfo->op_state = OPLOCK_STATE_NONE;8567 wake_up_interruptible_all(&opinfo->oplock_q);8568 atomic_dec(&opinfo->breaking_cnt);8569 wake_up_interruptible_all(&opinfo->oplock_brk);8570 opinfo_put(opinfo);8571 8572 rsp->StructureSize = cpu_to_le16(36);8573 rsp->Reserved = 0;8574 rsp->Flags = 0;8575 memcpy(rsp->LeaseKey, req->LeaseKey, 16);8576 rsp->LeaseState = lease_state;8577 rsp->LeaseDuration = 0;8578 ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lease_ack));8579 if (!ret)8580 return;8581 8582err_out:8583 wake_up_interruptible_all(&opinfo->oplock_q);8584 atomic_dec(&opinfo->breaking_cnt);8585 wake_up_interruptible_all(&opinfo->oplock_brk);8586 8587 opinfo_put(opinfo);8588 smb2_set_err_rsp(work);8589}8590 8591/**8592 * smb2_oplock_break() - dispatcher for smb2.0 and 2.1 oplock/lease break8593 * @work: smb work containing oplock/lease break command buffer8594 *8595 * Return: 08596 */8597int smb2_oplock_break(struct ksmbd_work *work)8598{8599 struct smb2_oplock_break *req;8600 struct smb2_oplock_break *rsp;8601 8602 WORK_BUFFERS(work, req, rsp);8603 8604 switch (le16_to_cpu(req->StructureSize)) {8605 case OP_BREAK_STRUCT_SIZE_20:8606 smb20_oplock_break_ack(work);8607 break;8608 case OP_BREAK_STRUCT_SIZE_21:8609 smb21_lease_break_ack(work);8610 break;8611 default:8612 ksmbd_debug(OPLOCK, "invalid break cmd %d\n",8613 le16_to_cpu(req->StructureSize));8614 rsp->hdr.Status = STATUS_INVALID_PARAMETER;8615 smb2_set_err_rsp(work);8616 }8617 8618 return 0;8619}8620 8621/**8622 * smb2_notify() - handler for smb2 notify request8623 * @work: smb work containing notify command buffer8624 *8625 * Return: 08626 */8627int smb2_notify(struct ksmbd_work *work)8628{8629 struct smb2_change_notify_req *req;8630 struct smb2_change_notify_rsp *rsp;8631 8632 WORK_BUFFERS(work, req, rsp);8633 8634 if (work->next_smb2_rcv_hdr_off && req->hdr.NextCommand) {8635 rsp->hdr.Status = STATUS_INTERNAL_ERROR;8636 smb2_set_err_rsp(work);8637 return 0;8638 }8639 8640 smb2_set_err_rsp(work);8641 rsp->hdr.Status = STATUS_NOT_IMPLEMENTED;8642 return 0;8643}8644 8645/**8646 * smb2_is_sign_req() - handler for checking packet signing status8647 * @work: smb work containing notify command buffer8648 * @command: SMB2 command id8649 *8650 * Return: true if packed is signed, false otherwise8651 */8652bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)8653{8654 struct smb2_hdr *rcv_hdr2 = smb2_get_msg(work->request_buf);8655 8656 if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&8657 command != SMB2_NEGOTIATE_HE &&8658 command != SMB2_SESSION_SETUP_HE &&8659 command != SMB2_OPLOCK_BREAK_HE)8660 return true;8661 8662 return false;8663}8664 8665/**8666 * smb2_check_sign_req() - handler for req packet sign processing8667 * @work: smb work containing notify command buffer8668 *8669 * Return: 1 on success, 0 otherwise8670 */8671int smb2_check_sign_req(struct ksmbd_work *work)8672{8673 struct smb2_hdr *hdr;8674 char signature_req[SMB2_SIGNATURE_SIZE];8675 char signature[SMB2_HMACSHA256_SIZE];8676 struct kvec iov[1];8677 size_t len;8678 8679 hdr = smb2_get_msg(work->request_buf);8680 if (work->next_smb2_rcv_hdr_off)8681 hdr = ksmbd_req_buf_next(work);8682 8683 if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off)8684 len = get_rfc1002_len(work->request_buf);8685 else if (hdr->NextCommand)8686 len = le32_to_cpu(hdr->NextCommand);8687 else8688 len = get_rfc1002_len(work->request_buf) -8689 work->next_smb2_rcv_hdr_off;8690 8691 memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE);8692 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);8693 8694 iov[0].iov_base = (char *)&hdr->ProtocolId;8695 iov[0].iov_len = len;8696 8697 if (ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, 1,8698 signature))8699 return 0;8700 8701 if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {8702 pr_err("bad smb2 signature\n");8703 return 0;8704 }8705 8706 return 1;8707}8708 8709/**8710 * smb2_set_sign_rsp() - handler for rsp packet sign processing8711 * @work: smb work containing notify command buffer8712 *8713 */8714void smb2_set_sign_rsp(struct ksmbd_work *work)8715{8716 struct smb2_hdr *hdr;8717 char signature[SMB2_HMACSHA256_SIZE];8718 struct kvec *iov;8719 int n_vec = 1;8720 8721 hdr = ksmbd_resp_buf_curr(work);8722 hdr->Flags |= SMB2_FLAGS_SIGNED;8723 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);8724 8725 if (hdr->Command == SMB2_READ) {8726 iov = &work->iov[work->iov_idx - 1];8727 n_vec++;8728 } else {8729 iov = &work->iov[work->iov_idx];8730 }8731 8732 if (!ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec,8733 signature))8734 memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);8735}8736 8737/**8738 * smb3_check_sign_req() - handler for req packet sign processing8739 * @work: smb work containing notify command buffer8740 *8741 * Return: 1 on success, 0 otherwise8742 */8743int smb3_check_sign_req(struct ksmbd_work *work)8744{8745 struct ksmbd_conn *conn = work->conn;8746 char *signing_key;8747 struct smb2_hdr *hdr;8748 struct channel *chann;8749 char signature_req[SMB2_SIGNATURE_SIZE];8750 char signature[SMB2_CMACAES_SIZE];8751 struct kvec iov[1];8752 size_t len;8753 8754 hdr = smb2_get_msg(work->request_buf);8755 if (work->next_smb2_rcv_hdr_off)8756 hdr = ksmbd_req_buf_next(work);8757 8758 if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off)8759 len = get_rfc1002_len(work->request_buf);8760 else if (hdr->NextCommand)8761 len = le32_to_cpu(hdr->NextCommand);8762 else8763 len = get_rfc1002_len(work->request_buf) -8764 work->next_smb2_rcv_hdr_off;8765 8766 if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {8767 signing_key = work->sess->smb3signingkey;8768 } else {8769 chann = lookup_chann_list(work->sess, conn);8770 if (!chann) {8771 return 0;8772 }8773 signing_key = chann->smb3signingkey;8774 }8775 8776 if (!signing_key) {8777 pr_err("SMB3 signing key is not generated\n");8778 return 0;8779 }8780 8781 memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE);8782 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);8783 iov[0].iov_base = (char *)&hdr->ProtocolId;8784 iov[0].iov_len = len;8785 8786 if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature))8787 return 0;8788 8789 if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {8790 pr_err("bad smb2 signature\n");8791 return 0;8792 }8793 8794 return 1;8795}8796 8797/**8798 * smb3_set_sign_rsp() - handler for rsp packet sign processing8799 * @work: smb work containing notify command buffer8800 *8801 */8802void smb3_set_sign_rsp(struct ksmbd_work *work)8803{8804 struct ksmbd_conn *conn = work->conn;8805 struct smb2_hdr *hdr;8806 struct channel *chann;8807 char signature[SMB2_CMACAES_SIZE];8808 struct kvec *iov;8809 int n_vec = 1;8810 char *signing_key;8811 8812 hdr = ksmbd_resp_buf_curr(work);8813 8814 if (conn->binding == false &&8815 le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {8816 signing_key = work->sess->smb3signingkey;8817 } else {8818 chann = lookup_chann_list(work->sess, work->conn);8819 if (!chann) {8820 return;8821 }8822 signing_key = chann->smb3signingkey;8823 }8824 8825 if (!signing_key)8826 return;8827 8828 hdr->Flags |= SMB2_FLAGS_SIGNED;8829 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);8830 8831 if (hdr->Command == SMB2_READ) {8832 iov = &work->iov[work->iov_idx - 1];8833 n_vec++;8834 } else {8835 iov = &work->iov[work->iov_idx];8836 }8837 8838 if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec,8839 signature))8840 memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);8841}8842 8843/**8844 * smb3_preauth_hash_rsp() - handler for computing preauth hash on response8845 * @work: smb work containing response buffer8846 *8847 */8848void smb3_preauth_hash_rsp(struct ksmbd_work *work)8849{8850 struct ksmbd_conn *conn = work->conn;8851 struct ksmbd_session *sess = work->sess;8852 struct smb2_hdr *req, *rsp;8853 8854 if (conn->dialect != SMB311_PROT_ID)8855 return;8856 8857 WORK_BUFFERS(work, req, rsp);8858 8859 if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE &&8860 conn->preauth_info)8861 ksmbd_gen_preauth_integrity_hash(conn, work->response_buf,8862 conn->preauth_info->Preauth_HashValue);8863 8864 if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) {8865 __u8 *hash_value;8866 8867 if (conn->binding) {8868 struct preauth_session *preauth_sess;8869 8870 preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);8871 if (!preauth_sess)8872 return;8873 hash_value = preauth_sess->Preauth_HashValue;8874 } else {8875 hash_value = sess->Preauth_HashValue;8876 if (!hash_value)8877 return;8878 }8879 ksmbd_gen_preauth_integrity_hash(conn, work->response_buf,8880 hash_value);8881 }8882}8883 8884static void fill_transform_hdr(void *tr_buf, char *old_buf, __le16 cipher_type)8885{8886 struct smb2_transform_hdr *tr_hdr = tr_buf + 4;8887 struct smb2_hdr *hdr = smb2_get_msg(old_buf);8888 unsigned int orig_len = get_rfc1002_len(old_buf);8889 8890 /* tr_buf must be cleared by the caller */8891 tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;8892 tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);8893 tr_hdr->Flags = cpu_to_le16(TRANSFORM_FLAG_ENCRYPTED);8894 if (cipher_type == SMB2_ENCRYPTION_AES128_GCM ||8895 cipher_type == SMB2_ENCRYPTION_AES256_GCM)8896 get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE);8897 else8898 get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE);8899 memcpy(&tr_hdr->SessionId, &hdr->SessionId, 8);8900 inc_rfc1001_len(tr_buf, sizeof(struct smb2_transform_hdr));8901 inc_rfc1001_len(tr_buf, orig_len);8902}8903 8904int smb3_encrypt_resp(struct ksmbd_work *work)8905{8906 struct kvec *iov = work->iov;8907 int rc = -ENOMEM;8908 void *tr_buf;8909 8910 tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL);8911 if (!tr_buf)8912 return rc;8913 8914 /* fill transform header */8915 fill_transform_hdr(tr_buf, work->response_buf, work->conn->cipher_type);8916 8917 iov[0].iov_base = tr_buf;8918 iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;8919 work->tr_buf = tr_buf;8920 8921 return ksmbd_crypt_message(work, iov, work->iov_idx + 1, 1);8922}8923 8924bool smb3_is_transform_hdr(void *buf)8925{8926 struct smb2_transform_hdr *trhdr = smb2_get_msg(buf);8927 8928 return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;8929}8930 8931int smb3_decrypt_req(struct ksmbd_work *work)8932{8933 struct ksmbd_session *sess;8934 char *buf = work->request_buf;8935 unsigned int pdu_length = get_rfc1002_len(buf);8936 struct kvec iov[2];8937 int buf_data_size = pdu_length - sizeof(struct smb2_transform_hdr);8938 struct smb2_transform_hdr *tr_hdr = smb2_get_msg(buf);8939 int rc = 0;8940 8941 if (pdu_length < sizeof(struct smb2_transform_hdr) ||8942 buf_data_size < sizeof(struct smb2_hdr)) {8943 pr_err("Transform message is too small (%u)\n",8944 pdu_length);8945 return -ECONNABORTED;8946 }8947 8948 if (buf_data_size < le32_to_cpu(tr_hdr->OriginalMessageSize)) {8949 pr_err("Transform message is broken\n");8950 return -ECONNABORTED;8951 }8952 8953 sess = ksmbd_session_lookup_all(work->conn, le64_to_cpu(tr_hdr->SessionId));8954 if (!sess) {8955 pr_err("invalid session id(%llx) in transform header\n",8956 le64_to_cpu(tr_hdr->SessionId));8957 return -ECONNABORTED;8958 }8959 8960 iov[0].iov_base = buf;8961 iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;8962 iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr) + 4;8963 iov[1].iov_len = buf_data_size;8964 rc = ksmbd_crypt_message(work, iov, 2, 0);8965 if (rc)8966 return rc;8967 8968 memmove(buf + 4, iov[1].iov_base, buf_data_size);8969 *(__be32 *)buf = cpu_to_be32(buf_data_size);8970 8971 return rc;8972}8973 8974bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)8975{8976 struct ksmbd_conn *conn = work->conn;8977 struct ksmbd_session *sess = work->sess;8978 struct smb2_hdr *rsp = smb2_get_msg(work->response_buf);8979 8980 if (conn->dialect < SMB30_PROT_ID)8981 return false;8982 8983 if (work->next_smb2_rcv_hdr_off)8984 rsp = ksmbd_resp_buf_next(work);8985 8986 if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE &&8987 sess->user && !user_guest(sess->user) &&8988 rsp->Status == STATUS_SUCCESS)8989 return true;8990 return false;8991}8992