blob: 6304c9bda479c7ed4aaddb22eb32370ff3e065c8 [file] [log] [blame]
Namjae Jeone2f34482021-03-16 10:49:09 +09001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
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>
Namjae Jeone8c06192021-06-22 11:06:11 +090013#include <linux/falloc.h>
Namjae Jeone2f34482021-03-16 10:49:09 +090014
15#include "glob.h"
16#include "smb2pdu.h"
17#include "smbfsctl.h"
18#include "oplock.h"
19#include "smbacl.h"
20
21#include "auth.h"
22#include "asn1.h"
Namjae Jeone2f34482021-03-16 10:49:09 +090023#include "connection.h"
24#include "transport_ipc.h"
Hyunchul Lee03d8d4f2021-07-13 16:09:34 +090025#include "transport_rdma.h"
Namjae Jeone2f34482021-03-16 10:49:09 +090026#include "vfs.h"
27#include "vfs_cache.h"
28#include "misc.h"
29
Namjae Jeone2f34482021-03-16 10:49:09 +090030#include "server.h"
31#include "smb_common.h"
32#include "smbstatus.h"
33#include "ksmbd_work.h"
34#include "mgmt/user_config.h"
35#include "mgmt/share_config.h"
36#include "mgmt/tree_connect.h"
37#include "mgmt/user_session.h"
38#include "mgmt/ksmbd_ida.h"
39#include "ndr.h"
40
41static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
42{
43 if (work->next_smb2_rcv_hdr_off) {
Namjae Jeon8a893312021-06-25 13:43:37 +090044 *req = ksmbd_req_buf_next(work);
45 *rsp = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +090046 } else {
Namjae Jeone5066492021-03-30 12:35:23 +090047 *req = work->request_buf;
48 *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +090049 }
50}
51
52#define WORK_BUFFERS(w, rq, rs) __wbuf((w), (void **)&(rq), (void **)&(rs))
53
54/**
55 * check_session_id() - check for valid session id in smb header
56 * @conn: connection instance
57 * @id: session id from smb header
58 *
59 * Return: 1 if valid session id, otherwise 0
60 */
Namjae Jeonf4228b62021-08-12 10:16:40 +090061static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
Namjae Jeone2f34482021-03-16 10:49:09 +090062{
63 struct ksmbd_session *sess;
64
65 if (id == 0 || id == -1)
Namjae Jeonf4228b62021-08-12 10:16:40 +090066 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +090067
Namjae Jeonf5a544e2021-06-18 10:04:19 +090068 sess = ksmbd_session_lookup_all(conn, id);
Namjae Jeone2f34482021-03-16 10:49:09 +090069 if (sess)
Namjae Jeonf4228b62021-08-12 10:16:40 +090070 return true;
Namjae Jeonbde16942021-06-28 15:23:19 +090071 pr_err("Invalid user session id: %llu\n", id);
Namjae Jeonf4228b62021-08-12 10:16:40 +090072 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +090073}
74
Namjae Jeonf5a544e2021-06-18 10:04:19 +090075struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)
Namjae Jeone2f34482021-03-16 10:49:09 +090076{
77 struct channel *chann;
Namjae Jeone2f34482021-03-16 10:49:09 +090078
Namjae Jeon6f3d5ee2021-06-18 10:28:52 +090079 list_for_each_entry(chann, &sess->ksmbd_chann_list, chann_list) {
Namjae Jeon560ac052021-06-22 16:16:45 +090080 if (chann->conn == conn)
Namjae Jeone2f34482021-03-16 10:49:09 +090081 return chann;
82 }
83
84 return NULL;
85}
86
87/**
Namjae Jeon5ec3df8e2021-08-12 10:17:39 +090088 * smb2_get_ksmbd_tcon() - get tree connection information using a tree id.
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +090089 * @work: smb work
Namjae Jeone2f34482021-03-16 10:49:09 +090090 *
Namjae Jeon5ec3df8e2021-08-12 10:17:39 +090091 * Return: 0 if there is a tree connection matched or these are
92 * skipable commands, otherwise error
Namjae Jeone2f34482021-03-16 10:49:09 +090093 */
94int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
95{
Namjae Jeone5066492021-03-30 12:35:23 +090096 struct smb2_hdr *req_hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +090097 int tree_id;
98
99 work->tcon = NULL;
Namjae Jeon64b39f42021-03-30 14:25:35 +0900100 if (work->conn->ops->get_cmd_val(work) == SMB2_TREE_CONNECT_HE ||
101 work->conn->ops->get_cmd_val(work) == SMB2_CANCEL_HE ||
102 work->conn->ops->get_cmd_val(work) == SMB2_LOGOFF_HE) {
Namjae Jeone2f34482021-03-16 10:49:09 +0900103 ksmbd_debug(SMB, "skip to check tree connect request\n");
104 return 0;
105 }
106
Namjae Jeon02b68b22021-04-01 17:45:33 +0900107 if (xa_empty(&work->sess->tree_conns)) {
Namjae Jeone2f34482021-03-16 10:49:09 +0900108 ksmbd_debug(SMB, "NO tree connected\n");
Namjae Jeonc6ce2b52021-08-12 10:18:18 +0900109 return -ENOENT;
Namjae Jeone2f34482021-03-16 10:49:09 +0900110 }
111
112 tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId);
113 work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id);
114 if (!work->tcon) {
Namjae Jeonbde16942021-06-28 15:23:19 +0900115 pr_err("Invalid tid %d\n", tree_id);
Namjae Jeonc6ce2b52021-08-12 10:18:18 +0900116 return -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +0900117 }
118
119 return 1;
120}
121
122/**
123 * smb2_set_err_rsp() - set error response code on smb response
124 * @work: smb work containing response buffer
125 */
126void smb2_set_err_rsp(struct ksmbd_work *work)
127{
128 struct smb2_err_rsp *err_rsp;
129
130 if (work->next_smb2_rcv_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +0900131 err_rsp = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +0900132 else
Namjae Jeone5066492021-03-30 12:35:23 +0900133 err_rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900134
135 if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) {
136 err_rsp->StructureSize = SMB2_ERROR_STRUCTURE_SIZE2_LE;
137 err_rsp->ErrorContextCount = 0;
138 err_rsp->Reserved = 0;
139 err_rsp->ByteCount = 0;
140 err_rsp->ErrorData[0] = 0;
Namjae Jeone5066492021-03-30 12:35:23 +0900141 inc_rfc1001_len(work->response_buf, SMB2_ERROR_STRUCTURE_SIZE2);
Namjae Jeone2f34482021-03-16 10:49:09 +0900142 }
143}
144
145/**
146 * is_smb2_neg_cmd() - is it smb2 negotiation command
147 * @work: smb work containing smb header
148 *
Namjae Jeonf4228b62021-08-12 10:16:40 +0900149 * Return: true if smb2 negotiation command, otherwise false
Namjae Jeone2f34482021-03-16 10:49:09 +0900150 */
Namjae Jeonf4228b62021-08-12 10:16:40 +0900151bool is_smb2_neg_cmd(struct ksmbd_work *work)
Namjae Jeone2f34482021-03-16 10:49:09 +0900152{
Namjae Jeone5066492021-03-30 12:35:23 +0900153 struct smb2_hdr *hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900154
155 /* is it SMB2 header ? */
156 if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
Namjae Jeonf4228b62021-08-12 10:16:40 +0900157 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +0900158
159 /* make sure it is request not response message */
160 if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
Namjae Jeonf4228b62021-08-12 10:16:40 +0900161 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +0900162
163 if (hdr->Command != SMB2_NEGOTIATE)
Namjae Jeonf4228b62021-08-12 10:16:40 +0900164 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +0900165
Namjae Jeonf4228b62021-08-12 10:16:40 +0900166 return true;
Namjae Jeone2f34482021-03-16 10:49:09 +0900167}
168
169/**
170 * is_smb2_rsp() - is it smb2 response
171 * @work: smb work containing smb response buffer
172 *
Namjae Jeonf4228b62021-08-12 10:16:40 +0900173 * Return: true if smb2 response, otherwise false
Namjae Jeone2f34482021-03-16 10:49:09 +0900174 */
Namjae Jeonf4228b62021-08-12 10:16:40 +0900175bool is_smb2_rsp(struct ksmbd_work *work)
Namjae Jeone2f34482021-03-16 10:49:09 +0900176{
Namjae Jeone5066492021-03-30 12:35:23 +0900177 struct smb2_hdr *hdr = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900178
179 /* is it SMB2 header ? */
180 if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
Namjae Jeonf4228b62021-08-12 10:16:40 +0900181 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +0900182
183 /* make sure it is response not request message */
184 if (!(hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR))
Namjae Jeonf4228b62021-08-12 10:16:40 +0900185 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +0900186
Namjae Jeonf4228b62021-08-12 10:16:40 +0900187 return true;
Namjae Jeone2f34482021-03-16 10:49:09 +0900188}
189
190/**
191 * get_smb2_cmd_val() - get smb command code from smb header
192 * @work: smb work containing smb request buffer
193 *
194 * Return: smb2 request command value
195 */
Namjae Jeonfc2d1b52021-05-26 18:01:08 +0900196u16 get_smb2_cmd_val(struct ksmbd_work *work)
Namjae Jeone2f34482021-03-16 10:49:09 +0900197{
198 struct smb2_hdr *rcv_hdr;
199
200 if (work->next_smb2_rcv_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +0900201 rcv_hdr = ksmbd_req_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +0900202 else
Namjae Jeone5066492021-03-30 12:35:23 +0900203 rcv_hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900204 return le16_to_cpu(rcv_hdr->Command);
205}
206
207/**
208 * set_smb2_rsp_status() - set error response code on smb2 header
209 * @work: smb work containing response buffer
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +0900210 * @err: error response code
Namjae Jeone2f34482021-03-16 10:49:09 +0900211 */
212void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err)
213{
214 struct smb2_hdr *rsp_hdr;
215
216 if (work->next_smb2_rcv_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +0900217 rsp_hdr = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +0900218 else
Namjae Jeone5066492021-03-30 12:35:23 +0900219 rsp_hdr = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900220 rsp_hdr->Status = err;
221 smb2_set_err_rsp(work);
222}
223
224/**
225 * init_smb2_neg_rsp() - initialize smb2 response for negotiate command
226 * @work: smb work containing smb request buffer
227 *
228 * smb2 negotiate response is sent in reply of smb1 negotiate command for
229 * dialect auto-negotiation.
230 */
231int init_smb2_neg_rsp(struct ksmbd_work *work)
232{
233 struct smb2_hdr *rsp_hdr;
234 struct smb2_negotiate_rsp *rsp;
235 struct ksmbd_conn *conn = work->conn;
236
237 if (conn->need_neg == false)
238 return -EINVAL;
239 if (!(conn->dialect >= SMB20_PROT_ID &&
Namjae Jeon64b39f42021-03-30 14:25:35 +0900240 conn->dialect <= SMB311_PROT_ID))
Namjae Jeone2f34482021-03-16 10:49:09 +0900241 return -EINVAL;
242
Namjae Jeone5066492021-03-30 12:35:23 +0900243 rsp_hdr = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900244
245 memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
246
247 rsp_hdr->smb2_buf_length =
Hyunchul Leed8fb2992021-06-25 11:53:26 +0900248 cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals));
Namjae Jeone2f34482021-03-16 10:49:09 +0900249
250 rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
251 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
252 rsp_hdr->CreditRequest = cpu_to_le16(2);
253 rsp_hdr->Command = SMB2_NEGOTIATE;
254 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
255 rsp_hdr->NextCommand = 0;
256 rsp_hdr->MessageId = 0;
257 rsp_hdr->Id.SyncId.ProcessId = 0;
258 rsp_hdr->Id.SyncId.TreeId = 0;
259 rsp_hdr->SessionId = 0;
260 memset(rsp_hdr->Signature, 0, 16);
261
Namjae Jeone5066492021-03-30 12:35:23 +0900262 rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900263
264 WARN_ON(ksmbd_conn_good(work));
265
266 rsp->StructureSize = cpu_to_le16(65);
267 ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
268 rsp->DialectRevision = cpu_to_le16(conn->dialect);
269 /* Not setting conn guid rsp->ServerGUID, as it
270 * not used by client for identifying connection
271 */
272 rsp->Capabilities = cpu_to_le32(conn->vals->capabilities);
273 /* Default Max Message Size till SMB2.0, 64K*/
274 rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size);
275 rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size);
276 rsp->MaxWriteSize = cpu_to_le32(conn->vals->max_write_size);
277
278 rsp->SystemTime = cpu_to_le64(ksmbd_systime());
279 rsp->ServerStartTime = 0;
280
281 rsp->SecurityBufferOffset = cpu_to_le16(128);
282 rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH);
283 ksmbd_copy_gss_neg_header(((char *)(&rsp->hdr) +
284 sizeof(rsp->hdr.smb2_buf_length)) +
285 le16_to_cpu(rsp->SecurityBufferOffset));
286 inc_rfc1001_len(rsp, sizeof(struct smb2_negotiate_rsp) -
287 sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) +
288 AUTH_GSS_LENGTH);
289 rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE;
290 if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY)
291 rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;
292 conn->use_spnego = true;
293
294 ksmbd_conn_set_need_negotiate(work);
295 return 0;
296}
297
298static int smb2_consume_credit_charge(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +0900299 unsigned short credit_charge)
Namjae Jeone2f34482021-03-16 10:49:09 +0900300{
301 struct ksmbd_conn *conn = work->conn;
302 unsigned int rsp_credits = 1;
303
304 if (!conn->total_credits)
305 return 0;
306
307 if (credit_charge > 0)
308 rsp_credits = credit_charge;
309
310 conn->total_credits -= rsp_credits;
311 return rsp_credits;
312}
313
314/**
315 * smb2_set_rsp_credits() - set number of credits in response buffer
316 * @work: smb work containing smb response buffer
317 */
318int smb2_set_rsp_credits(struct ksmbd_work *work)
319{
Namjae Jeon8a893312021-06-25 13:43:37 +0900320 struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work);
321 struct smb2_hdr *hdr = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +0900322 struct ksmbd_conn *conn = work->conn;
323 unsigned short credits_requested = le16_to_cpu(req_hdr->CreditRequest);
324 unsigned short credit_charge = 1, credits_granted = 0;
325 unsigned short aux_max, aux_credits, min_credits;
326 int rsp_credit_charge;
327
328 if (hdr->Command == SMB2_CANCEL)
329 goto out;
330
331 /* get default minimum credits by shifting maximum credits by 4 */
332 min_credits = conn->max_credits >> 4;
333
334 if (conn->total_credits >= conn->max_credits) {
Namjae Jeonbde16942021-06-28 15:23:19 +0900335 pr_err("Total credits overflow: %d\n", conn->total_credits);
Namjae Jeone2f34482021-03-16 10:49:09 +0900336 conn->total_credits = min_credits;
337 }
338
Namjae Jeon070fb212021-05-26 17:57:12 +0900339 rsp_credit_charge =
340 smb2_consume_credit_charge(work, le16_to_cpu(req_hdr->CreditCharge));
Namjae Jeone2f34482021-03-16 10:49:09 +0900341 if (rsp_credit_charge < 0)
342 return -EINVAL;
343
344 hdr->CreditCharge = cpu_to_le16(rsp_credit_charge);
345
346 if (credits_requested > 0) {
347 aux_credits = credits_requested - 1;
348 aux_max = 32;
349 if (hdr->Command == SMB2_NEGOTIATE)
350 aux_max = 0;
351 aux_credits = (aux_credits < aux_max) ? aux_credits : aux_max;
352 credits_granted = aux_credits + credit_charge;
353
354 /* if credits granted per client is getting bigger than default
355 * minimum credits then we should wrap it up within the limits.
356 */
357 if ((conn->total_credits + credits_granted) > min_credits)
358 credits_granted = min_credits - conn->total_credits;
359 /*
360 * TODO: Need to adjuct CreditRequest value according to
361 * current cpu load
362 */
363 } else if (conn->total_credits == 0) {
364 credits_granted = 1;
365 }
366
367 conn->total_credits += credits_granted;
368 work->credits_granted += credits_granted;
369
370 if (!req_hdr->NextCommand) {
371 /* Update CreditRequest in last request */
372 hdr->CreditRequest = cpu_to_le16(work->credits_granted);
373 }
374out:
375 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +0900376 "credits: requested[%d] granted[%d] total_granted[%d]\n",
377 credits_requested, credits_granted,
378 conn->total_credits);
Namjae Jeone2f34482021-03-16 10:49:09 +0900379 return 0;
380}
381
382/**
383 * init_chained_smb2_rsp() - initialize smb2 chained response
384 * @work: smb work containing smb response buffer
385 */
386static void init_chained_smb2_rsp(struct ksmbd_work *work)
387{
Namjae Jeon8a893312021-06-25 13:43:37 +0900388 struct smb2_hdr *req = ksmbd_req_buf_next(work);
389 struct smb2_hdr *rsp = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +0900390 struct smb2_hdr *rsp_hdr;
391 struct smb2_hdr *rcv_hdr;
392 int next_hdr_offset = 0;
393 int len, new_len;
394
395 /* Len of this response = updated RFC len - offset of previous cmd
396 * in the compound rsp
397 */
398
399 /* Storing the current local FID which may be needed by subsequent
400 * command in the compound request
401 */
402 if (req->Command == SMB2_CREATE && rsp->Status == STATUS_SUCCESS) {
403 work->compound_fid =
404 le64_to_cpu(((struct smb2_create_rsp *)rsp)->
405 VolatileFileId);
406 work->compound_pfid =
407 le64_to_cpu(((struct smb2_create_rsp *)rsp)->
408 PersistentFileId);
409 work->compound_sid = le64_to_cpu(rsp->SessionId);
410 }
411
Namjae Jeone5066492021-03-30 12:35:23 +0900412 len = get_rfc1002_len(work->response_buf) - work->next_smb2_rsp_hdr_off;
Namjae Jeone2f34482021-03-16 10:49:09 +0900413 next_hdr_offset = le32_to_cpu(req->NextCommand);
414
415 new_len = ALIGN(len, 8);
Namjae Jeone5066492021-03-30 12:35:23 +0900416 inc_rfc1001_len(work->response_buf, ((sizeof(struct smb2_hdr) - 4)
Namjae Jeone2f34482021-03-16 10:49:09 +0900417 + new_len - len));
418 rsp->NextCommand = cpu_to_le32(new_len);
419
420 work->next_smb2_rcv_hdr_off += next_hdr_offset;
421 work->next_smb2_rsp_hdr_off += new_len;
422 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +0900423 "Compound req new_len = %d rcv off = %d rsp off = %d\n",
424 new_len, work->next_smb2_rcv_hdr_off,
425 work->next_smb2_rsp_hdr_off);
Namjae Jeone2f34482021-03-16 10:49:09 +0900426
Namjae Jeon8a893312021-06-25 13:43:37 +0900427 rsp_hdr = ksmbd_resp_buf_next(work);
428 rcv_hdr = ksmbd_req_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +0900429
430 if (!(rcv_hdr->Flags & SMB2_FLAGS_RELATED_OPERATIONS)) {
431 ksmbd_debug(SMB, "related flag should be set\n");
432 work->compound_fid = KSMBD_NO_FID;
433 work->compound_pfid = KSMBD_NO_FID;
434 }
435 memset((char *)rsp_hdr + 4, 0, sizeof(struct smb2_hdr) + 2);
436 rsp_hdr->ProtocolId = rcv_hdr->ProtocolId;
437 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
438 rsp_hdr->Command = rcv_hdr->Command;
439
440 /*
441 * Message is response. We don't grant oplock yet.
442 */
443 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR |
444 SMB2_FLAGS_RELATED_OPERATIONS);
445 rsp_hdr->NextCommand = 0;
446 rsp_hdr->MessageId = rcv_hdr->MessageId;
447 rsp_hdr->Id.SyncId.ProcessId = rcv_hdr->Id.SyncId.ProcessId;
448 rsp_hdr->Id.SyncId.TreeId = rcv_hdr->Id.SyncId.TreeId;
449 rsp_hdr->SessionId = rcv_hdr->SessionId;
450 memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);
451}
452
453/**
454 * is_chained_smb2_message() - check for chained command
455 * @work: smb work containing smb request buffer
456 *
457 * Return: true if chained request, otherwise false
458 */
459bool is_chained_smb2_message(struct ksmbd_work *work)
460{
Namjae Jeone5066492021-03-30 12:35:23 +0900461 struct smb2_hdr *hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900462 unsigned int len;
463
464 if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
465 return false;
466
Namjae Jeon8a893312021-06-25 13:43:37 +0900467 hdr = ksmbd_req_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +0900468 if (le32_to_cpu(hdr->NextCommand) > 0) {
469 ksmbd_debug(SMB, "got SMB2 chained command\n");
470 init_chained_smb2_rsp(work);
471 return true;
472 } else if (work->next_smb2_rcv_hdr_off) {
473 /*
474 * This is last request in chained command,
475 * align response to 8 byte
476 */
Namjae Jeone5066492021-03-30 12:35:23 +0900477 len = ALIGN(get_rfc1002_len(work->response_buf), 8);
478 len = len - get_rfc1002_len(work->response_buf);
Namjae Jeone2f34482021-03-16 10:49:09 +0900479 if (len) {
480 ksmbd_debug(SMB, "padding len %u\n", len);
Namjae Jeone5066492021-03-30 12:35:23 +0900481 inc_rfc1001_len(work->response_buf, len);
482 if (work->aux_payload_sz)
Namjae Jeone2f34482021-03-16 10:49:09 +0900483 work->aux_payload_sz += len;
484 }
485 }
486 return false;
487}
488
489/**
490 * init_smb2_rsp_hdr() - initialize smb2 response
491 * @work: smb work containing smb request buffer
492 *
493 * Return: 0
494 */
495int init_smb2_rsp_hdr(struct ksmbd_work *work)
496{
Namjae Jeone5066492021-03-30 12:35:23 +0900497 struct smb2_hdr *rsp_hdr = work->response_buf;
498 struct smb2_hdr *rcv_hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900499 struct ksmbd_conn *conn = work->conn;
500
501 memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
Hyunchul Leed8fb2992021-06-25 11:53:26 +0900502 rsp_hdr->smb2_buf_length =
503 cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals));
Namjae Jeone2f34482021-03-16 10:49:09 +0900504 rsp_hdr->ProtocolId = rcv_hdr->ProtocolId;
505 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
506 rsp_hdr->Command = rcv_hdr->Command;
507
508 /*
509 * Message is response. We don't grant oplock yet.
510 */
511 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
512 rsp_hdr->NextCommand = 0;
513 rsp_hdr->MessageId = rcv_hdr->MessageId;
514 rsp_hdr->Id.SyncId.ProcessId = rcv_hdr->Id.SyncId.ProcessId;
515 rsp_hdr->Id.SyncId.TreeId = rcv_hdr->Id.SyncId.TreeId;
516 rsp_hdr->SessionId = rcv_hdr->SessionId;
517 memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);
518
519 work->syncronous = true;
520 if (work->async_id) {
Namjae Jeond40012a2021-04-13 13:06:30 +0900521 ksmbd_release_id(&conn->async_ida, work->async_id);
Namjae Jeone2f34482021-03-16 10:49:09 +0900522 work->async_id = 0;
523 }
524
525 return 0;
526}
527
528/**
529 * smb2_allocate_rsp_buf() - allocate smb2 response buffer
530 * @work: smb work containing smb request buffer
531 *
532 * Return: 0 on success, otherwise -ENOMEM
533 */
534int smb2_allocate_rsp_buf(struct ksmbd_work *work)
535{
Namjae Jeone5066492021-03-30 12:35:23 +0900536 struct smb2_hdr *hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900537 size_t small_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
538 size_t large_sz = work->conn->vals->max_trans_size + MAX_SMB2_HDR_SIZE;
539 size_t sz = small_sz;
540 int cmd = le16_to_cpu(hdr->Command);
541
Namjae Jeonc30f4eb2021-06-18 10:17:37 +0900542 if (cmd == SMB2_IOCTL_HE || cmd == SMB2_QUERY_DIRECTORY_HE)
Namjae Jeone2f34482021-03-16 10:49:09 +0900543 sz = large_sz;
Namjae Jeone2f34482021-03-16 10:49:09 +0900544
545 if (cmd == SMB2_QUERY_INFO_HE) {
546 struct smb2_query_info_req *req;
547
Namjae Jeone5066492021-03-30 12:35:23 +0900548 req = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900549 if (req->InfoType == SMB2_O_INFO_FILE &&
Namjae Jeon64b39f42021-03-30 14:25:35 +0900550 (req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
Namjae Jeonc30f4eb2021-06-18 10:17:37 +0900551 req->FileInfoClass == FILE_ALL_INFORMATION))
Namjae Jeone2f34482021-03-16 10:49:09 +0900552 sz = large_sz;
Namjae Jeone2f34482021-03-16 10:49:09 +0900553 }
554
555 /* allocate large response buf for chained commands */
556 if (le32_to_cpu(hdr->NextCommand) > 0)
557 sz = large_sz;
558
Namjae Jeonc30f4eb2021-06-18 10:17:37 +0900559 work->response_buf = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO);
Namjae Jeon63c454f2021-04-20 14:24:28 +0900560 if (!work->response_buf)
Namjae Jeone2f34482021-03-16 10:49:09 +0900561 return -ENOMEM;
Namjae Jeone2f34482021-03-16 10:49:09 +0900562
563 work->response_sz = sz;
564 return 0;
565}
566
567/**
568 * smb2_check_user_session() - check for valid session for a user
569 * @work: smb work containing smb request buffer
570 *
571 * Return: 0 on success, otherwise error
572 */
573int smb2_check_user_session(struct ksmbd_work *work)
574{
Namjae Jeone5066492021-03-30 12:35:23 +0900575 struct smb2_hdr *req_hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900576 struct ksmbd_conn *conn = work->conn;
577 unsigned int cmd = conn->ops->get_cmd_val(work);
578 unsigned long long sess_id;
579
580 work->sess = NULL;
581 /*
582 * SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not
583 * require a session id, so no need to validate user session's for
584 * these commands.
585 */
586 if (cmd == SMB2_ECHO_HE || cmd == SMB2_NEGOTIATE_HE ||
Namjae Jeon64b39f42021-03-30 14:25:35 +0900587 cmd == SMB2_SESSION_SETUP_HE)
Namjae Jeone2f34482021-03-16 10:49:09 +0900588 return 0;
589
590 if (!ksmbd_conn_good(work))
591 return -EINVAL;
592
593 sess_id = le64_to_cpu(req_hdr->SessionId);
594 /* Check for validity of user session */
Namjae Jeonf5a544e2021-06-18 10:04:19 +0900595 work->sess = ksmbd_session_lookup_all(conn, sess_id);
Namjae Jeone2f34482021-03-16 10:49:09 +0900596 if (work->sess)
597 return 1;
598 ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
599 return -EINVAL;
600}
601
Namjae Jeon64b39f42021-03-30 14:25:35 +0900602static void destroy_previous_session(struct ksmbd_user *user, u64 id)
Namjae Jeone2f34482021-03-16 10:49:09 +0900603{
604 struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
605 struct ksmbd_user *prev_user;
606
607 if (!prev_sess)
608 return;
609
610 prev_user = prev_sess->user;
611
Marios Makassikis1fca8032021-05-06 11:41:54 +0900612 if (!prev_user ||
613 strcmp(user->name, prev_user->name) ||
Namjae Jeone2f34482021-03-16 10:49:09 +0900614 user->passkey_sz != prev_user->passkey_sz ||
615 memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) {
616 put_session(prev_sess);
617 return;
618 }
619
620 put_session(prev_sess);
621 ksmbd_session_destroy(prev_sess);
622}
623
624/**
625 * smb2_get_name() - get filename string from on the wire smb format
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +0900626 * @share: ksmbd_share_config pointer
Namjae Jeone2f34482021-03-16 10:49:09 +0900627 * @src: source buffer
628 * @maxlen: maxlen of source string
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +0900629 * @nls_table: nls_table pointer
Namjae Jeone2f34482021-03-16 10:49:09 +0900630 *
631 * Return: matching converted filename on success, otherwise error ptr
632 */
633static char *
Namjae Jeon64b39f42021-03-30 14:25:35 +0900634smb2_get_name(struct ksmbd_share_config *share, const char *src,
Namjae Jeon070fb212021-05-26 17:57:12 +0900635 const int maxlen, struct nls_table *local_nls)
Namjae Jeone2f34482021-03-16 10:49:09 +0900636{
Hyunchul Leef58eae62021-09-17 22:14:08 +0900637 char *name, *norm_name, *unixname;
Namjae Jeone2f34482021-03-16 10:49:09 +0900638
Namjae Jeon64b39f42021-03-30 14:25:35 +0900639 name = smb_strndup_from_utf16(src, maxlen, 1, local_nls);
Namjae Jeone2f34482021-03-16 10:49:09 +0900640 if (IS_ERR(name)) {
Namjae Jeonbde16942021-06-28 15:23:19 +0900641 pr_err("failed to get name %ld\n", PTR_ERR(name));
Namjae Jeone2f34482021-03-16 10:49:09 +0900642 return name;
643 }
644
645 /* change it to absolute unix name */
Hyunchul Leef58eae62021-09-17 22:14:08 +0900646 norm_name = ksmbd_conv_path_to_unix(name);
647 if (IS_ERR(norm_name)) {
648 kfree(name);
649 return norm_name;
650 }
Namjae Jeone2f34482021-03-16 10:49:09 +0900651 kfree(name);
Hyunchul Leef58eae62021-09-17 22:14:08 +0900652
653 unixname = convert_to_unix_name(share, norm_name);
654 kfree(norm_name);
Namjae Jeone2f34482021-03-16 10:49:09 +0900655 if (!unixname) {
Namjae Jeonbde16942021-06-28 15:23:19 +0900656 pr_err("can not convert absolute name\n");
Namjae Jeone2f34482021-03-16 10:49:09 +0900657 return ERR_PTR(-ENOMEM);
658 }
659
660 ksmbd_debug(SMB, "absolute name = %s\n", unixname);
661 return unixname;
662}
663
Namjae Jeone2f34482021-03-16 10:49:09 +0900664int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
665{
666 struct smb2_hdr *rsp_hdr;
667 struct ksmbd_conn *conn = work->conn;
668 int id;
669
Namjae Jeone5066492021-03-30 12:35:23 +0900670 rsp_hdr = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900671 rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
672
Namjae Jeond40012a2021-04-13 13:06:30 +0900673 id = ksmbd_acquire_async_msg_id(&conn->async_ida);
Namjae Jeone2f34482021-03-16 10:49:09 +0900674 if (id < 0) {
Namjae Jeonbde16942021-06-28 15:23:19 +0900675 pr_err("Failed to alloc async message id\n");
Namjae Jeone2f34482021-03-16 10:49:09 +0900676 return id;
677 }
678 work->syncronous = false;
679 work->async_id = id;
680 rsp_hdr->Id.AsyncId = cpu_to_le64(id);
681
682 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +0900683 "Send interim Response to inform async request id : %d\n",
684 work->async_id);
Namjae Jeone2f34482021-03-16 10:49:09 +0900685
686 work->cancel_fn = fn;
687 work->cancel_argv = arg;
688
Namjae Jeon6c4e6752021-06-07 09:08:45 +0900689 if (list_empty(&work->async_request_entry)) {
690 spin_lock(&conn->request_lock);
691 list_add_tail(&work->async_request_entry, &conn->async_requests);
692 spin_unlock(&conn->request_lock);
693 }
Namjae Jeone2f34482021-03-16 10:49:09 +0900694
695 return 0;
696}
697
698void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
699{
700 struct smb2_hdr *rsp_hdr;
701
Namjae Jeone5066492021-03-30 12:35:23 +0900702 rsp_hdr = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +0900703 smb2_set_err_rsp(work);
704 rsp_hdr->Status = status;
705
706 work->multiRsp = 1;
707 ksmbd_conn_write(work);
708 rsp_hdr->Status = 0;
709 work->multiRsp = 0;
710}
711
712static __le32 smb2_get_reparse_tag_special_file(umode_t mode)
713{
714 if (S_ISDIR(mode) || S_ISREG(mode))
715 return 0;
716
717 if (S_ISLNK(mode))
718 return IO_REPARSE_TAG_LX_SYMLINK_LE;
719 else if (S_ISFIFO(mode))
720 return IO_REPARSE_TAG_LX_FIFO_LE;
721 else if (S_ISSOCK(mode))
722 return IO_REPARSE_TAG_AF_UNIX_LE;
723 else if (S_ISCHR(mode))
724 return IO_REPARSE_TAG_LX_CHR_LE;
725 else if (S_ISBLK(mode))
726 return IO_REPARSE_TAG_LX_BLK_LE;
727
728 return 0;
729}
730
731/**
732 * smb2_get_dos_mode() - get file mode in dos format from unix mode
733 * @stat: kstat containing file mode
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +0900734 * @attribute: attribute flags
Namjae Jeone2f34482021-03-16 10:49:09 +0900735 *
736 * Return: converted dos mode
737 */
738static int smb2_get_dos_mode(struct kstat *stat, int attribute)
739{
740 int attr = 0;
741
Namjae Jeon64b39f42021-03-30 14:25:35 +0900742 if (S_ISDIR(stat->mode)) {
Namjae Jeone2f34482021-03-16 10:49:09 +0900743 attr = ATTR_DIRECTORY |
744 (attribute & (ATTR_HIDDEN | ATTR_SYSTEM));
Namjae Jeon64b39f42021-03-30 14:25:35 +0900745 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +0900746 attr = (attribute & 0x00005137) | ATTR_ARCHIVE;
747 attr &= ~(ATTR_DIRECTORY);
748 if (S_ISREG(stat->mode) && (server_conf.share_fake_fscaps &
749 FILE_SUPPORTS_SPARSE_FILES))
750 attr |= ATTR_SPARSE;
751
752 if (smb2_get_reparse_tag_special_file(stat->mode))
753 attr |= ATTR_REPARSE;
754 }
755
756 return attr;
757}
758
759static void build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt,
Namjae Jeon070fb212021-05-26 17:57:12 +0900760 __le16 hash_id)
Namjae Jeone2f34482021-03-16 10:49:09 +0900761{
762 pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;
763 pneg_ctxt->DataLength = cpu_to_le16(38);
764 pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1);
765 pneg_ctxt->Reserved = cpu_to_le32(0);
766 pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE);
767 get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE);
768 pneg_ctxt->HashAlgorithms = hash_id;
769}
770
771static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt,
Namjae Jeon070fb212021-05-26 17:57:12 +0900772 __le16 cipher_type)
Namjae Jeone2f34482021-03-16 10:49:09 +0900773{
774 pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
775 pneg_ctxt->DataLength = cpu_to_le16(4);
776 pneg_ctxt->Reserved = cpu_to_le32(0);
777 pneg_ctxt->CipherCount = cpu_to_le16(1);
778 pneg_ctxt->Ciphers[0] = cipher_type;
779}
780
781static void build_compression_ctxt(struct smb2_compression_ctx *pneg_ctxt,
Namjae Jeon070fb212021-05-26 17:57:12 +0900782 __le16 comp_algo)
Namjae Jeone2f34482021-03-16 10:49:09 +0900783{
784 pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES;
785 pneg_ctxt->DataLength =
786 cpu_to_le16(sizeof(struct smb2_compression_ctx)
787 - sizeof(struct smb2_neg_context));
788 pneg_ctxt->Reserved = cpu_to_le32(0);
789 pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(1);
790 pneg_ctxt->Reserved1 = cpu_to_le32(0);
791 pneg_ctxt->CompressionAlgorithms[0] = comp_algo;
792}
793
Namjae Jeon378087c2021-07-21 10:05:53 +0900794static void build_sign_cap_ctxt(struct smb2_signing_capabilities *pneg_ctxt,
795 __le16 sign_algo)
796{
797 pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES;
798 pneg_ctxt->DataLength =
799 cpu_to_le16((sizeof(struct smb2_signing_capabilities) + 2)
800 - sizeof(struct smb2_neg_context));
801 pneg_ctxt->Reserved = cpu_to_le32(0);
802 pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(1);
803 pneg_ctxt->SigningAlgorithms[0] = sign_algo;
804}
805
Namjae Jeon64b39f42021-03-30 14:25:35 +0900806static void build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
Namjae Jeone2f34482021-03-16 10:49:09 +0900807{
808 pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE;
809 pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
810 /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
811 pneg_ctxt->Name[0] = 0x93;
812 pneg_ctxt->Name[1] = 0xAD;
813 pneg_ctxt->Name[2] = 0x25;
814 pneg_ctxt->Name[3] = 0x50;
815 pneg_ctxt->Name[4] = 0x9C;
816 pneg_ctxt->Name[5] = 0xB4;
817 pneg_ctxt->Name[6] = 0x11;
818 pneg_ctxt->Name[7] = 0xE7;
819 pneg_ctxt->Name[8] = 0xB4;
820 pneg_ctxt->Name[9] = 0x23;
821 pneg_ctxt->Name[10] = 0x83;
822 pneg_ctxt->Name[11] = 0xDE;
823 pneg_ctxt->Name[12] = 0x96;
824 pneg_ctxt->Name[13] = 0x8B;
825 pneg_ctxt->Name[14] = 0xCD;
826 pneg_ctxt->Name[15] = 0x7C;
827}
828
Namjae Jeon64b39f42021-03-30 14:25:35 +0900829static void assemble_neg_contexts(struct ksmbd_conn *conn,
Namjae Jeon070fb212021-05-26 17:57:12 +0900830 struct smb2_negotiate_rsp *rsp)
Namjae Jeone2f34482021-03-16 10:49:09 +0900831{
832 /* +4 is to account for the RFC1001 len field */
833 char *pneg_ctxt = (char *)rsp +
834 le32_to_cpu(rsp->NegotiateContextOffset) + 4;
835 int neg_ctxt_cnt = 1;
836 int ctxt_size;
837
838 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +0900839 "assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +0900840 build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt,
Namjae Jeon070fb212021-05-26 17:57:12 +0900841 conn->preauth_info->Preauth_HashId);
Namjae Jeone2f34482021-03-16 10:49:09 +0900842 rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt);
843 inc_rfc1001_len(rsp, AUTH_GSS_PADDING);
844 ctxt_size = sizeof(struct smb2_preauth_neg_context);
845 /* Round to 8 byte boundary */
846 pneg_ctxt += round_up(sizeof(struct smb2_preauth_neg_context), 8);
847
848 if (conn->cipher_type) {
849 ctxt_size = round_up(ctxt_size, 8);
850 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +0900851 "assemble SMB2_ENCRYPTION_CAPABILITIES context\n");
Namjae Jeon64b39f42021-03-30 14:25:35 +0900852 build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt,
Namjae Jeon070fb212021-05-26 17:57:12 +0900853 conn->cipher_type);
Namjae Jeone2f34482021-03-16 10:49:09 +0900854 rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
Namjae Jeonaf320a72021-07-21 10:03:19 +0900855 ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2;
Namjae Jeone2f34482021-03-16 10:49:09 +0900856 /* Round to 8 byte boundary */
857 pneg_ctxt +=
Namjae Jeonaf320a72021-07-21 10:03:19 +0900858 round_up(sizeof(struct smb2_encryption_neg_context) + 2,
Namjae Jeone2f34482021-03-16 10:49:09 +0900859 8);
860 }
861
862 if (conn->compress_algorithm) {
863 ctxt_size = round_up(ctxt_size, 8);
864 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +0900865 "assemble SMB2_COMPRESSION_CAPABILITIES context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +0900866 /* Temporarily set to SMB3_COMPRESS_NONE */
867 build_compression_ctxt((struct smb2_compression_ctx *)pneg_ctxt,
Namjae Jeon070fb212021-05-26 17:57:12 +0900868 conn->compress_algorithm);
Namjae Jeone2f34482021-03-16 10:49:09 +0900869 rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
Namjae Jeonaf320a72021-07-21 10:03:19 +0900870 ctxt_size += sizeof(struct smb2_compression_ctx) + 2;
Namjae Jeone2f34482021-03-16 10:49:09 +0900871 /* Round to 8 byte boundary */
Namjae Jeonaf320a72021-07-21 10:03:19 +0900872 pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx) + 2,
873 8);
Namjae Jeone2f34482021-03-16 10:49:09 +0900874 }
875
876 if (conn->posix_ext_supported) {
877 ctxt_size = round_up(ctxt_size, 8);
878 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +0900879 "assemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +0900880 build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
881 rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
882 ctxt_size += sizeof(struct smb2_posix_neg_context);
Namjae Jeon378087c2021-07-21 10:05:53 +0900883 /* Round to 8 byte boundary */
884 pneg_ctxt += round_up(sizeof(struct smb2_posix_neg_context), 8);
885 }
886
887 if (conn->signing_negotiated) {
888 ctxt_size = round_up(ctxt_size, 8);
889 ksmbd_debug(SMB,
890 "assemble SMB2_SIGNING_CAPABILITIES context\n");
891 build_sign_cap_ctxt((struct smb2_signing_capabilities *)pneg_ctxt,
892 conn->signing_algorithm);
893 rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
894 ctxt_size += sizeof(struct smb2_signing_capabilities) + 2;
Namjae Jeone2f34482021-03-16 10:49:09 +0900895 }
896
897 inc_rfc1001_len(rsp, ctxt_size);
898}
899
Namjae Jeon64b39f42021-03-30 14:25:35 +0900900static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
Namjae Jeon070fb212021-05-26 17:57:12 +0900901 struct smb2_preauth_neg_context *pneg_ctxt)
Namjae Jeone2f34482021-03-16 10:49:09 +0900902{
903 __le32 err = STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP;
904
Namjae Jeon070fb212021-05-26 17:57:12 +0900905 if (pneg_ctxt->HashAlgorithms == SMB2_PREAUTH_INTEGRITY_SHA512) {
Namjae Jeone2f34482021-03-16 10:49:09 +0900906 conn->preauth_info->Preauth_HashId =
907 SMB2_PREAUTH_INTEGRITY_SHA512;
908 err = STATUS_SUCCESS;
909 }
910
911 return err;
912}
913
Namjae Jeonaf320a72021-07-21 10:03:19 +0900914static void decode_encrypt_ctxt(struct ksmbd_conn *conn,
915 struct smb2_encryption_neg_context *pneg_ctxt,
916 int len_of_ctxts)
Namjae Jeone2f34482021-03-16 10:49:09 +0900917{
Namjae Jeone2f34482021-03-16 10:49:09 +0900918 int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
Namjae Jeonaf320a72021-07-21 10:03:19 +0900919 int i, cphs_size = cph_cnt * sizeof(__le16);
Namjae Jeone2f34482021-03-16 10:49:09 +0900920
921 conn->cipher_type = 0;
922
Namjae Jeonaf320a72021-07-21 10:03:19 +0900923 if (sizeof(struct smb2_encryption_neg_context) + cphs_size >
924 len_of_ctxts) {
925 pr_err("Invalid cipher count(%d)\n", cph_cnt);
926 return;
927 }
928
Namjae Jeone2f34482021-03-16 10:49:09 +0900929 if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION))
Namjae Jeonaf320a72021-07-21 10:03:19 +0900930 return;
Namjae Jeone2f34482021-03-16 10:49:09 +0900931
932 for (i = 0; i < cph_cnt; i++) {
933 if (pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_GCM ||
Namjae Jeon5a0ca772021-05-06 11:43:37 +0900934 pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_CCM ||
935 pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_CCM ||
936 pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_GCM) {
Namjae Jeone2f34482021-03-16 10:49:09 +0900937 ksmbd_debug(SMB, "Cipher ID = 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +0900938 pneg_ctxt->Ciphers[i]);
Namjae Jeone2f34482021-03-16 10:49:09 +0900939 conn->cipher_type = pneg_ctxt->Ciphers[i];
940 break;
941 }
942 }
Namjae Jeone2f34482021-03-16 10:49:09 +0900943}
944
Namjae Jeonaf320a72021-07-21 10:03:19 +0900945static void decode_compress_ctxt(struct ksmbd_conn *conn,
946 struct smb2_compression_ctx *pneg_ctxt)
Namjae Jeone2f34482021-03-16 10:49:09 +0900947{
Namjae Jeone2f34482021-03-16 10:49:09 +0900948 conn->compress_algorithm = SMB3_COMPRESS_NONE;
Namjae Jeone2f34482021-03-16 10:49:09 +0900949}
950
Namjae Jeon378087c2021-07-21 10:05:53 +0900951static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,
952 struct smb2_signing_capabilities *pneg_ctxt,
953 int len_of_ctxts)
954{
955 int sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);
956 int i, sign_alos_size = sign_algo_cnt * sizeof(__le16);
957
958 conn->signing_negotiated = false;
959
960 if (sizeof(struct smb2_signing_capabilities) + sign_alos_size >
961 len_of_ctxts) {
962 pr_err("Invalid signing algorithm count(%d)\n", sign_algo_cnt);
963 return;
964 }
965
966 for (i = 0; i < sign_algo_cnt; i++) {
967 if (pneg_ctxt->SigningAlgorithms[i] == SIGNING_ALG_HMAC_SHA256 ||
968 pneg_ctxt->SigningAlgorithms[i] == SIGNING_ALG_AES_CMAC) {
969 ksmbd_debug(SMB, "Signing Algorithm ID = 0x%x\n",
970 pneg_ctxt->SigningAlgorithms[i]);
971 conn->signing_negotiated = true;
972 conn->signing_algorithm =
973 pneg_ctxt->SigningAlgorithms[i];
974 break;
975 }
976 }
977}
978
Namjae Jeone2f34482021-03-16 10:49:09 +0900979static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
Namjae Jeon070fb212021-05-26 17:57:12 +0900980 struct smb2_negotiate_req *req)
Namjae Jeone2f34482021-03-16 10:49:09 +0900981{
Namjae Jeone2f34482021-03-16 10:49:09 +0900982 /* +4 is to account for the RFC1001 len field */
Namjae Jeonaf320a72021-07-21 10:03:19 +0900983 struct smb2_neg_context *pctx = (struct smb2_neg_context *)((char *)req + 4);
984 int i = 0, len_of_ctxts;
985 int offset = le32_to_cpu(req->NegotiateContextOffset);
Namjae Jeone2f34482021-03-16 10:49:09 +0900986 int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);
Namjae Jeonaf320a72021-07-21 10:03:19 +0900987 int len_of_smb = be32_to_cpu(req->hdr.smb2_buf_length);
988 __le32 status = STATUS_INVALID_PARAMETER;
Namjae Jeone2f34482021-03-16 10:49:09 +0900989
Namjae Jeonaf320a72021-07-21 10:03:19 +0900990 ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt);
991 if (len_of_smb <= offset) {
992 ksmbd_debug(SMB, "Invalid response: negotiate context offset\n");
993 return status;
994 }
995
996 len_of_ctxts = len_of_smb - offset;
997
Namjae Jeone2f34482021-03-16 10:49:09 +0900998 while (i++ < neg_ctxt_cnt) {
Namjae Jeonaf320a72021-07-21 10:03:19 +0900999 int clen;
1000
1001 /* check that offset is not beyond end of SMB */
1002 if (len_of_ctxts == 0)
1003 break;
1004
1005 if (len_of_ctxts < sizeof(struct smb2_neg_context))
1006 break;
1007
1008 pctx = (struct smb2_neg_context *)((char *)pctx + offset);
1009 clen = le16_to_cpu(pctx->DataLength);
1010 if (clen + sizeof(struct smb2_neg_context) > len_of_ctxts)
1011 break;
1012
1013 if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001014 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09001015 "deassemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001016 if (conn->preauth_info->Preauth_HashId)
1017 break;
1018
1019 status = decode_preauth_ctxt(conn,
Namjae Jeonaf320a72021-07-21 10:03:19 +09001020 (struct smb2_preauth_neg_context *)pctx);
1021 if (status != STATUS_SUCCESS)
1022 break;
1023 } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001024 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09001025 "deassemble SMB2_ENCRYPTION_CAPABILITIES context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001026 if (conn->cipher_type)
1027 break;
1028
Namjae Jeonaf320a72021-07-21 10:03:19 +09001029 decode_encrypt_ctxt(conn,
1030 (struct smb2_encryption_neg_context *)pctx,
1031 len_of_ctxts);
1032 } else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001033 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09001034 "deassemble SMB2_COMPRESSION_CAPABILITIES context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001035 if (conn->compress_algorithm)
1036 break;
1037
Namjae Jeonaf320a72021-07-21 10:03:19 +09001038 decode_compress_ctxt(conn,
1039 (struct smb2_compression_ctx *)pctx);
1040 } else if (pctx->ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001041 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09001042 "deassemble SMB2_NETNAME_NEGOTIATE_CONTEXT_ID context\n");
Namjae Jeonaf320a72021-07-21 10:03:19 +09001043 } else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001044 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09001045 "deassemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001046 conn->posix_ext_supported = true;
Namjae Jeon378087c2021-07-21 10:05:53 +09001047 } else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) {
1048 ksmbd_debug(SMB,
1049 "deassemble SMB2_SIGNING_CAPABILITIES context\n");
1050 decode_sign_cap_ctxt(conn,
1051 (struct smb2_signing_capabilities *)pctx,
1052 len_of_ctxts);
Namjae Jeone2f34482021-03-16 10:49:09 +09001053 }
Namjae Jeone2f34482021-03-16 10:49:09 +09001054
Namjae Jeonaf320a72021-07-21 10:03:19 +09001055 /* offsets must be 8 byte aligned */
1056 clen = (clen + 7) & ~0x7;
1057 offset = clen + sizeof(struct smb2_neg_context);
1058 len_of_ctxts -= clen + sizeof(struct smb2_neg_context);
Namjae Jeone2f34482021-03-16 10:49:09 +09001059 }
1060 return status;
1061}
1062
1063/**
1064 * smb2_handle_negotiate() - handler for smb2 negotiate command
1065 * @work: smb work containing smb request buffer
1066 *
1067 * Return: 0
1068 */
1069int smb2_handle_negotiate(struct ksmbd_work *work)
1070{
1071 struct ksmbd_conn *conn = work->conn;
Namjae Jeone5066492021-03-30 12:35:23 +09001072 struct smb2_negotiate_req *req = work->request_buf;
1073 struct smb2_negotiate_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001074 int rc = 0;
1075 __le32 status;
1076
1077 ksmbd_debug(SMB, "Received negotiate request\n");
1078 conn->need_neg = false;
1079 if (ksmbd_conn_good(work)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09001080 pr_err("conn->tcp_status is already in CifsGood State\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001081 work->send_no_response = 1;
1082 return rc;
1083 }
1084
1085 if (req->DialectCount == 0) {
Namjae Jeonbde16942021-06-28 15:23:19 +09001086 pr_err("malformed packet\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001087 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1088 rc = -EINVAL;
1089 goto err_out;
1090 }
1091
1092 conn->cli_cap = le32_to_cpu(req->Capabilities);
1093 switch (conn->dialect) {
1094 case SMB311_PROT_ID:
1095 conn->preauth_info =
1096 kzalloc(sizeof(struct preauth_integrity_info),
Namjae Jeon070fb212021-05-26 17:57:12 +09001097 GFP_KERNEL);
Namjae Jeone2f34482021-03-16 10:49:09 +09001098 if (!conn->preauth_info) {
1099 rc = -ENOMEM;
1100 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1101 goto err_out;
1102 }
1103
1104 status = deassemble_neg_contexts(conn, req);
1105 if (status != STATUS_SUCCESS) {
Namjae Jeonbde16942021-06-28 15:23:19 +09001106 pr_err("deassemble_neg_contexts error(0x%x)\n",
1107 status);
Namjae Jeone2f34482021-03-16 10:49:09 +09001108 rsp->hdr.Status = status;
1109 rc = -EINVAL;
1110 goto err_out;
1111 }
1112
1113 rc = init_smb3_11_server(conn);
1114 if (rc < 0) {
1115 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1116 goto err_out;
1117 }
1118
1119 ksmbd_gen_preauth_integrity_hash(conn,
Namjae Jeon070fb212021-05-26 17:57:12 +09001120 work->request_buf,
1121 conn->preauth_info->Preauth_HashValue);
Namjae Jeone2f34482021-03-16 10:49:09 +09001122 rsp->NegotiateContextOffset =
1123 cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
1124 assemble_neg_contexts(conn, rsp);
1125 break;
1126 case SMB302_PROT_ID:
1127 init_smb3_02_server(conn);
1128 break;
1129 case SMB30_PROT_ID:
1130 init_smb3_0_server(conn);
1131 break;
1132 case SMB21_PROT_ID:
1133 init_smb2_1_server(conn);
1134 break;
1135 case SMB20_PROT_ID:
1136 rc = init_smb2_0_server(conn);
1137 if (rc) {
1138 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
1139 goto err_out;
1140 }
1141 break;
1142 case SMB2X_PROT_ID:
1143 case BAD_PROT_ID:
1144 default:
1145 ksmbd_debug(SMB, "Server dialect :0x%x not supported\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09001146 conn->dialect);
Namjae Jeone2f34482021-03-16 10:49:09 +09001147 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
1148 rc = -EINVAL;
1149 goto err_out;
1150 }
1151 rsp->Capabilities = cpu_to_le32(conn->vals->capabilities);
1152
1153 /* For stats */
1154 conn->connection_type = conn->dialect;
1155
1156 rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size);
1157 rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size);
1158 rsp->MaxWriteSize = cpu_to_le32(conn->vals->max_write_size);
1159
1160 if (conn->dialect > SMB20_PROT_ID) {
1161 memcpy(conn->ClientGUID, req->ClientGUID,
Namjae Jeon070fb212021-05-26 17:57:12 +09001162 SMB2_CLIENT_GUID_SIZE);
Namjae Jeone2f34482021-03-16 10:49:09 +09001163 conn->cli_sec_mode = le16_to_cpu(req->SecurityMode);
1164 }
1165
1166 rsp->StructureSize = cpu_to_le16(65);
1167 rsp->DialectRevision = cpu_to_le16(conn->dialect);
1168 /* Not setting conn guid rsp->ServerGUID, as it
1169 * not used by client for identifying server
1170 */
1171 memset(rsp->ServerGUID, 0, SMB2_CLIENT_GUID_SIZE);
1172
1173 rsp->SystemTime = cpu_to_le64(ksmbd_systime());
1174 rsp->ServerStartTime = 0;
1175 ksmbd_debug(SMB, "negotiate context offset %d, count %d\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09001176 le32_to_cpu(rsp->NegotiateContextOffset),
1177 le16_to_cpu(rsp->NegotiateContextCount));
Namjae Jeone2f34482021-03-16 10:49:09 +09001178
1179 rsp->SecurityBufferOffset = cpu_to_le16(128);
1180 rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH);
1181 ksmbd_copy_gss_neg_header(((char *)(&rsp->hdr) +
Namjae Jeon070fb212021-05-26 17:57:12 +09001182 sizeof(rsp->hdr.smb2_buf_length)) +
1183 le16_to_cpu(rsp->SecurityBufferOffset));
Namjae Jeone2f34482021-03-16 10:49:09 +09001184 inc_rfc1001_len(rsp, sizeof(struct smb2_negotiate_rsp) -
Namjae Jeon070fb212021-05-26 17:57:12 +09001185 sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) +
1186 AUTH_GSS_LENGTH);
Namjae Jeone2f34482021-03-16 10:49:09 +09001187 rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE;
1188 conn->use_spnego = true;
1189
1190 if ((server_conf.signing == KSMBD_CONFIG_OPT_AUTO ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09001191 server_conf.signing == KSMBD_CONFIG_OPT_DISABLED) &&
1192 req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED_LE)
Namjae Jeone2f34482021-03-16 10:49:09 +09001193 conn->sign = true;
1194 else if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) {
1195 server_conf.enforced_signing = true;
1196 rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;
1197 conn->sign = true;
1198 }
1199
1200 conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode);
1201 ksmbd_conn_set_need_negotiate(work);
1202
1203err_out:
1204 if (rc < 0)
1205 smb2_set_err_rsp(work);
1206
1207 return rc;
1208}
1209
1210static int alloc_preauth_hash(struct ksmbd_session *sess,
Namjae Jeon070fb212021-05-26 17:57:12 +09001211 struct ksmbd_conn *conn)
Namjae Jeone2f34482021-03-16 10:49:09 +09001212{
1213 if (sess->Preauth_HashValue)
1214 return 0;
1215
kernel test robot86f52972021-04-02 12:17:24 +09001216 sess->Preauth_HashValue = kmemdup(conn->preauth_info->Preauth_HashValue,
Namjae Jeon070fb212021-05-26 17:57:12 +09001217 PREAUTH_HASHVALUE_SIZE, GFP_KERNEL);
Namjae Jeone2f34482021-03-16 10:49:09 +09001218 if (!sess->Preauth_HashValue)
1219 return -ENOMEM;
1220
Namjae Jeone2f34482021-03-16 10:49:09 +09001221 return 0;
1222}
1223
1224static int generate_preauth_hash(struct ksmbd_work *work)
1225{
1226 struct ksmbd_conn *conn = work->conn;
1227 struct ksmbd_session *sess = work->sess;
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001228 u8 *preauth_hash;
Namjae Jeone2f34482021-03-16 10:49:09 +09001229
1230 if (conn->dialect != SMB311_PROT_ID)
1231 return 0;
1232
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001233 if (conn->binding) {
1234 struct preauth_session *preauth_sess;
1235
1236 preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
1237 if (!preauth_sess) {
1238 preauth_sess = ksmbd_preauth_session_alloc(conn, sess->id);
1239 if (!preauth_sess)
1240 return -ENOMEM;
1241 }
1242
1243 preauth_hash = preauth_sess->Preauth_HashValue;
1244 } else {
1245 if (!sess->Preauth_HashValue)
1246 if (alloc_preauth_hash(sess, conn))
1247 return -ENOMEM;
1248 preauth_hash = sess->Preauth_HashValue;
Namjae Jeone2f34482021-03-16 10:49:09 +09001249 }
1250
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001251 ksmbd_gen_preauth_integrity_hash(conn, work->request_buf, preauth_hash);
Namjae Jeone2f34482021-03-16 10:49:09 +09001252 return 0;
1253}
1254
1255static int decode_negotiation_token(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09001256 struct negotiate_message *negblob)
Namjae Jeone2f34482021-03-16 10:49:09 +09001257{
1258 struct ksmbd_conn *conn = work->conn;
1259 struct smb2_sess_setup_req *req;
1260 int sz;
1261
1262 if (!conn->use_spnego)
1263 return -EINVAL;
1264
Namjae Jeone5066492021-03-30 12:35:23 +09001265 req = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001266 sz = le16_to_cpu(req->SecurityBufferLength);
1267
Hyunchul Leefad41612021-04-19 17:26:15 +09001268 if (ksmbd_decode_negTokenInit((char *)negblob, sz, conn)) {
1269 if (ksmbd_decode_negTokenTarg((char *)negblob, sz, conn)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001270 conn->auth_mechs |= KSMBD_AUTH_NTLMSSP;
1271 conn->preferred_auth_mech = KSMBD_AUTH_NTLMSSP;
1272 conn->use_spnego = false;
1273 }
1274 }
1275 return 0;
1276}
1277
1278static int ntlm_negotiate(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09001279 struct negotiate_message *negblob)
Namjae Jeone2f34482021-03-16 10:49:09 +09001280{
Namjae Jeone5066492021-03-30 12:35:23 +09001281 struct smb2_sess_setup_req *req = work->request_buf;
1282 struct smb2_sess_setup_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001283 struct challenge_message *chgblob;
1284 unsigned char *spnego_blob = NULL;
1285 u16 spnego_blob_len;
1286 char *neg_blob;
1287 int sz, rc;
1288
1289 ksmbd_debug(SMB, "negotiate phase\n");
1290 sz = le16_to_cpu(req->SecurityBufferLength);
1291 rc = ksmbd_decode_ntlmssp_neg_blob(negblob, sz, work->sess);
1292 if (rc)
1293 return rc;
1294
1295 sz = le16_to_cpu(rsp->SecurityBufferOffset);
1296 chgblob =
1297 (struct challenge_message *)((char *)&rsp->hdr.ProtocolId + sz);
1298 memset(chgblob, 0, sizeof(struct challenge_message));
1299
1300 if (!work->conn->use_spnego) {
1301 sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->sess);
1302 if (sz < 0)
1303 return -ENOMEM;
1304
1305 rsp->SecurityBufferLength = cpu_to_le16(sz);
1306 return 0;
1307 }
1308
1309 sz = sizeof(struct challenge_message);
1310 sz += (strlen(ksmbd_netbios_name()) * 2 + 1 + 4) * 6;
1311
1312 neg_blob = kzalloc(sz, GFP_KERNEL);
1313 if (!neg_blob)
1314 return -ENOMEM;
1315
1316 chgblob = (struct challenge_message *)neg_blob;
1317 sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->sess);
1318 if (sz < 0) {
1319 rc = -ENOMEM;
1320 goto out;
1321 }
1322
Namjae Jeon070fb212021-05-26 17:57:12 +09001323 rc = build_spnego_ntlmssp_neg_blob(&spnego_blob, &spnego_blob_len,
1324 neg_blob, sz);
Namjae Jeone2f34482021-03-16 10:49:09 +09001325 if (rc) {
1326 rc = -ENOMEM;
1327 goto out;
1328 }
1329
1330 sz = le16_to_cpu(rsp->SecurityBufferOffset);
1331 memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
1332 rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
1333
1334out:
1335 kfree(spnego_blob);
1336 kfree(neg_blob);
1337 return rc;
1338}
1339
1340static struct authenticate_message *user_authblob(struct ksmbd_conn *conn,
Namjae Jeon070fb212021-05-26 17:57:12 +09001341 struct smb2_sess_setup_req *req)
Namjae Jeone2f34482021-03-16 10:49:09 +09001342{
1343 int sz;
1344
1345 if (conn->use_spnego && conn->mechToken)
1346 return (struct authenticate_message *)conn->mechToken;
1347
1348 sz = le16_to_cpu(req->SecurityBufferOffset);
1349 return (struct authenticate_message *)((char *)&req->hdr.ProtocolId
1350 + sz);
1351}
1352
1353static struct ksmbd_user *session_user(struct ksmbd_conn *conn,
Namjae Jeon070fb212021-05-26 17:57:12 +09001354 struct smb2_sess_setup_req *req)
Namjae Jeone2f34482021-03-16 10:49:09 +09001355{
1356 struct authenticate_message *authblob;
1357 struct ksmbd_user *user;
1358 char *name;
1359 int sz;
1360
1361 authblob = user_authblob(conn, req);
1362 sz = le32_to_cpu(authblob->UserName.BufferOffset);
1363 name = smb_strndup_from_utf16((const char *)authblob + sz,
1364 le16_to_cpu(authblob->UserName.Length),
1365 true,
1366 conn->local_nls);
1367 if (IS_ERR(name)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09001368 pr_err("cannot allocate memory\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001369 return NULL;
1370 }
1371
1372 ksmbd_debug(SMB, "session setup request for user %s\n", name);
1373 user = ksmbd_login_user(name);
1374 kfree(name);
1375 return user;
1376}
1377
1378static int ntlm_authenticate(struct ksmbd_work *work)
1379{
Namjae Jeone5066492021-03-30 12:35:23 +09001380 struct smb2_sess_setup_req *req = work->request_buf;
1381 struct smb2_sess_setup_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001382 struct ksmbd_conn *conn = work->conn;
1383 struct ksmbd_session *sess = work->sess;
1384 struct channel *chann = NULL;
1385 struct ksmbd_user *user;
Namjae Jeon64b39f42021-03-30 14:25:35 +09001386 u64 prev_id;
Namjae Jeone2f34482021-03-16 10:49:09 +09001387 int sz, rc;
1388
1389 ksmbd_debug(SMB, "authenticate phase\n");
1390 if (conn->use_spnego) {
1391 unsigned char *spnego_blob;
1392 u16 spnego_blob_len;
1393
1394 rc = build_spnego_ntlmssp_auth_blob(&spnego_blob,
1395 &spnego_blob_len,
1396 0);
1397 if (rc)
1398 return -ENOMEM;
1399
1400 sz = le16_to_cpu(rsp->SecurityBufferOffset);
Namjae Jeon64b39f42021-03-30 14:25:35 +09001401 memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
Namjae Jeone2f34482021-03-16 10:49:09 +09001402 rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
1403 kfree(spnego_blob);
1404 inc_rfc1001_len(rsp, spnego_blob_len - 1);
1405 }
1406
1407 user = session_user(conn, req);
1408 if (!user) {
1409 ksmbd_debug(SMB, "Unknown user name or an error\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001410 return -EPERM;
Namjae Jeone2f34482021-03-16 10:49:09 +09001411 }
1412
1413 /* Check for previous session */
1414 prev_id = le64_to_cpu(req->PreviousSessionId);
1415 if (prev_id && prev_id != sess->id)
1416 destroy_previous_session(user, prev_id);
1417
1418 if (sess->state == SMB2_SESSION_VALID) {
1419 /*
1420 * Reuse session if anonymous try to connect
1421 * on reauthetication.
1422 */
1423 if (ksmbd_anonymous_user(user)) {
1424 ksmbd_free_user(user);
1425 return 0;
1426 }
1427 ksmbd_free_user(sess->user);
1428 }
1429
1430 sess->user = user;
1431 if (user_guest(sess->user)) {
1432 if (conn->sign) {
Namjae Jeon64b39f42021-03-30 14:25:35 +09001433 ksmbd_debug(SMB, "Guest login not allowed when signing enabled\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001434 return -EPERM;
Namjae Jeone2f34482021-03-16 10:49:09 +09001435 }
1436
1437 rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE;
1438 } else {
1439 struct authenticate_message *authblob;
1440
1441 authblob = user_authblob(conn, req);
1442 sz = le16_to_cpu(req->SecurityBufferLength);
1443 rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, sess);
1444 if (rc) {
1445 set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD);
1446 ksmbd_debug(SMB, "authentication failed\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001447 return -EPERM;
Namjae Jeone2f34482021-03-16 10:49:09 +09001448 }
1449
1450 /*
1451 * If session state is SMB2_SESSION_VALID, We can assume
1452 * that it is reauthentication. And the user/password
1453 * has been verified, so return it here.
1454 */
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001455 if (sess->state == SMB2_SESSION_VALID) {
1456 if (conn->binding)
1457 goto binding_session;
Namjae Jeone2f34482021-03-16 10:49:09 +09001458 return 0;
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001459 }
Namjae Jeone2f34482021-03-16 10:49:09 +09001460
1461 if ((conn->sign || server_conf.enforced_signing) ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09001462 (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
Namjae Jeone2f34482021-03-16 10:49:09 +09001463 sess->sign = true;
1464
1465 if (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION &&
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001466 conn->ops->generate_encryptionkey &&
1467 !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001468 rc = conn->ops->generate_encryptionkey(sess);
1469 if (rc) {
1470 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09001471 "SMB3 encryption key generation failed\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001472 return -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001473 }
1474 sess->enc = true;
1475 rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE;
1476 /*
1477 * signing is disable if encryption is enable
1478 * on this session
1479 */
1480 sess->sign = false;
1481 }
1482 }
1483
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001484binding_session:
Namjae Jeone2f34482021-03-16 10:49:09 +09001485 if (conn->dialect >= SMB30_PROT_ID) {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001486 chann = lookup_chann_list(sess, conn);
Namjae Jeone2f34482021-03-16 10:49:09 +09001487 if (!chann) {
1488 chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
1489 if (!chann)
1490 return -ENOMEM;
1491
1492 chann->conn = conn;
1493 INIT_LIST_HEAD(&chann->chann_list);
1494 list_add(&chann->chann_list, &sess->ksmbd_chann_list);
1495 }
1496 }
1497
1498 if (conn->ops->generate_signingkey) {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001499 rc = conn->ops->generate_signingkey(sess, conn);
Namjae Jeone2f34482021-03-16 10:49:09 +09001500 if (rc) {
Namjae Jeon64b39f42021-03-30 14:25:35 +09001501 ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001502 return -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001503 }
1504 }
1505
1506 if (conn->dialect > SMB20_PROT_ID) {
1507 if (!ksmbd_conn_lookup_dialect(conn)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09001508 pr_err("fail to verify the dialect\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001509 return -ENOENT;
Namjae Jeone2f34482021-03-16 10:49:09 +09001510 }
1511 }
1512 return 0;
1513}
1514
1515#ifdef CONFIG_SMB_SERVER_KERBEROS5
1516static int krb5_authenticate(struct ksmbd_work *work)
1517{
Namjae Jeone5066492021-03-30 12:35:23 +09001518 struct smb2_sess_setup_req *req = work->request_buf;
1519 struct smb2_sess_setup_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001520 struct ksmbd_conn *conn = work->conn;
1521 struct ksmbd_session *sess = work->sess;
1522 char *in_blob, *out_blob;
1523 struct channel *chann = NULL;
Namjae Jeon64b39f42021-03-30 14:25:35 +09001524 u64 prev_sess_id;
Namjae Jeone2f34482021-03-16 10:49:09 +09001525 int in_len, out_len;
1526 int retval;
1527
1528 in_blob = (char *)&req->hdr.ProtocolId +
1529 le16_to_cpu(req->SecurityBufferOffset);
1530 in_len = le16_to_cpu(req->SecurityBufferLength);
1531 out_blob = (char *)&rsp->hdr.ProtocolId +
1532 le16_to_cpu(rsp->SecurityBufferOffset);
1533 out_len = work->response_sz -
1534 offsetof(struct smb2_hdr, smb2_buf_length) -
1535 le16_to_cpu(rsp->SecurityBufferOffset);
1536
1537 /* Check previous session */
1538 prev_sess_id = le64_to_cpu(req->PreviousSessionId);
1539 if (prev_sess_id && prev_sess_id != sess->id)
1540 destroy_previous_session(sess->user, prev_sess_id);
1541
1542 if (sess->state == SMB2_SESSION_VALID)
1543 ksmbd_free_user(sess->user);
1544
1545 retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
Namjae Jeon070fb212021-05-26 17:57:12 +09001546 out_blob, &out_len);
Namjae Jeone2f34482021-03-16 10:49:09 +09001547 if (retval) {
1548 ksmbd_debug(SMB, "krb5 authentication failed\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001549 return -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001550 }
1551 rsp->SecurityBufferLength = cpu_to_le16(out_len);
1552 inc_rfc1001_len(rsp, out_len - 1);
1553
1554 if ((conn->sign || server_conf.enforced_signing) ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09001555 (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
Namjae Jeone2f34482021-03-16 10:49:09 +09001556 sess->sign = true;
1557
1558 if ((conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09001559 conn->ops->generate_encryptionkey) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001560 retval = conn->ops->generate_encryptionkey(sess);
1561 if (retval) {
1562 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09001563 "SMB3 encryption key generation failed\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001564 return -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001565 }
1566 sess->enc = true;
1567 rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE;
1568 sess->sign = false;
1569 }
1570
1571 if (conn->dialect >= SMB30_PROT_ID) {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001572 chann = lookup_chann_list(sess, conn);
Namjae Jeone2f34482021-03-16 10:49:09 +09001573 if (!chann) {
1574 chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
1575 if (!chann)
1576 return -ENOMEM;
1577
1578 chann->conn = conn;
1579 INIT_LIST_HEAD(&chann->chann_list);
1580 list_add(&chann->chann_list, &sess->ksmbd_chann_list);
1581 }
1582 }
1583
1584 if (conn->ops->generate_signingkey) {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001585 retval = conn->ops->generate_signingkey(sess, conn);
Namjae Jeone2f34482021-03-16 10:49:09 +09001586 if (retval) {
Namjae Jeon64b39f42021-03-30 14:25:35 +09001587 ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001588 return -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001589 }
1590 }
1591
1592 if (conn->dialect > SMB20_PROT_ID) {
1593 if (!ksmbd_conn_lookup_dialect(conn)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09001594 pr_err("fail to verify the dialect\n");
Namjae Jeon58090b12021-07-16 14:52:09 +09001595 return -ENOENT;
Namjae Jeone2f34482021-03-16 10:49:09 +09001596 }
1597 }
1598 return 0;
1599}
1600#else
1601static int krb5_authenticate(struct ksmbd_work *work)
1602{
1603 return -EOPNOTSUPP;
1604}
1605#endif
1606
1607int smb2_sess_setup(struct ksmbd_work *work)
1608{
1609 struct ksmbd_conn *conn = work->conn;
Namjae Jeone5066492021-03-30 12:35:23 +09001610 struct smb2_sess_setup_req *req = work->request_buf;
1611 struct smb2_sess_setup_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001612 struct ksmbd_session *sess;
1613 struct negotiate_message *negblob;
1614 int rc = 0;
1615
1616 ksmbd_debug(SMB, "Received request for session setup\n");
1617
1618 rsp->StructureSize = cpu_to_le16(9);
1619 rsp->SessionFlags = 0;
1620 rsp->SecurityBufferOffset = cpu_to_le16(72);
1621 rsp->SecurityBufferLength = 0;
1622 inc_rfc1001_len(rsp, 9);
1623
1624 if (!req->hdr.SessionId) {
1625 sess = ksmbd_smb2_session_create();
1626 if (!sess) {
1627 rc = -ENOMEM;
1628 goto out_err;
1629 }
1630 rsp->hdr.SessionId = cpu_to_le64(sess->id);
1631 ksmbd_session_register(conn, sess);
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001632 } else if (conn->dialect >= SMB30_PROT_ID &&
1633 (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
1634 req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) {
1635 u64 sess_id = le64_to_cpu(req->hdr.SessionId);
1636
1637 sess = ksmbd_session_lookup_slowpath(sess_id);
1638 if (!sess) {
1639 rc = -ENOENT;
1640 goto out_err;
1641 }
1642
1643 if (conn->dialect != sess->conn->dialect) {
1644 rc = -EINVAL;
1645 goto out_err;
1646 }
1647
1648 if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
1649 rc = -EINVAL;
1650 goto out_err;
1651 }
1652
1653 if (strncmp(conn->ClientGUID, sess->conn->ClientGUID,
1654 SMB2_CLIENT_GUID_SIZE)) {
1655 rc = -ENOENT;
1656 goto out_err;
1657 }
1658
1659 if (sess->state == SMB2_SESSION_IN_PROGRESS) {
1660 rc = -EACCES;
1661 goto out_err;
1662 }
1663
1664 if (sess->state == SMB2_SESSION_EXPIRED) {
1665 rc = -EFAULT;
1666 goto out_err;
1667 }
1668
1669 if (ksmbd_session_lookup(conn, sess_id)) {
1670 rc = -EACCES;
1671 goto out_err;
1672 }
1673
1674 conn->binding = true;
1675 } else if ((conn->dialect < SMB30_PROT_ID ||
1676 server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
1677 (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
Colin Ian King4951a842021-07-06 13:05:01 +01001678 sess = NULL;
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001679 rc = -EACCES;
1680 goto out_err;
Namjae Jeone2f34482021-03-16 10:49:09 +09001681 } else {
1682 sess = ksmbd_session_lookup(conn,
Namjae Jeon070fb212021-05-26 17:57:12 +09001683 le64_to_cpu(req->hdr.SessionId));
Namjae Jeone2f34482021-03-16 10:49:09 +09001684 if (!sess) {
1685 rc = -ENOENT;
Namjae Jeone2f34482021-03-16 10:49:09 +09001686 goto out_err;
1687 }
1688 }
1689 work->sess = sess;
1690
1691 if (sess->state == SMB2_SESSION_EXPIRED)
1692 sess->state = SMB2_SESSION_IN_PROGRESS;
1693
1694 negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +
1695 le16_to_cpu(req->SecurityBufferOffset));
1696
1697 if (decode_negotiation_token(work, negblob) == 0) {
1698 if (conn->mechToken)
1699 negblob = (struct negotiate_message *)conn->mechToken;
1700 }
1701
1702 if (server_conf.auth_mechs & conn->auth_mechs) {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001703 rc = generate_preauth_hash(work);
1704 if (rc)
1705 goto out_err;
1706
Namjae Jeone2f34482021-03-16 10:49:09 +09001707 if (conn->preferred_auth_mech &
1708 (KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001709 rc = krb5_authenticate(work);
1710 if (rc) {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001711 rc = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001712 goto out_err;
1713 }
1714
1715 ksmbd_conn_set_good(work);
1716 sess->state = SMB2_SESSION_VALID;
Muhammad Usama Anjum822bc8e2021-04-02 09:25:35 +09001717 kfree(sess->Preauth_HashValue);
Namjae Jeone2f34482021-03-16 10:49:09 +09001718 sess->Preauth_HashValue = NULL;
1719 } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001720 if (negblob->MessageType == NtLmNegotiate) {
1721 rc = ntlm_negotiate(work, negblob);
1722 if (rc)
1723 goto out_err;
1724 rsp->hdr.Status =
1725 STATUS_MORE_PROCESSING_REQUIRED;
1726 /*
1727 * Note: here total size -1 is done as an
1728 * adjustment for 0 size blob
1729 */
Namjae Jeon64b39f42021-03-30 14:25:35 +09001730 inc_rfc1001_len(rsp, le16_to_cpu(rsp->SecurityBufferLength) - 1);
Namjae Jeone2f34482021-03-16 10:49:09 +09001731
1732 } else if (negblob->MessageType == NtLmAuthenticate) {
1733 rc = ntlm_authenticate(work);
1734 if (rc)
1735 goto out_err;
1736
1737 ksmbd_conn_set_good(work);
1738 sess->state = SMB2_SESSION_VALID;
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001739 if (conn->binding) {
1740 struct preauth_session *preauth_sess;
1741
1742 preauth_sess =
1743 ksmbd_preauth_session_lookup(conn, sess->id);
1744 if (preauth_sess) {
1745 list_del(&preauth_sess->preauth_entry);
1746 kfree(preauth_sess);
1747 }
1748 }
Muhammad Usama Anjum822bc8e2021-04-02 09:25:35 +09001749 kfree(sess->Preauth_HashValue);
Namjae Jeone2f34482021-03-16 10:49:09 +09001750 sess->Preauth_HashValue = NULL;
1751 }
1752 } else {
1753 /* TODO: need one more negotiation */
Namjae Jeonbde16942021-06-28 15:23:19 +09001754 pr_err("Not support the preferred authentication\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001755 rc = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001756 }
1757 } else {
Namjae Jeonbde16942021-06-28 15:23:19 +09001758 pr_err("Not support authentication\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001759 rc = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09001760 }
1761
1762out_err:
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001763 if (rc == -EINVAL)
1764 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1765 else if (rc == -ENOENT)
1766 rsp->hdr.Status = STATUS_USER_SESSION_DELETED;
1767 else if (rc == -EACCES)
1768 rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
1769 else if (rc == -EFAULT)
1770 rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED;
Namjae Jeon58090b12021-07-16 14:52:09 +09001771 else if (rc == -ENOMEM)
1772 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
Namjae Jeonf5a544e2021-06-18 10:04:19 +09001773 else if (rc)
1774 rsp->hdr.Status = STATUS_LOGON_FAILURE;
1775
Namjae Jeone2f34482021-03-16 10:49:09 +09001776 if (conn->use_spnego && conn->mechToken) {
1777 kfree(conn->mechToken);
1778 conn->mechToken = NULL;
1779 }
1780
1781 if (rc < 0 && sess) {
1782 ksmbd_session_destroy(sess);
1783 work->sess = NULL;
1784 }
1785
1786 return rc;
1787}
1788
1789/**
1790 * smb2_tree_connect() - handler for smb2 tree connect command
1791 * @work: smb work containing smb request buffer
1792 *
1793 * Return: 0 on success, otherwise error
1794 */
1795int smb2_tree_connect(struct ksmbd_work *work)
1796{
1797 struct ksmbd_conn *conn = work->conn;
Namjae Jeone5066492021-03-30 12:35:23 +09001798 struct smb2_tree_connect_req *req = work->request_buf;
1799 struct smb2_tree_connect_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001800 struct ksmbd_session *sess = work->sess;
1801 char *treename = NULL, *name = NULL;
1802 struct ksmbd_tree_conn_status status;
1803 struct ksmbd_share_config *share;
1804 int rc = -EINVAL;
1805
1806 treename = smb_strndup_from_utf16(req->Buffer,
Namjae Jeon070fb212021-05-26 17:57:12 +09001807 le16_to_cpu(req->PathLength), true,
1808 conn->local_nls);
Namjae Jeone2f34482021-03-16 10:49:09 +09001809 if (IS_ERR(treename)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09001810 pr_err("treename is NULL\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09001811 status.ret = KSMBD_TREE_CONN_STATUS_ERROR;
1812 goto out_err1;
1813 }
1814
Stephen Rothwell36ba3862021-03-17 17:01:15 +09001815 name = ksmbd_extract_sharename(treename);
Namjae Jeone2f34482021-03-16 10:49:09 +09001816 if (IS_ERR(name)) {
1817 status.ret = KSMBD_TREE_CONN_STATUS_ERROR;
1818 goto out_err1;
1819 }
1820
1821 ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09001822 name, treename);
Namjae Jeone2f34482021-03-16 10:49:09 +09001823
1824 status = ksmbd_tree_conn_connect(sess, name);
1825 if (status.ret == KSMBD_TREE_CONN_STATUS_OK)
1826 rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id);
1827 else
1828 goto out_err1;
1829
1830 share = status.tree_conn->share_conf;
1831 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
1832 ksmbd_debug(SMB, "IPC share path request\n");
1833 rsp->ShareType = SMB2_SHARE_TYPE_PIPE;
1834 rsp->MaximalAccess = FILE_READ_DATA_LE | FILE_READ_EA_LE |
1835 FILE_EXECUTE_LE | FILE_READ_ATTRIBUTES_LE |
1836 FILE_DELETE_LE | FILE_READ_CONTROL_LE |
1837 FILE_WRITE_DAC_LE | FILE_WRITE_OWNER_LE |
1838 FILE_SYNCHRONIZE_LE;
1839 } else {
1840 rsp->ShareType = SMB2_SHARE_TYPE_DISK;
1841 rsp->MaximalAccess = FILE_READ_DATA_LE | FILE_READ_EA_LE |
1842 FILE_EXECUTE_LE | FILE_READ_ATTRIBUTES_LE;
1843 if (test_tree_conn_flag(status.tree_conn,
1844 KSMBD_TREE_CONN_FLAG_WRITABLE)) {
1845 rsp->MaximalAccess |= FILE_WRITE_DATA_LE |
1846 FILE_APPEND_DATA_LE | FILE_WRITE_EA_LE |
Wan Jiabing3aefd542021-06-07 12:54:32 +08001847 FILE_DELETE_LE | FILE_WRITE_ATTRIBUTES_LE |
1848 FILE_DELETE_CHILD_LE | FILE_READ_CONTROL_LE |
1849 FILE_WRITE_DAC_LE | FILE_WRITE_OWNER_LE |
1850 FILE_SYNCHRONIZE_LE;
Namjae Jeone2f34482021-03-16 10:49:09 +09001851 }
1852 }
1853
1854 status.tree_conn->maximal_access = le32_to_cpu(rsp->MaximalAccess);
1855 if (conn->posix_ext_supported)
1856 status.tree_conn->posix_extensions = true;
1857
1858out_err1:
1859 rsp->StructureSize = cpu_to_le16(16);
1860 rsp->Capabilities = 0;
1861 rsp->Reserved = 0;
1862 /* default manual caching */
1863 rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING;
1864 inc_rfc1001_len(rsp, 16);
1865
1866 if (!IS_ERR(treename))
1867 kfree(treename);
1868 if (!IS_ERR(name))
1869 kfree(name);
1870
1871 switch (status.ret) {
1872 case KSMBD_TREE_CONN_STATUS_OK:
1873 rsp->hdr.Status = STATUS_SUCCESS;
1874 rc = 0;
1875 break;
1876 case KSMBD_TREE_CONN_STATUS_NO_SHARE:
1877 rsp->hdr.Status = STATUS_BAD_NETWORK_PATH;
1878 break;
1879 case -ENOMEM:
1880 case KSMBD_TREE_CONN_STATUS_NOMEM:
1881 rsp->hdr.Status = STATUS_NO_MEMORY;
1882 break;
1883 case KSMBD_TREE_CONN_STATUS_ERROR:
1884 case KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS:
1885 case KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS:
1886 rsp->hdr.Status = STATUS_ACCESS_DENIED;
1887 break;
1888 case -EINVAL:
1889 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1890 break;
1891 default:
1892 rsp->hdr.Status = STATUS_ACCESS_DENIED;
1893 }
1894
1895 return rc;
1896}
1897
1898/**
1899 * smb2_create_open_flags() - convert smb open flags to unix open flags
1900 * @file_present: is file already present
1901 * @access: file access flags
1902 * @disposition: file disposition flags
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09001903 * @may_flags: set with MAY_ flags
Namjae Jeone2f34482021-03-16 10:49:09 +09001904 *
1905 * Return: file open flags
1906 */
1907static int smb2_create_open_flags(bool file_present, __le32 access,
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09001908 __le32 disposition,
1909 int *may_flags)
Namjae Jeone2f34482021-03-16 10:49:09 +09001910{
1911 int oflags = O_NONBLOCK | O_LARGEFILE;
1912
1913 if (access & FILE_READ_DESIRED_ACCESS_LE &&
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09001914 access & FILE_WRITE_DESIRE_ACCESS_LE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001915 oflags |= O_RDWR;
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09001916 *may_flags = MAY_OPEN | MAY_READ | MAY_WRITE;
1917 } else if (access & FILE_WRITE_DESIRE_ACCESS_LE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09001918 oflags |= O_WRONLY;
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09001919 *may_flags = MAY_OPEN | MAY_WRITE;
1920 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09001921 oflags |= O_RDONLY;
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09001922 *may_flags = MAY_OPEN | MAY_READ;
1923 }
Namjae Jeone2f34482021-03-16 10:49:09 +09001924
1925 if (access == FILE_READ_ATTRIBUTES_LE)
1926 oflags |= O_PATH;
1927
1928 if (file_present) {
1929 switch (disposition & FILE_CREATE_MASK_LE) {
1930 case FILE_OPEN_LE:
1931 case FILE_CREATE_LE:
1932 break;
1933 case FILE_SUPERSEDE_LE:
1934 case FILE_OVERWRITE_LE:
1935 case FILE_OVERWRITE_IF_LE:
1936 oflags |= O_TRUNC;
1937 break;
1938 default:
1939 break;
1940 }
1941 } else {
1942 switch (disposition & FILE_CREATE_MASK_LE) {
1943 case FILE_SUPERSEDE_LE:
1944 case FILE_CREATE_LE:
1945 case FILE_OPEN_IF_LE:
1946 case FILE_OVERWRITE_IF_LE:
1947 oflags |= O_CREAT;
1948 break;
1949 case FILE_OPEN_LE:
1950 case FILE_OVERWRITE_LE:
1951 oflags &= ~O_CREAT;
1952 break;
1953 default:
1954 break;
1955 }
1956 }
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09001957
Namjae Jeone2f34482021-03-16 10:49:09 +09001958 return oflags;
1959}
1960
1961/**
1962 * smb2_tree_disconnect() - handler for smb tree connect request
1963 * @work: smb work containing request buffer
1964 *
1965 * Return: 0
1966 */
1967int smb2_tree_disconnect(struct ksmbd_work *work)
1968{
Namjae Jeone5066492021-03-30 12:35:23 +09001969 struct smb2_tree_disconnect_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001970 struct ksmbd_session *sess = work->sess;
1971 struct ksmbd_tree_connect *tcon = work->tcon;
1972
1973 rsp->StructureSize = cpu_to_le16(4);
1974 inc_rfc1001_len(rsp, 4);
1975
1976 ksmbd_debug(SMB, "request\n");
1977
1978 if (!tcon) {
Namjae Jeone5066492021-03-30 12:35:23 +09001979 struct smb2_tree_disconnect_req *req = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09001980
1981 ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
1982 rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
1983 smb2_set_err_rsp(work);
1984 return 0;
1985 }
1986
1987 ksmbd_close_tree_conn_fds(work);
1988 ksmbd_tree_conn_disconnect(sess, tcon);
1989 return 0;
1990}
1991
1992/**
1993 * smb2_session_logoff() - handler for session log off request
1994 * @work: smb work containing request buffer
1995 *
1996 * Return: 0
1997 */
1998int smb2_session_logoff(struct ksmbd_work *work)
1999{
2000 struct ksmbd_conn *conn = work->conn;
Namjae Jeone5066492021-03-30 12:35:23 +09002001 struct smb2_logoff_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09002002 struct ksmbd_session *sess = work->sess;
2003
2004 rsp->StructureSize = cpu_to_le16(4);
2005 inc_rfc1001_len(rsp, 4);
2006
2007 ksmbd_debug(SMB, "request\n");
2008
2009 /* Got a valid session, set connection state */
2010 WARN_ON(sess->conn != conn);
2011
2012 /* setting CifsExiting here may race with start_tcp_sess */
2013 ksmbd_conn_set_need_reconnect(work);
2014 ksmbd_close_session_fds(work);
2015 ksmbd_conn_wait_idle(conn);
2016
2017 if (ksmbd_tree_conn_session_logoff(sess)) {
Namjae Jeone5066492021-03-30 12:35:23 +09002018 struct smb2_logoff_req *req = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09002019
2020 ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
2021 rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
2022 smb2_set_err_rsp(work);
2023 return 0;
2024 }
2025
2026 ksmbd_destroy_file_table(&sess->file_table);
2027 sess->state = SMB2_SESSION_EXPIRED;
2028
2029 ksmbd_free_user(sess->user);
2030 sess->user = NULL;
2031
2032 /* let start_tcp_sess free connection info now */
2033 ksmbd_conn_set_need_negotiate(work);
2034 return 0;
2035}
2036
2037/**
2038 * create_smb2_pipe() - create IPC pipe
2039 * @work: smb work containing request buffer
2040 *
2041 * Return: 0 on success, otherwise error
2042 */
2043static noinline int create_smb2_pipe(struct ksmbd_work *work)
2044{
Namjae Jeone5066492021-03-30 12:35:23 +09002045 struct smb2_create_rsp *rsp = work->response_buf;
2046 struct smb2_create_req *req = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09002047 int id;
2048 int err;
2049 char *name;
2050
2051 name = smb_strndup_from_utf16(req->Buffer, le16_to_cpu(req->NameLength),
Namjae Jeon070fb212021-05-26 17:57:12 +09002052 1, work->conn->local_nls);
Namjae Jeone2f34482021-03-16 10:49:09 +09002053 if (IS_ERR(name)) {
2054 rsp->hdr.Status = STATUS_NO_MEMORY;
2055 err = PTR_ERR(name);
2056 goto out;
2057 }
2058
2059 id = ksmbd_session_rpc_open(work->sess, name);
Marios Makassikis79caa962021-05-06 11:38:35 +09002060 if (id < 0) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002061 pr_err("Unable to open RPC pipe: %d\n", id);
Marios Makassikis79caa962021-05-06 11:38:35 +09002062 err = id;
2063 goto out;
2064 }
Namjae Jeone2f34482021-03-16 10:49:09 +09002065
Marios Makassikis79caa962021-05-06 11:38:35 +09002066 rsp->hdr.Status = STATUS_SUCCESS;
Namjae Jeone2f34482021-03-16 10:49:09 +09002067 rsp->StructureSize = cpu_to_le16(89);
2068 rsp->OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
2069 rsp->Reserved = 0;
2070 rsp->CreateAction = cpu_to_le32(FILE_OPENED);
2071
2072 rsp->CreationTime = cpu_to_le64(0);
2073 rsp->LastAccessTime = cpu_to_le64(0);
2074 rsp->ChangeTime = cpu_to_le64(0);
2075 rsp->AllocationSize = cpu_to_le64(0);
2076 rsp->EndofFile = cpu_to_le64(0);
2077 rsp->FileAttributes = ATTR_NORMAL_LE;
2078 rsp->Reserved2 = 0;
2079 rsp->VolatileFileId = cpu_to_le64(id);
2080 rsp->PersistentFileId = 0;
2081 rsp->CreateContextsOffset = 0;
2082 rsp->CreateContextsLength = 0;
2083
2084 inc_rfc1001_len(rsp, 88); /* StructureSize - 1*/
2085 kfree(name);
2086 return 0;
2087
2088out:
Marios Makassikis79caa962021-05-06 11:38:35 +09002089 switch (err) {
2090 case -EINVAL:
2091 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
2092 break;
2093 case -ENOSPC:
2094 case -ENOMEM:
2095 rsp->hdr.Status = STATUS_NO_MEMORY;
2096 break;
2097 }
2098
2099 if (!IS_ERR(name))
2100 kfree(name);
2101
Namjae Jeone2f34482021-03-16 10:49:09 +09002102 smb2_set_err_rsp(work);
2103 return err;
2104}
2105
Namjae Jeone2f34482021-03-16 10:49:09 +09002106/**
2107 * smb2_set_ea() - handler for setting extended attributes using set
2108 * info command
2109 * @eabuf: set info command buffer
2110 * @path: dentry path for get ea
2111 *
2112 * Return: 0 on success, otherwise error
2113 */
2114static int smb2_set_ea(struct smb2_ea_info *eabuf, struct path *path)
2115{
Hyunchul Lee465d7202021-07-03 12:10:36 +09002116 struct user_namespace *user_ns = mnt_user_ns(path->mnt);
Namjae Jeone2f34482021-03-16 10:49:09 +09002117 char *attr_name = NULL, *value;
2118 int rc = 0;
2119 int next = 0;
2120
2121 attr_name = kmalloc(XATTR_NAME_MAX + 1, GFP_KERNEL);
2122 if (!attr_name)
2123 return -ENOMEM;
2124
2125 do {
2126 if (!eabuf->EaNameLength)
2127 goto next;
2128
2129 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002130 "name : <%s>, name_len : %u, value_len : %u, next : %u\n",
2131 eabuf->name, eabuf->EaNameLength,
2132 le16_to_cpu(eabuf->EaValueLength),
2133 le32_to_cpu(eabuf->NextEntryOffset));
Namjae Jeone2f34482021-03-16 10:49:09 +09002134
2135 if (eabuf->EaNameLength >
Namjae Jeon070fb212021-05-26 17:57:12 +09002136 (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002137 rc = -EINVAL;
2138 break;
2139 }
2140
2141 memcpy(attr_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
2142 memcpy(&attr_name[XATTR_USER_PREFIX_LEN], eabuf->name,
Namjae Jeon070fb212021-05-26 17:57:12 +09002143 eabuf->EaNameLength);
Namjae Jeone2f34482021-03-16 10:49:09 +09002144 attr_name[XATTR_USER_PREFIX_LEN + eabuf->EaNameLength] = '\0';
2145 value = (char *)&eabuf->name + eabuf->EaNameLength + 1;
2146
2147 if (!eabuf->EaValueLength) {
Hyunchul Lee465d7202021-07-03 12:10:36 +09002148 rc = ksmbd_vfs_casexattr_len(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002149 path->dentry,
Namjae Jeone2f34482021-03-16 10:49:09 +09002150 attr_name,
2151 XATTR_USER_PREFIX_LEN +
2152 eabuf->EaNameLength);
2153
2154 /* delete the EA only when it exits */
2155 if (rc > 0) {
Hyunchul Lee465d7202021-07-03 12:10:36 +09002156 rc = ksmbd_vfs_remove_xattr(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002157 path->dentry,
Namjae Jeone2f34482021-03-16 10:49:09 +09002158 attr_name);
2159
2160 if (rc < 0) {
2161 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002162 "remove xattr failed(%d)\n",
2163 rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002164 break;
2165 }
2166 }
2167
2168 /* if the EA doesn't exist, just do nothing. */
2169 rc = 0;
2170 } else {
Hyunchul Lee465d7202021-07-03 12:10:36 +09002171 rc = ksmbd_vfs_setxattr(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002172 path->dentry, attr_name, value,
Namjae Jeon070fb212021-05-26 17:57:12 +09002173 le16_to_cpu(eabuf->EaValueLength), 0);
Namjae Jeone2f34482021-03-16 10:49:09 +09002174 if (rc < 0) {
2175 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002176 "ksmbd_vfs_setxattr is failed(%d)\n",
2177 rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002178 break;
2179 }
2180 }
2181
2182next:
2183 next = le32_to_cpu(eabuf->NextEntryOffset);
2184 eabuf = (struct smb2_ea_info *)((char *)eabuf + next);
2185 } while (next != 0);
2186
2187 kfree(attr_name);
2188 return rc;
2189}
2190
Namjae Jeone2f34482021-03-16 10:49:09 +09002191static noinline int smb2_set_stream_name_xattr(struct path *path,
Namjae Jeon070fb212021-05-26 17:57:12 +09002192 struct ksmbd_file *fp,
2193 char *stream_name, int s_type)
Namjae Jeone2f34482021-03-16 10:49:09 +09002194{
Hyunchul Lee465d7202021-07-03 12:10:36 +09002195 struct user_namespace *user_ns = mnt_user_ns(path->mnt);
Namjae Jeone2f34482021-03-16 10:49:09 +09002196 size_t xattr_stream_size;
2197 char *xattr_stream_name;
2198 int rc;
2199
2200 rc = ksmbd_vfs_xattr_stream_name(stream_name,
2201 &xattr_stream_name,
2202 &xattr_stream_size,
2203 s_type);
2204 if (rc)
2205 return rc;
2206
2207 fp->stream.name = xattr_stream_name;
2208 fp->stream.size = xattr_stream_size;
2209
2210 /* Check if there is stream prefix in xattr space */
Hyunchul Lee465d7202021-07-03 12:10:36 +09002211 rc = ksmbd_vfs_casexattr_len(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002212 path->dentry,
Namjae Jeone2f34482021-03-16 10:49:09 +09002213 xattr_stream_name,
2214 xattr_stream_size);
2215 if (rc >= 0)
2216 return 0;
2217
2218 if (fp->cdoption == FILE_OPEN_LE) {
2219 ksmbd_debug(SMB, "XATTR stream name lookup failed: %d\n", rc);
2220 return -EBADF;
2221 }
2222
Hyunchul Lee465d7202021-07-03 12:10:36 +09002223 rc = ksmbd_vfs_setxattr(user_ns, path->dentry,
2224 xattr_stream_name, NULL, 0, 0);
Namjae Jeone2f34482021-03-16 10:49:09 +09002225 if (rc < 0)
Namjae Jeonbde16942021-06-28 15:23:19 +09002226 pr_err("Failed to store XATTR stream name :%d\n", rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002227 return 0;
2228}
2229
Hyunchul Leeef24c962021-06-30 18:25:52 +09002230static int smb2_remove_smb_xattrs(struct path *path)
Namjae Jeone2f34482021-03-16 10:49:09 +09002231{
Hyunchul Lee465d7202021-07-03 12:10:36 +09002232 struct user_namespace *user_ns = mnt_user_ns(path->mnt);
Namjae Jeone2f34482021-03-16 10:49:09 +09002233 char *name, *xattr_list = NULL;
2234 ssize_t xattr_list_len;
2235 int err = 0;
2236
Hyunchul Leeef24c962021-06-30 18:25:52 +09002237 xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
Namjae Jeone2f34482021-03-16 10:49:09 +09002238 if (xattr_list_len < 0) {
2239 goto out;
2240 } else if (!xattr_list_len) {
2241 ksmbd_debug(SMB, "empty xattr in the file\n");
2242 goto out;
2243 }
2244
2245 for (name = xattr_list; name - xattr_list < xattr_list_len;
2246 name += strlen(name) + 1) {
2247 ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));
2248
2249 if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002250 strncmp(&name[XATTR_USER_PREFIX_LEN], DOS_ATTRIBUTE_PREFIX,
2251 DOS_ATTRIBUTE_PREFIX_LEN) &&
2252 strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX, STREAM_PREFIX_LEN))
Namjae Jeone2f34482021-03-16 10:49:09 +09002253 continue;
2254
Hyunchul Lee465d7202021-07-03 12:10:36 +09002255 err = ksmbd_vfs_remove_xattr(user_ns, path->dentry, name);
Namjae Jeone2f34482021-03-16 10:49:09 +09002256 if (err)
2257 ksmbd_debug(SMB, "remove xattr failed : %s\n", name);
2258 }
2259out:
Namjae Jeon79f6b112021-04-02 12:47:14 +09002260 kvfree(xattr_list);
Namjae Jeone2f34482021-03-16 10:49:09 +09002261 return err;
2262}
2263
2264static int smb2_create_truncate(struct path *path)
2265{
2266 int rc = vfs_truncate(path, 0);
2267
2268 if (rc) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002269 pr_err("vfs_truncate failed, rc %d\n", rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002270 return rc;
2271 }
2272
Hyunchul Leeef24c962021-06-30 18:25:52 +09002273 rc = smb2_remove_smb_xattrs(path);
Namjae Jeone2f34482021-03-16 10:49:09 +09002274 if (rc == -EOPNOTSUPP)
2275 rc = 0;
2276 if (rc)
2277 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002278 "ksmbd_truncate_stream_name_xattr failed, rc %d\n",
2279 rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002280 return rc;
2281}
2282
Namjae Jeon64b39f42021-03-30 14:25:35 +09002283static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, struct path *path,
Namjae Jeon070fb212021-05-26 17:57:12 +09002284 struct ksmbd_file *fp)
Namjae Jeone2f34482021-03-16 10:49:09 +09002285{
2286 struct xattr_dos_attrib da = {0};
2287 int rc;
2288
2289 if (!test_share_config_flag(tcon->share_conf,
2290 KSMBD_SHARE_FLAG_STORE_DOS_ATTRS))
2291 return;
2292
2293 da.version = 4;
2294 da.attr = le32_to_cpu(fp->f_ci->m_fattr);
2295 da.itime = da.create_time = fp->create_time;
2296 da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
2297 XATTR_DOSINFO_ITIME;
2298
Hyunchul Leeaf349832021-06-30 18:25:53 +09002299 rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_user_ns(path->mnt),
2300 path->dentry, &da);
Namjae Jeone2f34482021-03-16 10:49:09 +09002301 if (rc)
2302 ksmbd_debug(SMB, "failed to store file attribute into xattr\n");
2303}
2304
2305static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon,
Namjae Jeon070fb212021-05-26 17:57:12 +09002306 struct path *path, struct ksmbd_file *fp)
Namjae Jeone2f34482021-03-16 10:49:09 +09002307{
2308 struct xattr_dos_attrib da;
2309 int rc;
2310
2311 fp->f_ci->m_fattr &= ~(ATTR_HIDDEN_LE | ATTR_SYSTEM_LE);
2312
2313 /* get FileAttributes from XATTR_NAME_DOS_ATTRIBUTE */
2314 if (!test_share_config_flag(tcon->share_conf,
Namjae Jeon64b39f42021-03-30 14:25:35 +09002315 KSMBD_SHARE_FLAG_STORE_DOS_ATTRS))
Namjae Jeone2f34482021-03-16 10:49:09 +09002316 return;
2317
Hyunchul Leeaf349832021-06-30 18:25:53 +09002318 rc = ksmbd_vfs_get_dos_attrib_xattr(mnt_user_ns(path->mnt),
2319 path->dentry, &da);
Namjae Jeone2f34482021-03-16 10:49:09 +09002320 if (rc > 0) {
2321 fp->f_ci->m_fattr = cpu_to_le32(da.attr);
2322 fp->create_time = da.create_time;
2323 fp->itime = da.itime;
2324 }
2325}
2326
Namjae Jeon64b39f42021-03-30 14:25:35 +09002327static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name,
Namjae Jeon070fb212021-05-26 17:57:12 +09002328 int open_flags, umode_t posix_mode, bool is_dir)
Namjae Jeone2f34482021-03-16 10:49:09 +09002329{
2330 struct ksmbd_tree_connect *tcon = work->tcon;
2331 struct ksmbd_share_config *share = tcon->share_conf;
2332 umode_t mode;
2333 int rc;
2334
2335 if (!(open_flags & O_CREAT))
2336 return -EBADF;
2337
2338 ksmbd_debug(SMB, "file does not exist, so creating\n");
2339 if (is_dir == true) {
2340 ksmbd_debug(SMB, "creating directory\n");
2341
2342 mode = share_config_directory_mode(share, posix_mode);
2343 rc = ksmbd_vfs_mkdir(work, name, mode);
2344 if (rc)
2345 return rc;
2346 } else {
2347 ksmbd_debug(SMB, "creating regular file\n");
2348
2349 mode = share_config_create_mode(share, posix_mode);
2350 rc = ksmbd_vfs_create(work, name, mode);
2351 if (rc)
2352 return rc;
2353 }
2354
2355 rc = ksmbd_vfs_kern_path(name, 0, path, 0);
2356 if (rc) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002357 pr_err("cannot get linux path (%s), err = %d\n",
2358 name, rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002359 return rc;
2360 }
2361 return 0;
2362}
2363
2364static int smb2_create_sd_buffer(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09002365 struct smb2_create_req *req,
Hyunchul Leeef24c962021-06-30 18:25:52 +09002366 struct path *path)
Namjae Jeone2f34482021-03-16 10:49:09 +09002367{
2368 struct create_context *context;
Hyunchul Lee21dd1fd2021-07-09 17:06:34 +09002369 struct create_sd_buf_req *sd_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09002370
2371 if (!req->CreateContextsOffset)
Hyunchul Lee21dd1fd2021-07-09 17:06:34 +09002372 return -ENOENT;
Namjae Jeone2f34482021-03-16 10:49:09 +09002373
2374 /* Parse SD BUFFER create contexts */
2375 context = smb2_find_context_vals(req, SMB2_CREATE_SD_BUFFER);
Hyunchul Lee21dd1fd2021-07-09 17:06:34 +09002376 if (!context)
2377 return -ENOENT;
2378 else if (IS_ERR(context))
2379 return PTR_ERR(context);
Namjae Jeone2f34482021-03-16 10:49:09 +09002380
Hyunchul Lee21dd1fd2021-07-09 17:06:34 +09002381 ksmbd_debug(SMB,
2382 "Set ACLs using SMB2_CREATE_SD_BUFFER context\n");
2383 sd_buf = (struct create_sd_buf_req *)context;
2384 return set_info_sec(work->conn, work->tcon, path, &sd_buf->ntsd,
2385 le32_to_cpu(sd_buf->ccontext.DataLength), true);
Namjae Jeone2f34482021-03-16 10:49:09 +09002386}
2387
Christian Brauner43205ca2021-08-23 17:13:50 +02002388static void ksmbd_acls_fattr(struct smb_fattr *fattr,
2389 struct user_namespace *mnt_userns,
2390 struct inode *inode)
Namjae Jeon3d47e542021-04-20 14:25:35 +09002391{
Christian Brauner43205ca2021-08-23 17:13:50 +02002392 fattr->cf_uid = i_uid_into_mnt(mnt_userns, inode);
2393 fattr->cf_gid = i_gid_into_mnt(mnt_userns, inode);
Namjae Jeon3d47e542021-04-20 14:25:35 +09002394 fattr->cf_mode = inode->i_mode;
Namjae Jeon777cad12021-08-13 08:15:33 +09002395 fattr->cf_acls = NULL;
Namjae Jeon3d47e542021-04-20 14:25:35 +09002396 fattr->cf_dacls = NULL;
2397
Namjae Jeon777cad12021-08-13 08:15:33 +09002398 if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
2399 fattr->cf_acls = get_acl(inode, ACL_TYPE_ACCESS);
2400 if (S_ISDIR(inode->i_mode))
2401 fattr->cf_dacls = get_acl(inode, ACL_TYPE_DEFAULT);
2402 }
Namjae Jeon3d47e542021-04-20 14:25:35 +09002403}
2404
Namjae Jeone2f34482021-03-16 10:49:09 +09002405/**
2406 * smb2_open() - handler for smb file open request
2407 * @work: smb work containing request buffer
2408 *
2409 * Return: 0 on success, otherwise error
2410 */
2411int smb2_open(struct ksmbd_work *work)
2412{
2413 struct ksmbd_conn *conn = work->conn;
2414 struct ksmbd_session *sess = work->sess;
2415 struct ksmbd_tree_connect *tcon = work->tcon;
2416 struct smb2_create_req *req;
2417 struct smb2_create_rsp *rsp, *rsp_org;
2418 struct path path;
2419 struct ksmbd_share_config *share = tcon->share_conf;
2420 struct ksmbd_file *fp = NULL;
2421 struct file *filp = NULL;
Hyunchul Lee465d7202021-07-03 12:10:36 +09002422 struct user_namespace *user_ns = NULL;
Namjae Jeone2f34482021-03-16 10:49:09 +09002423 struct kstat stat;
2424 struct create_context *context;
2425 struct lease_ctx_info *lc = NULL;
2426 struct create_ea_buf_req *ea_buf = NULL;
2427 struct oplock_info *opinfo;
2428 __le32 *next_ptr = NULL;
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09002429 int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0;
Namjae Jeone2f34482021-03-16 10:49:09 +09002430 int rc = 0, len = 0;
2431 int contxt_cnt = 0, query_disk_id = 0;
2432 int maximal_access_ctxt = 0, posix_ctxt = 0;
2433 int s_type = 0;
2434 int next_off = 0;
2435 char *name = NULL;
2436 char *stream_name = NULL;
2437 bool file_present = false, created = false, already_permitted = false;
Namjae Jeone2f34482021-03-16 10:49:09 +09002438 int share_ret, need_truncate = 0;
2439 u64 time;
2440 umode_t posix_mode = 0;
2441 __le32 daccess, maximal_access = 0;
2442
Namjae Jeone5066492021-03-30 12:35:23 +09002443 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09002444 WORK_BUFFERS(work, req, rsp);
2445
2446 if (req->hdr.NextCommand && !work->next_smb2_rcv_hdr_off &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002447 (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002448 ksmbd_debug(SMB, "invalid flag in chained command\n");
2449 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
2450 smb2_set_err_rsp(work);
2451 return -EINVAL;
2452 }
2453
2454 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
2455 ksmbd_debug(SMB, "IPC pipe create request\n");
2456 return create_smb2_pipe(work);
2457 }
2458
2459 if (req->NameLength) {
2460 if ((req->CreateOptions & FILE_DIRECTORY_FILE_LE) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002461 *(char *)req->Buffer == '\\') {
Namjae Jeonbde16942021-06-28 15:23:19 +09002462 pr_err("not allow directory name included leading slash\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09002463 rc = -EINVAL;
2464 goto err_out1;
2465 }
2466
2467 name = smb2_get_name(share,
2468 req->Buffer,
2469 le16_to_cpu(req->NameLength),
2470 work->conn->local_nls);
2471 if (IS_ERR(name)) {
2472 rc = PTR_ERR(name);
2473 if (rc != -ENOMEM)
2474 rc = -ENOENT;
Dan Carpenter8b99f352021-08-02 08:14:03 +09002475 name = NULL;
Namjae Jeone2f34482021-03-16 10:49:09 +09002476 goto err_out1;
2477 }
2478
2479 ksmbd_debug(SMB, "converted name = %s\n", name);
2480 if (strchr(name, ':')) {
2481 if (!test_share_config_flag(work->tcon->share_conf,
Namjae Jeon64b39f42021-03-30 14:25:35 +09002482 KSMBD_SHARE_FLAG_STREAMS)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002483 rc = -EBADF;
2484 goto err_out1;
2485 }
2486 rc = parse_stream_name(name, &stream_name, &s_type);
2487 if (rc < 0)
2488 goto err_out1;
2489 }
2490
2491 rc = ksmbd_validate_filename(name);
2492 if (rc < 0)
2493 goto err_out1;
2494
2495 if (ksmbd_share_veto_filename(share, name)) {
2496 rc = -ENOENT;
2497 ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09002498 name);
Namjae Jeone2f34482021-03-16 10:49:09 +09002499 goto err_out1;
2500 }
2501 } else {
2502 len = strlen(share->path);
2503 ksmbd_debug(SMB, "share path len %d\n", len);
2504 name = kmalloc(len + 1, GFP_KERNEL);
2505 if (!name) {
2506 rsp->hdr.Status = STATUS_NO_MEMORY;
2507 rc = -ENOMEM;
2508 goto err_out1;
2509 }
2510
2511 memcpy(name, share->path, len);
2512 *(name + len) = '\0';
2513 }
2514
2515 req_op_level = req->RequestedOplockLevel;
Namjae Jeon73f9dad2021-04-16 14:12:06 +09002516 if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
Namjae Jeone2f34482021-03-16 10:49:09 +09002517 lc = parse_lease_state(req);
Namjae Jeone2f34482021-03-16 10:49:09 +09002518
Namjae Jeon64b39f42021-03-30 14:25:35 +09002519 if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002520 pr_err("Invalid impersonationlevel : 0x%x\n",
2521 le32_to_cpu(req->ImpersonationLevel));
Namjae Jeone2f34482021-03-16 10:49:09 +09002522 rc = -EIO;
2523 rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL;
2524 goto err_out1;
2525 }
2526
2527 if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002528 pr_err("Invalid create options : 0x%x\n",
2529 le32_to_cpu(req->CreateOptions));
Namjae Jeone2f34482021-03-16 10:49:09 +09002530 rc = -EINVAL;
2531 goto err_out1;
2532 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09002533 if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002534 req->CreateOptions & FILE_RANDOM_ACCESS_LE)
Namjae Jeone2f34482021-03-16 10:49:09 +09002535 req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE);
2536
Namjae Jeon070fb212021-05-26 17:57:12 +09002537 if (req->CreateOptions &
2538 (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION |
2539 FILE_RESERVE_OPFILTER_LE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002540 rc = -EOPNOTSUPP;
2541 goto err_out1;
2542 }
2543
2544 if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
2545 if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) {
2546 rc = -EINVAL;
2547 goto err_out1;
Namjae Jeon64b39f42021-03-30 14:25:35 +09002548 } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002549 req->CreateOptions = ~(FILE_NO_COMPRESSION_LE);
Namjae Jeon64b39f42021-03-30 14:25:35 +09002550 }
Namjae Jeone2f34482021-03-16 10:49:09 +09002551 }
2552 }
2553
2554 if (le32_to_cpu(req->CreateDisposition) >
Namjae Jeon070fb212021-05-26 17:57:12 +09002555 le32_to_cpu(FILE_OVERWRITE_IF_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002556 pr_err("Invalid create disposition : 0x%x\n",
2557 le32_to_cpu(req->CreateDisposition));
Namjae Jeone2f34482021-03-16 10:49:09 +09002558 rc = -EINVAL;
2559 goto err_out1;
2560 }
2561
2562 if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002563 pr_err("Invalid desired access : 0x%x\n",
2564 le32_to_cpu(req->DesiredAccess));
Namjae Jeone2f34482021-03-16 10:49:09 +09002565 rc = -EACCES;
2566 goto err_out1;
2567 }
2568
Namjae Jeon64b39f42021-03-30 14:25:35 +09002569 if (req->FileAttributes && !(req->FileAttributes & ATTR_MASK_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09002570 pr_err("Invalid file attribute : 0x%x\n",
2571 le32_to_cpu(req->FileAttributes));
Namjae Jeone2f34482021-03-16 10:49:09 +09002572 rc = -EINVAL;
2573 goto err_out1;
2574 }
2575
2576 if (req->CreateContextsOffset) {
2577 /* Parse non-durable handle create contexts */
2578 context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER);
Namjae Jeonf19b3962021-07-13 09:59:34 +09002579 if (IS_ERR(context)) {
2580 rc = PTR_ERR(context);
2581 goto err_out1;
2582 } else if (context) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002583 ea_buf = (struct create_ea_buf_req *)context;
2584 if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) {
2585 rsp->hdr.Status = STATUS_ACCESS_DENIED;
2586 rc = -EACCES;
2587 goto err_out1;
2588 }
2589 }
2590
2591 context = smb2_find_context_vals(req,
Namjae Jeon070fb212021-05-26 17:57:12 +09002592 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST);
Namjae Jeonf19b3962021-07-13 09:59:34 +09002593 if (IS_ERR(context)) {
2594 rc = PTR_ERR(context);
2595 goto err_out1;
2596 } else if (context) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002597 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002598 "get query maximal access context\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09002599 maximal_access_ctxt = 1;
2600 }
2601
2602 context = smb2_find_context_vals(req,
Namjae Jeon070fb212021-05-26 17:57:12 +09002603 SMB2_CREATE_TIMEWARP_REQUEST);
Namjae Jeonf19b3962021-07-13 09:59:34 +09002604 if (IS_ERR(context)) {
2605 rc = PTR_ERR(context);
2606 goto err_out1;
2607 } else if (context) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002608 ksmbd_debug(SMB, "get timewarp context\n");
2609 rc = -EBADF;
2610 goto err_out1;
2611 }
2612
2613 if (tcon->posix_extensions) {
2614 context = smb2_find_context_vals(req,
Namjae Jeon070fb212021-05-26 17:57:12 +09002615 SMB2_CREATE_TAG_POSIX);
Namjae Jeonf19b3962021-07-13 09:59:34 +09002616 if (IS_ERR(context)) {
2617 rc = PTR_ERR(context);
2618 goto err_out1;
2619 } else if (context) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002620 struct create_posix *posix =
2621 (struct create_posix *)context;
2622 ksmbd_debug(SMB, "get posix context\n");
2623
2624 posix_mode = le32_to_cpu(posix->Mode);
2625 posix_ctxt = 1;
2626 }
2627 }
2628 }
2629
2630 if (ksmbd_override_fsids(work)) {
2631 rc = -ENOMEM;
2632 goto err_out1;
2633 }
2634
2635 if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
2636 /*
2637 * On delete request, instead of following up, need to
2638 * look the current entity
2639 */
2640 rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
2641 if (!rc) {
2642 /*
2643 * If file exists with under flags, return access
2644 * denied error.
2645 */
2646 if (req->CreateDisposition == FILE_OVERWRITE_IF_LE ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09002647 req->CreateDisposition == FILE_OPEN_IF_LE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002648 rc = -EACCES;
2649 path_put(&path);
2650 goto err_out;
2651 }
2652
Namjae Jeon64b39f42021-03-30 14:25:35 +09002653 if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002654 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002655 "User does not have write permission\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09002656 rc = -EACCES;
2657 path_put(&path);
2658 goto err_out;
2659 }
2660 }
2661 } else {
2662 if (test_share_config_flag(work->tcon->share_conf,
Namjae Jeon64b39f42021-03-30 14:25:35 +09002663 KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002664 /*
2665 * Use LOOKUP_FOLLOW to follow the path of
2666 * symlink in path buildup
2667 */
2668 rc = ksmbd_vfs_kern_path(name, LOOKUP_FOLLOW, &path, 1);
2669 if (rc) { /* Case for broken link ?*/
2670 rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
2671 }
2672 } else {
2673 rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
2674 if (!rc && d_is_symlink(path.dentry)) {
2675 rc = -EACCES;
2676 path_put(&path);
2677 goto err_out;
2678 }
2679 }
2680 }
2681
2682 if (rc) {
2683 if (rc == -EACCES) {
2684 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002685 "User does not have right permission\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09002686 goto err_out;
2687 }
2688 ksmbd_debug(SMB, "can not get linux path for %s, rc = %d\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09002689 name, rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002690 rc = 0;
2691 } else {
2692 file_present = true;
Hyunchul Lee465d7202021-07-03 12:10:36 +09002693 user_ns = mnt_user_ns(path.mnt);
2694 generic_fillattr(user_ns, d_inode(path.dentry), &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09002695 }
2696 if (stream_name) {
2697 if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
2698 if (s_type == DATA_STREAM) {
2699 rc = -EIO;
2700 rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;
2701 }
2702 } else {
2703 if (S_ISDIR(stat.mode) && s_type == DATA_STREAM) {
2704 rc = -EIO;
2705 rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
2706 }
2707 }
2708
2709 if (req->CreateOptions & FILE_DIRECTORY_FILE_LE &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002710 req->FileAttributes & ATTR_NORMAL_LE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002711 rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;
2712 rc = -EIO;
2713 }
2714
2715 if (rc < 0)
2716 goto err_out;
2717 }
2718
Namjae Jeon64b39f42021-03-30 14:25:35 +09002719 if (file_present && req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE &&
2720 S_ISDIR(stat.mode) && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002721 ksmbd_debug(SMB, "open() argument is a directory: %s, %x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09002722 name, req->CreateOptions);
Namjae Jeone2f34482021-03-16 10:49:09 +09002723 rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
2724 rc = -EIO;
2725 goto err_out;
2726 }
2727
2728 if (file_present && (req->CreateOptions & FILE_DIRECTORY_FILE_LE) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002729 !(req->CreateDisposition == FILE_CREATE_LE) &&
2730 !S_ISDIR(stat.mode)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002731 rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;
2732 rc = -EIO;
2733 goto err_out;
2734 }
2735
2736 if (!stream_name && file_present &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002737 req->CreateDisposition == FILE_CREATE_LE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002738 rc = -EEXIST;
2739 goto err_out;
2740 }
2741
Namjae Jeone2f34482021-03-16 10:49:09 +09002742 daccess = smb_map_generic_desired_access(req->DesiredAccess);
2743
2744 if (file_present && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
Hyunchul Leeef24c962021-06-30 18:25:52 +09002745 rc = smb_check_perm_dacl(conn, &path, &daccess,
Namjae Jeon070fb212021-05-26 17:57:12 +09002746 sess->user->uid);
Namjae Jeone2f34482021-03-16 10:49:09 +09002747 if (rc)
2748 goto err_out;
2749 }
2750
2751 if (daccess & FILE_MAXIMAL_ACCESS_LE) {
2752 if (!file_present) {
2753 daccess = cpu_to_le32(GENERIC_ALL_FLAGS);
2754 } else {
Hyunchul Lee465d7202021-07-03 12:10:36 +09002755 rc = ksmbd_vfs_query_maximal_access(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002756 path.dentry,
Namjae Jeone2f34482021-03-16 10:49:09 +09002757 &daccess);
2758 if (rc)
2759 goto err_out;
2760 already_permitted = true;
2761 }
2762 maximal_access = daccess;
2763 }
2764
Namjae Jeon070fb212021-05-26 17:57:12 +09002765 open_flags = smb2_create_open_flags(file_present, daccess,
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09002766 req->CreateDisposition,
2767 &may_flags);
Namjae Jeone2f34482021-03-16 10:49:09 +09002768
2769 if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
2770 if (open_flags & O_CREAT) {
2771 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002772 "User does not have write permission\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09002773 rc = -EACCES;
2774 goto err_out;
2775 }
2776 }
2777
2778 /*create file if not present */
2779 if (!file_present) {
2780 rc = smb2_creat(work, &path, name, open_flags, posix_mode,
Namjae Jeon070fb212021-05-26 17:57:12 +09002781 req->CreateOptions & FILE_DIRECTORY_FILE_LE);
Marios Makassikisd337a442021-07-27 09:24:51 +09002782 if (rc) {
2783 if (rc == -ENOENT) {
2784 rc = -EIO;
2785 rsp->hdr.Status = STATUS_OBJECT_PATH_NOT_FOUND;
2786 }
Namjae Jeone2f34482021-03-16 10:49:09 +09002787 goto err_out;
Marios Makassikisd337a442021-07-27 09:24:51 +09002788 }
Namjae Jeone2f34482021-03-16 10:49:09 +09002789
2790 created = true;
Hyunchul Lee465d7202021-07-03 12:10:36 +09002791 user_ns = mnt_user_ns(path.mnt);
Namjae Jeone2f34482021-03-16 10:49:09 +09002792 if (ea_buf) {
2793 rc = smb2_set_ea(&ea_buf->ea, &path);
2794 if (rc == -EOPNOTSUPP)
2795 rc = 0;
2796 else if (rc)
2797 goto err_out;
2798 }
2799 } else if (!already_permitted) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002800 /* FILE_READ_ATTRIBUTE is allowed without inode_permission,
2801 * because execute(search) permission on a parent directory,
2802 * is already granted.
2803 */
Namjae Jeon64b39f42021-03-30 14:25:35 +09002804 if (daccess & ~(FILE_READ_ATTRIBUTES_LE | FILE_READ_CONTROL_LE)) {
Hyunchul Lee465d7202021-07-03 12:10:36 +09002805 rc = inode_permission(user_ns,
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09002806 d_inode(path.dentry),
2807 may_flags);
Namjae Jeonff1d5722021-04-13 13:18:10 +09002808 if (rc)
Namjae Jeone2f34482021-03-16 10:49:09 +09002809 goto err_out;
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09002810
2811 if ((daccess & FILE_DELETE_LE) ||
2812 (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
Hyunchul Lee465d7202021-07-03 12:10:36 +09002813 rc = ksmbd_vfs_may_delete(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002814 path.dentry);
Hyunchul Lee6c5e36d2021-06-23 13:48:24 +09002815 if (rc)
2816 goto err_out;
2817 }
Namjae Jeone2f34482021-03-16 10:49:09 +09002818 }
2819 }
2820
2821 rc = ksmbd_query_inode_status(d_inode(path.dentry->d_parent));
2822 if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) {
2823 rc = -EBUSY;
2824 goto err_out;
2825 }
2826
2827 rc = 0;
2828 filp = dentry_open(&path, open_flags, current_cred());
2829 if (IS_ERR(filp)) {
2830 rc = PTR_ERR(filp);
Namjae Jeonbde16942021-06-28 15:23:19 +09002831 pr_err("dentry open for dir failed, rc %d\n", rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002832 goto err_out;
2833 }
2834
2835 if (file_present) {
2836 if (!(open_flags & O_TRUNC))
2837 file_info = FILE_OPENED;
2838 else
2839 file_info = FILE_OVERWRITTEN;
2840
Namjae Jeon070fb212021-05-26 17:57:12 +09002841 if ((req->CreateDisposition & FILE_CREATE_MASK_LE) ==
2842 FILE_SUPERSEDE_LE)
Namjae Jeone2f34482021-03-16 10:49:09 +09002843 file_info = FILE_SUPERSEDED;
Namjae Jeon64b39f42021-03-30 14:25:35 +09002844 } else if (open_flags & O_CREAT) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002845 file_info = FILE_CREATED;
Namjae Jeon64b39f42021-03-30 14:25:35 +09002846 }
Namjae Jeone2f34482021-03-16 10:49:09 +09002847
2848 ksmbd_vfs_set_fadvise(filp, req->CreateOptions);
2849
2850 /* Obtain Volatile-ID */
2851 fp = ksmbd_open_fd(work, filp);
2852 if (IS_ERR(fp)) {
2853 fput(filp);
2854 rc = PTR_ERR(fp);
2855 fp = NULL;
2856 goto err_out;
2857 }
2858
2859 /* Get Persistent-ID */
2860 ksmbd_open_durable_fd(fp);
Namjae Jeon38673692021-07-08 12:32:27 +09002861 if (!has_file_id(fp->persistent_id)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002862 rc = -ENOMEM;
2863 goto err_out;
2864 }
2865
2866 fp->filename = name;
2867 fp->cdoption = req->CreateDisposition;
2868 fp->daccess = daccess;
2869 fp->saccess = req->ShareAccess;
2870 fp->coption = req->CreateOptions;
2871
2872 /* Set default windows and posix acls if creating new file */
2873 if (created) {
2874 int posix_acl_rc;
Namjae Jeonfba08fa2021-04-15 10:29:39 +09002875 struct inode *inode = d_inode(path.dentry);
Namjae Jeone2f34482021-03-16 10:49:09 +09002876
Hyunchul Lee465d7202021-07-03 12:10:36 +09002877 posix_acl_rc = ksmbd_vfs_inherit_posix_acl(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002878 inode,
2879 d_inode(path.dentry->d_parent));
Namjae Jeone2f34482021-03-16 10:49:09 +09002880 if (posix_acl_rc)
2881 ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);
2882
2883 if (test_share_config_flag(work->tcon->share_conf,
Namjae Jeon64b39f42021-03-30 14:25:35 +09002884 KSMBD_SHARE_FLAG_ACL_XATTR)) {
Hyunchul Leeef24c962021-06-30 18:25:52 +09002885 rc = smb_inherit_dacl(conn, &path, sess->user->uid,
Namjae Jeon070fb212021-05-26 17:57:12 +09002886 sess->user->gid);
Namjae Jeone2f34482021-03-16 10:49:09 +09002887 }
2888
2889 if (rc) {
Hyunchul Leeef24c962021-06-30 18:25:52 +09002890 rc = smb2_create_sd_buffer(work, req, &path);
Namjae Jeone2f34482021-03-16 10:49:09 +09002891 if (rc) {
2892 if (posix_acl_rc)
Hyunchul Lee465d7202021-07-03 12:10:36 +09002893 ksmbd_vfs_set_init_posix_acl(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002894 inode);
Namjae Jeone2f34482021-03-16 10:49:09 +09002895
2896 if (test_share_config_flag(work->tcon->share_conf,
Namjae Jeon64b39f42021-03-30 14:25:35 +09002897 KSMBD_SHARE_FLAG_ACL_XATTR)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002898 struct smb_fattr fattr;
2899 struct smb_ntsd *pntsd;
Namjae Jeon3d47e542021-04-20 14:25:35 +09002900 int pntsd_size, ace_num = 0;
Namjae Jeone2f34482021-03-16 10:49:09 +09002901
Christian Brauner43205ca2021-08-23 17:13:50 +02002902 ksmbd_acls_fattr(&fattr, user_ns, inode);
Marios Makassikise6b10592021-04-15 10:24:56 +09002903 if (fattr.cf_acls)
2904 ace_num = fattr.cf_acls->a_count;
Namjae Jeon3d47e542021-04-20 14:25:35 +09002905 if (fattr.cf_dacls)
2906 ace_num += fattr.cf_dacls->a_count;
Namjae Jeone2f34482021-03-16 10:49:09 +09002907
2908 pntsd = kmalloc(sizeof(struct smb_ntsd) +
Namjae Jeon64b39f42021-03-30 14:25:35 +09002909 sizeof(struct smb_sid) * 3 +
Namjae Jeone2f34482021-03-16 10:49:09 +09002910 sizeof(struct smb_acl) +
Namjae Jeon64b39f42021-03-30 14:25:35 +09002911 sizeof(struct smb_ace) * ace_num * 2,
Namjae Jeone2f34482021-03-16 10:49:09 +09002912 GFP_KERNEL);
2913 if (!pntsd)
2914 goto err_out;
2915
Hyunchul Lee465d7202021-07-03 12:10:36 +09002916 rc = build_sec_desc(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09002917 pntsd, NULL,
Namjae Jeon070fb212021-05-26 17:57:12 +09002918 OWNER_SECINFO |
Hyunchul Leeaf349832021-06-30 18:25:53 +09002919 GROUP_SECINFO |
2920 DACL_SECINFO,
Namjae Jeon070fb212021-05-26 17:57:12 +09002921 &pntsd_size, &fattr);
Namjae Jeone2f34482021-03-16 10:49:09 +09002922 posix_acl_release(fattr.cf_acls);
2923 posix_acl_release(fattr.cf_dacls);
2924
2925 rc = ksmbd_vfs_set_sd_xattr(conn,
Hyunchul Lee465d7202021-07-03 12:10:36 +09002926 user_ns,
Namjae Jeon070fb212021-05-26 17:57:12 +09002927 path.dentry,
2928 pntsd,
2929 pntsd_size);
Namjae Jeon3d47e542021-04-20 14:25:35 +09002930 kfree(pntsd);
Namjae Jeone2f34482021-03-16 10:49:09 +09002931 if (rc)
Namjae Jeonbde16942021-06-28 15:23:19 +09002932 pr_err("failed to store ntacl in xattr : %d\n",
2933 rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09002934 }
2935 }
2936 }
2937 rc = 0;
2938 }
2939
2940 if (stream_name) {
2941 rc = smb2_set_stream_name_xattr(&path,
2942 fp,
2943 stream_name,
2944 s_type);
2945 if (rc)
2946 goto err_out;
2947 file_info = FILE_CREATED;
2948 }
2949
2950 fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE |
2951 FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE));
Namjae Jeon64b39f42021-03-30 14:25:35 +09002952 if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
2953 !fp->attrib_only && !stream_name) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002954 smb_break_all_oplock(work, fp);
2955 need_truncate = 1;
2956 }
2957
2958 /* fp should be searchable through ksmbd_inode.m_fp_list
2959 * after daccess, saccess, attrib_only, and stream are
2960 * initialized.
2961 */
2962 write_lock(&fp->f_ci->m_lock);
2963 list_add(&fp->node, &fp->f_ci->m_fp_list);
2964 write_unlock(&fp->f_ci->m_lock);
2965
2966 rc = ksmbd_vfs_getattr(&path, &stat);
2967 if (rc) {
Hyunchul Lee465d7202021-07-03 12:10:36 +09002968 generic_fillattr(user_ns, d_inode(path.dentry), &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09002969 rc = 0;
2970 }
2971
2972 /* Check delete pending among previous fp before oplock break */
2973 if (ksmbd_inode_pending_delete(fp)) {
2974 rc = -EBUSY;
2975 goto err_out;
2976 }
2977
2978 share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);
Namjae Jeon64b39f42021-03-30 14:25:35 +09002979 if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) ||
2980 (req_op_level == SMB2_OPLOCK_LEVEL_LEASE &&
2981 !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) {
Namjae Jeonab0b2632021-06-29 09:20:13 +09002982 if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09002983 rc = share_ret;
2984 goto err_out;
2985 }
2986 } else {
2987 if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
2988 req_op_level = smb2_map_lease_to_oplock(lc->req_state);
2989 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09002990 "lease req for(%s) req oplock state 0x%x, lease state 0x%x\n",
2991 name, req_op_level, lc->req_state);
Namjae Jeone2f34482021-03-16 10:49:09 +09002992 rc = find_same_lease_key(sess, fp->f_ci, lc);
2993 if (rc)
2994 goto err_out;
2995 } else if (open_flags == O_RDONLY &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09002996 (req_op_level == SMB2_OPLOCK_LEVEL_BATCH ||
2997 req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE))
Namjae Jeone2f34482021-03-16 10:49:09 +09002998 req_op_level = SMB2_OPLOCK_LEVEL_II;
2999
3000 rc = smb_grant_oplock(work, req_op_level,
3001 fp->persistent_id, fp,
3002 le32_to_cpu(req->hdr.Id.SyncId.TreeId),
3003 lc, share_ret);
3004 if (rc < 0)
3005 goto err_out;
3006 }
3007
3008 if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)
3009 ksmbd_fd_set_delete_on_close(fp, file_info);
3010
3011 if (need_truncate) {
3012 rc = smb2_create_truncate(&path);
3013 if (rc)
3014 goto err_out;
3015 }
3016
3017 if (req->CreateContextsOffset) {
3018 struct create_alloc_size_req *az_req;
3019
Namjae Jeon070fb212021-05-26 17:57:12 +09003020 az_req = (struct create_alloc_size_req *)smb2_find_context_vals(req,
3021 SMB2_CREATE_ALLOCATION_SIZE);
Namjae Jeonf19b3962021-07-13 09:59:34 +09003022 if (IS_ERR(az_req)) {
3023 rc = PTR_ERR(az_req);
3024 goto err_out;
3025 } else if (az_req) {
Namjae Jeone2f34482021-03-16 10:49:09 +09003026 loff_t alloc_size = le64_to_cpu(az_req->AllocationSize);
3027 int err;
3028
3029 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09003030 "request smb2 create allocate size : %llu\n",
3031 alloc_size);
Namjae Jeone8c06192021-06-22 11:06:11 +09003032 smb_break_all_levII_oplock(work, fp, 1);
3033 err = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,
3034 alloc_size);
Namjae Jeone2f34482021-03-16 10:49:09 +09003035 if (err < 0)
3036 ksmbd_debug(SMB,
Namjae Jeone8c06192021-06-22 11:06:11 +09003037 "vfs_fallocate is failed : %d\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09003038 err);
Namjae Jeone2f34482021-03-16 10:49:09 +09003039 }
3040
Namjae Jeon64b39f42021-03-30 14:25:35 +09003041 context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID);
Namjae Jeonf19b3962021-07-13 09:59:34 +09003042 if (IS_ERR(context)) {
3043 rc = PTR_ERR(context);
3044 goto err_out;
3045 } else if (context) {
Namjae Jeone2f34482021-03-16 10:49:09 +09003046 ksmbd_debug(SMB, "get query on disk id context\n");
3047 query_disk_id = 1;
3048 }
3049 }
3050
3051 if (stat.result_mask & STATX_BTIME)
3052 fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
3053 else
3054 fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
3055 if (req->FileAttributes || fp->f_ci->m_fattr == 0)
Namjae Jeon070fb212021-05-26 17:57:12 +09003056 fp->f_ci->m_fattr =
3057 cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
Namjae Jeone2f34482021-03-16 10:49:09 +09003058
3059 if (!created)
3060 smb2_update_xattrs(tcon, &path, fp);
3061 else
3062 smb2_new_xattrs(tcon, &path, fp);
3063
3064 memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
3065
Hyunchul Lee465d7202021-07-03 12:10:36 +09003066 generic_fillattr(user_ns, file_inode(fp->filp),
Hyunchul Leeaf349832021-06-30 18:25:53 +09003067 &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09003068
3069 rsp->StructureSize = cpu_to_le16(89);
3070 rcu_read_lock();
3071 opinfo = rcu_dereference(fp->f_opinfo);
3072 rsp->OplockLevel = opinfo != NULL ? opinfo->level : 0;
3073 rcu_read_unlock();
3074 rsp->Reserved = 0;
3075 rsp->CreateAction = cpu_to_le32(file_info);
3076 rsp->CreationTime = cpu_to_le64(fp->create_time);
3077 time = ksmbd_UnixTimeToNT(stat.atime);
3078 rsp->LastAccessTime = cpu_to_le64(time);
3079 time = ksmbd_UnixTimeToNT(stat.mtime);
3080 rsp->LastWriteTime = cpu_to_le64(time);
3081 time = ksmbd_UnixTimeToNT(stat.ctime);
3082 rsp->ChangeTime = cpu_to_le64(time);
3083 rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :
3084 cpu_to_le64(stat.blocks << 9);
3085 rsp->EndofFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
3086 rsp->FileAttributes = fp->f_ci->m_fattr;
3087
3088 rsp->Reserved2 = 0;
3089
3090 rsp->PersistentFileId = cpu_to_le64(fp->persistent_id);
3091 rsp->VolatileFileId = cpu_to_le64(fp->volatile_id);
3092
3093 rsp->CreateContextsOffset = 0;
3094 rsp->CreateContextsLength = 0;
3095 inc_rfc1001_len(rsp_org, 88); /* StructureSize - 1*/
3096
3097 /* If lease is request send lease context response */
3098 if (opinfo && opinfo->is_lease) {
3099 struct create_context *lease_ccontext;
3100
3101 ksmbd_debug(SMB, "lease granted on(%s) lease state 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09003102 name, opinfo->o_lease->state);
Namjae Jeone2f34482021-03-16 10:49:09 +09003103 rsp->OplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
3104
3105 lease_ccontext = (struct create_context *)rsp->Buffer;
3106 contxt_cnt++;
3107 create_lease_buf(rsp->Buffer, opinfo->o_lease);
3108 le32_add_cpu(&rsp->CreateContextsLength,
3109 conn->vals->create_lease_size);
3110 inc_rfc1001_len(rsp_org, conn->vals->create_lease_size);
3111 next_ptr = &lease_ccontext->Next;
3112 next_off = conn->vals->create_lease_size;
3113 }
3114
Namjae Jeone2f34482021-03-16 10:49:09 +09003115 if (maximal_access_ctxt) {
3116 struct create_context *mxac_ccontext;
3117
3118 if (maximal_access == 0)
Hyunchul Lee465d7202021-07-03 12:10:36 +09003119 ksmbd_vfs_query_maximal_access(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09003120 path.dentry,
Namjae Jeone2f34482021-03-16 10:49:09 +09003121 &maximal_access);
3122 mxac_ccontext = (struct create_context *)(rsp->Buffer +
3123 le32_to_cpu(rsp->CreateContextsLength));
3124 contxt_cnt++;
3125 create_mxac_rsp_buf(rsp->Buffer +
3126 le32_to_cpu(rsp->CreateContextsLength),
3127 le32_to_cpu(maximal_access));
3128 le32_add_cpu(&rsp->CreateContextsLength,
3129 conn->vals->create_mxac_size);
3130 inc_rfc1001_len(rsp_org, conn->vals->create_mxac_size);
3131 if (next_ptr)
3132 *next_ptr = cpu_to_le32(next_off);
3133 next_ptr = &mxac_ccontext->Next;
3134 next_off = conn->vals->create_mxac_size;
3135 }
3136
3137 if (query_disk_id) {
3138 struct create_context *disk_id_ccontext;
3139
3140 disk_id_ccontext = (struct create_context *)(rsp->Buffer +
3141 le32_to_cpu(rsp->CreateContextsLength));
3142 contxt_cnt++;
3143 create_disk_id_rsp_buf(rsp->Buffer +
3144 le32_to_cpu(rsp->CreateContextsLength),
3145 stat.ino, tcon->id);
3146 le32_add_cpu(&rsp->CreateContextsLength,
3147 conn->vals->create_disk_id_size);
3148 inc_rfc1001_len(rsp_org, conn->vals->create_disk_id_size);
3149 if (next_ptr)
3150 *next_ptr = cpu_to_le32(next_off);
3151 next_ptr = &disk_id_ccontext->Next;
3152 next_off = conn->vals->create_disk_id_size;
3153 }
3154
3155 if (posix_ctxt) {
Namjae Jeone2f34482021-03-16 10:49:09 +09003156 contxt_cnt++;
3157 create_posix_rsp_buf(rsp->Buffer +
3158 le32_to_cpu(rsp->CreateContextsLength),
3159 fp);
3160 le32_add_cpu(&rsp->CreateContextsLength,
3161 conn->vals->create_posix_size);
3162 inc_rfc1001_len(rsp_org, conn->vals->create_posix_size);
3163 if (next_ptr)
3164 *next_ptr = cpu_to_le32(next_off);
3165 }
3166
3167 if (contxt_cnt > 0) {
3168 rsp->CreateContextsOffset =
3169 cpu_to_le32(offsetof(struct smb2_create_rsp, Buffer)
3170 - 4);
3171 }
3172
3173err_out:
3174 if (file_present || created)
3175 path_put(&path);
3176 ksmbd_revert_fsids(work);
3177err_out1:
3178 if (rc) {
3179 if (rc == -EINVAL)
3180 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
3181 else if (rc == -EOPNOTSUPP)
3182 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
Namjae Jeonff1d5722021-04-13 13:18:10 +09003183 else if (rc == -EACCES || rc == -ESTALE)
Namjae Jeone2f34482021-03-16 10:49:09 +09003184 rsp->hdr.Status = STATUS_ACCESS_DENIED;
3185 else if (rc == -ENOENT)
3186 rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID;
3187 else if (rc == -EPERM)
3188 rsp->hdr.Status = STATUS_SHARING_VIOLATION;
3189 else if (rc == -EBUSY)
3190 rsp->hdr.Status = STATUS_DELETE_PENDING;
3191 else if (rc == -EBADF)
3192 rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND;
3193 else if (rc == -ENOEXEC)
3194 rsp->hdr.Status = STATUS_DUPLICATE_OBJECTID;
3195 else if (rc == -ENXIO)
3196 rsp->hdr.Status = STATUS_NO_SUCH_DEVICE;
3197 else if (rc == -EEXIST)
3198 rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION;
3199 else if (rc == -EMFILE)
3200 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
3201 if (!rsp->hdr.Status)
3202 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
3203
3204 if (!fp || !fp->filename)
3205 kfree(name);
3206 if (fp)
3207 ksmbd_fd_put(work, fp);
3208 smb2_set_err_rsp(work);
3209 ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status);
3210 }
3211
3212 kfree(lc);
3213
3214 return 0;
3215}
3216
3217static int readdir_info_level_struct_sz(int info_level)
3218{
3219 switch (info_level) {
3220 case FILE_FULL_DIRECTORY_INFORMATION:
3221 return sizeof(struct file_full_directory_info);
3222 case FILE_BOTH_DIRECTORY_INFORMATION:
3223 return sizeof(struct file_both_directory_info);
3224 case FILE_DIRECTORY_INFORMATION:
3225 return sizeof(struct file_directory_info);
3226 case FILE_NAMES_INFORMATION:
3227 return sizeof(struct file_names_info);
3228 case FILEID_FULL_DIRECTORY_INFORMATION:
3229 return sizeof(struct file_id_full_dir_info);
3230 case FILEID_BOTH_DIRECTORY_INFORMATION:
3231 return sizeof(struct file_id_both_directory_info);
3232 case SMB_FIND_FILE_POSIX_INFO:
3233 return sizeof(struct smb2_posix_info);
3234 default:
3235 return -EOPNOTSUPP;
3236 }
3237}
3238
3239static int dentry_name(struct ksmbd_dir_info *d_info, int info_level)
3240{
3241 switch (info_level) {
3242 case FILE_FULL_DIRECTORY_INFORMATION:
3243 {
3244 struct file_full_directory_info *ffdinfo;
3245
3246 ffdinfo = (struct file_full_directory_info *)d_info->rptr;
3247 d_info->rptr += le32_to_cpu(ffdinfo->NextEntryOffset);
3248 d_info->name = ffdinfo->FileName;
3249 d_info->name_len = le32_to_cpu(ffdinfo->FileNameLength);
3250 return 0;
3251 }
3252 case FILE_BOTH_DIRECTORY_INFORMATION:
3253 {
3254 struct file_both_directory_info *fbdinfo;
3255
3256 fbdinfo = (struct file_both_directory_info *)d_info->rptr;
3257 d_info->rptr += le32_to_cpu(fbdinfo->NextEntryOffset);
3258 d_info->name = fbdinfo->FileName;
3259 d_info->name_len = le32_to_cpu(fbdinfo->FileNameLength);
3260 return 0;
3261 }
3262 case FILE_DIRECTORY_INFORMATION:
3263 {
3264 struct file_directory_info *fdinfo;
3265
3266 fdinfo = (struct file_directory_info *)d_info->rptr;
3267 d_info->rptr += le32_to_cpu(fdinfo->NextEntryOffset);
3268 d_info->name = fdinfo->FileName;
3269 d_info->name_len = le32_to_cpu(fdinfo->FileNameLength);
3270 return 0;
3271 }
3272 case FILE_NAMES_INFORMATION:
3273 {
3274 struct file_names_info *fninfo;
3275
3276 fninfo = (struct file_names_info *)d_info->rptr;
3277 d_info->rptr += le32_to_cpu(fninfo->NextEntryOffset);
3278 d_info->name = fninfo->FileName;
3279 d_info->name_len = le32_to_cpu(fninfo->FileNameLength);
3280 return 0;
3281 }
3282 case FILEID_FULL_DIRECTORY_INFORMATION:
3283 {
3284 struct file_id_full_dir_info *dinfo;
3285
3286 dinfo = (struct file_id_full_dir_info *)d_info->rptr;
3287 d_info->rptr += le32_to_cpu(dinfo->NextEntryOffset);
3288 d_info->name = dinfo->FileName;
3289 d_info->name_len = le32_to_cpu(dinfo->FileNameLength);
3290 return 0;
3291 }
3292 case FILEID_BOTH_DIRECTORY_INFORMATION:
3293 {
3294 struct file_id_both_directory_info *fibdinfo;
3295
3296 fibdinfo = (struct file_id_both_directory_info *)d_info->rptr;
3297 d_info->rptr += le32_to_cpu(fibdinfo->NextEntryOffset);
3298 d_info->name = fibdinfo->FileName;
3299 d_info->name_len = le32_to_cpu(fibdinfo->FileNameLength);
3300 return 0;
3301 }
3302 case SMB_FIND_FILE_POSIX_INFO:
3303 {
3304 struct smb2_posix_info *posix_info;
3305
3306 posix_info = (struct smb2_posix_info *)d_info->rptr;
3307 d_info->rptr += le32_to_cpu(posix_info->NextEntryOffset);
3308 d_info->name = posix_info->name;
3309 d_info->name_len = le32_to_cpu(posix_info->name_len);
3310 return 0;
3311 }
3312 default:
3313 return -EINVAL;
3314 }
3315}
3316
3317/**
3318 * smb2_populate_readdir_entry() - encode directory entry in smb2 response
3319 * buffer
3320 * @conn: connection instance
3321 * @info_level: smb information level
3322 * @d_info: structure included variables for query dir
Hyunchul Leeaf349832021-06-30 18:25:53 +09003323 * @user_ns: user namespace
Namjae Jeone2f34482021-03-16 10:49:09 +09003324 * @ksmbd_kstat: ksmbd wrapper of dirent stat information
3325 *
3326 * if directory has many entries, find first can't read it fully.
3327 * find next might be called multiple times to read remaining dir entries
3328 *
3329 * Return: 0 on success, otherwise error
3330 */
Namjae Jeon64b39f42021-03-30 14:25:35 +09003331static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
Namjae Jeon070fb212021-05-26 17:57:12 +09003332 struct ksmbd_dir_info *d_info,
3333 struct ksmbd_kstat *ksmbd_kstat)
Namjae Jeone2f34482021-03-16 10:49:09 +09003334{
3335 int next_entry_offset = 0;
3336 char *conv_name;
3337 int conv_len;
3338 void *kstat;
Namjae Jeondac0ec62021-07-07 14:57:24 +09003339 int struct_sz, rc = 0;
Namjae Jeone2f34482021-03-16 10:49:09 +09003340
3341 conv_name = ksmbd_convert_dir_info_name(d_info,
3342 conn->local_nls,
3343 &conv_len);
3344 if (!conv_name)
3345 return -ENOMEM;
3346
3347 /* Somehow the name has only terminating NULL bytes */
3348 if (conv_len < 0) {
Namjae Jeondac0ec62021-07-07 14:57:24 +09003349 rc = -EINVAL;
3350 goto free_conv_name;
Namjae Jeone2f34482021-03-16 10:49:09 +09003351 }
3352
3353 struct_sz = readdir_info_level_struct_sz(info_level);
3354 next_entry_offset = ALIGN(struct_sz - 1 + conv_len,
3355 KSMBD_DIR_INFO_ALIGNMENT);
3356
3357 if (next_entry_offset > d_info->out_buf_len) {
3358 d_info->out_buf_len = 0;
Namjae Jeondac0ec62021-07-07 14:57:24 +09003359 rc = -ENOSPC;
3360 goto free_conv_name;
Namjae Jeone2f34482021-03-16 10:49:09 +09003361 }
3362
3363 kstat = d_info->wptr;
3364 if (info_level != FILE_NAMES_INFORMATION)
3365 kstat = ksmbd_vfs_init_kstat(&d_info->wptr, ksmbd_kstat);
3366
3367 switch (info_level) {
3368 case FILE_FULL_DIRECTORY_INFORMATION:
3369 {
3370 struct file_full_directory_info *ffdinfo;
3371
3372 ffdinfo = (struct file_full_directory_info *)kstat;
3373 ffdinfo->FileNameLength = cpu_to_le32(conv_len);
3374 ffdinfo->EaSize =
3375 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);
3376 if (ffdinfo->EaSize)
3377 ffdinfo->ExtFileAttributes = ATTR_REPARSE_POINT_LE;
3378 if (d_info->hide_dot_file && d_info->name[0] == '.')
3379 ffdinfo->ExtFileAttributes |= ATTR_HIDDEN_LE;
3380 memcpy(ffdinfo->FileName, conv_name, conv_len);
3381 ffdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3382 break;
3383 }
3384 case FILE_BOTH_DIRECTORY_INFORMATION:
3385 {
3386 struct file_both_directory_info *fbdinfo;
3387
3388 fbdinfo = (struct file_both_directory_info *)kstat;
3389 fbdinfo->FileNameLength = cpu_to_le32(conv_len);
3390 fbdinfo->EaSize =
3391 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);
3392 if (fbdinfo->EaSize)
3393 fbdinfo->ExtFileAttributes = ATTR_REPARSE_POINT_LE;
3394 fbdinfo->ShortNameLength = 0;
3395 fbdinfo->Reserved = 0;
3396 if (d_info->hide_dot_file && d_info->name[0] == '.')
3397 fbdinfo->ExtFileAttributes |= ATTR_HIDDEN_LE;
3398 memcpy(fbdinfo->FileName, conv_name, conv_len);
3399 fbdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3400 break;
3401 }
3402 case FILE_DIRECTORY_INFORMATION:
3403 {
3404 struct file_directory_info *fdinfo;
3405
3406 fdinfo = (struct file_directory_info *)kstat;
3407 fdinfo->FileNameLength = cpu_to_le32(conv_len);
3408 if (d_info->hide_dot_file && d_info->name[0] == '.')
3409 fdinfo->ExtFileAttributes |= ATTR_HIDDEN_LE;
3410 memcpy(fdinfo->FileName, conv_name, conv_len);
3411 fdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3412 break;
3413 }
3414 case FILE_NAMES_INFORMATION:
3415 {
3416 struct file_names_info *fninfo;
3417
3418 fninfo = (struct file_names_info *)kstat;
3419 fninfo->FileNameLength = cpu_to_le32(conv_len);
3420 memcpy(fninfo->FileName, conv_name, conv_len);
3421 fninfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3422 break;
3423 }
3424 case FILEID_FULL_DIRECTORY_INFORMATION:
3425 {
3426 struct file_id_full_dir_info *dinfo;
3427
3428 dinfo = (struct file_id_full_dir_info *)kstat;
3429 dinfo->FileNameLength = cpu_to_le32(conv_len);
3430 dinfo->EaSize =
3431 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);
3432 if (dinfo->EaSize)
3433 dinfo->ExtFileAttributes = ATTR_REPARSE_POINT_LE;
3434 dinfo->Reserved = 0;
3435 dinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);
3436 if (d_info->hide_dot_file && d_info->name[0] == '.')
3437 dinfo->ExtFileAttributes |= ATTR_HIDDEN_LE;
3438 memcpy(dinfo->FileName, conv_name, conv_len);
3439 dinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3440 break;
3441 }
3442 case FILEID_BOTH_DIRECTORY_INFORMATION:
3443 {
3444 struct file_id_both_directory_info *fibdinfo;
3445
3446 fibdinfo = (struct file_id_both_directory_info *)kstat;
3447 fibdinfo->FileNameLength = cpu_to_le32(conv_len);
3448 fibdinfo->EaSize =
3449 smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);
3450 if (fibdinfo->EaSize)
3451 fibdinfo->ExtFileAttributes = ATTR_REPARSE_POINT_LE;
3452 fibdinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);
3453 fibdinfo->ShortNameLength = 0;
3454 fibdinfo->Reserved = 0;
3455 fibdinfo->Reserved2 = cpu_to_le16(0);
3456 if (d_info->hide_dot_file && d_info->name[0] == '.')
3457 fibdinfo->ExtFileAttributes |= ATTR_HIDDEN_LE;
3458 memcpy(fibdinfo->FileName, conv_name, conv_len);
3459 fibdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3460 break;
3461 }
3462 case SMB_FIND_FILE_POSIX_INFO:
3463 {
3464 struct smb2_posix_info *posix_info;
3465 u64 time;
3466
3467 posix_info = (struct smb2_posix_info *)kstat;
3468 posix_info->Ignored = 0;
3469 posix_info->CreationTime = cpu_to_le64(ksmbd_kstat->create_time);
3470 time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime);
3471 posix_info->ChangeTime = cpu_to_le64(time);
3472 time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->atime);
3473 posix_info->LastAccessTime = cpu_to_le64(time);
3474 time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->mtime);
3475 posix_info->LastWriteTime = cpu_to_le64(time);
3476 posix_info->EndOfFile = cpu_to_le64(ksmbd_kstat->kstat->size);
3477 posix_info->AllocationSize = cpu_to_le64(ksmbd_kstat->kstat->blocks << 9);
3478 posix_info->DeviceId = cpu_to_le32(ksmbd_kstat->kstat->rdev);
3479 posix_info->HardLinks = cpu_to_le32(ksmbd_kstat->kstat->nlink);
3480 posix_info->Mode = cpu_to_le32(ksmbd_kstat->kstat->mode);
3481 posix_info->Inode = cpu_to_le64(ksmbd_kstat->kstat->ino);
3482 posix_info->DosAttributes =
3483 S_ISDIR(ksmbd_kstat->kstat->mode) ? ATTR_DIRECTORY_LE : ATTR_ARCHIVE_LE;
3484 if (d_info->hide_dot_file && d_info->name[0] == '.')
3485 posix_info->DosAttributes |= ATTR_HIDDEN_LE;
Christian Brauner475d6f92021-08-23 17:13:48 +02003486 id_to_sid(from_kuid_munged(&init_user_ns, ksmbd_kstat->kstat->uid),
Namjae Jeon070fb212021-05-26 17:57:12 +09003487 SIDNFS_USER, (struct smb_sid *)&posix_info->SidBuffer[0]);
Christian Brauner475d6f92021-08-23 17:13:48 +02003488 id_to_sid(from_kgid_munged(&init_user_ns, ksmbd_kstat->kstat->gid),
Namjae Jeon070fb212021-05-26 17:57:12 +09003489 SIDNFS_GROUP, (struct smb_sid *)&posix_info->SidBuffer[20]);
Namjae Jeone2f34482021-03-16 10:49:09 +09003490 memcpy(posix_info->name, conv_name, conv_len);
3491 posix_info->name_len = cpu_to_le32(conv_len);
3492 posix_info->NextEntryOffset = cpu_to_le32(next_entry_offset);
3493 break;
3494 }
3495
3496 } /* switch (info_level) */
3497
3498 d_info->last_entry_offset = d_info->data_count;
3499 d_info->data_count += next_entry_offset;
Marios Makassikise7735c82021-05-06 11:40:02 +09003500 d_info->out_buf_len -= next_entry_offset;
Namjae Jeone2f34482021-03-16 10:49:09 +09003501 d_info->wptr += next_entry_offset;
Namjae Jeone2f34482021-03-16 10:49:09 +09003502
3503 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09003504 "info_level : %d, buf_len :%d, next_offset : %d, data_count : %d\n",
3505 info_level, d_info->out_buf_len,
3506 next_entry_offset, d_info->data_count);
Namjae Jeone2f34482021-03-16 10:49:09 +09003507
Namjae Jeondac0ec62021-07-07 14:57:24 +09003508free_conv_name:
3509 kfree(conv_name);
3510 return rc;
Namjae Jeone2f34482021-03-16 10:49:09 +09003511}
3512
3513struct smb2_query_dir_private {
3514 struct ksmbd_work *work;
3515 char *search_pattern;
3516 struct ksmbd_file *dir_fp;
3517
3518 struct ksmbd_dir_info *d_info;
3519 int info_level;
3520};
3521
3522static void lock_dir(struct ksmbd_file *dir_fp)
3523{
3524 struct dentry *dir = dir_fp->filp->f_path.dentry;
3525
3526 inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
3527}
3528
3529static void unlock_dir(struct ksmbd_file *dir_fp)
3530{
3531 struct dentry *dir = dir_fp->filp->f_path.dentry;
3532
3533 inode_unlock(d_inode(dir));
3534}
3535
3536static int process_query_dir_entries(struct smb2_query_dir_private *priv)
3537{
Hyunchul Lee465d7202021-07-03 12:10:36 +09003538 struct user_namespace *user_ns = file_mnt_user_ns(priv->dir_fp->filp);
Namjae Jeone2f34482021-03-16 10:49:09 +09003539 struct kstat kstat;
3540 struct ksmbd_kstat ksmbd_kstat;
3541 int rc;
3542 int i;
3543
3544 for (i = 0; i < priv->d_info->num_entry; i++) {
3545 struct dentry *dent;
3546
3547 if (dentry_name(priv->d_info, priv->info_level))
3548 return -EINVAL;
3549
3550 lock_dir(priv->dir_fp);
Christian Braunerda1e7ad2021-08-23 17:13:47 +02003551 dent = lookup_one(user_ns, priv->d_info->name,
3552 priv->dir_fp->filp->f_path.dentry,
3553 priv->d_info->name_len);
Namjae Jeone2f34482021-03-16 10:49:09 +09003554 unlock_dir(priv->dir_fp);
3555
3556 if (IS_ERR(dent)) {
3557 ksmbd_debug(SMB, "Cannot lookup `%s' [%ld]\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09003558 priv->d_info->name,
3559 PTR_ERR(dent));
Namjae Jeone2f34482021-03-16 10:49:09 +09003560 continue;
3561 }
3562 if (unlikely(d_is_negative(dent))) {
3563 dput(dent);
3564 ksmbd_debug(SMB, "Negative dentry `%s'\n",
3565 priv->d_info->name);
3566 continue;
3567 }
3568
3569 ksmbd_kstat.kstat = &kstat;
3570 if (priv->info_level != FILE_NAMES_INFORMATION)
3571 ksmbd_vfs_fill_dentry_attrs(priv->work,
Hyunchul Lee465d7202021-07-03 12:10:36 +09003572 user_ns,
Namjae Jeone2f34482021-03-16 10:49:09 +09003573 dent,
3574 &ksmbd_kstat);
3575
3576 rc = smb2_populate_readdir_entry(priv->work->conn,
3577 priv->info_level,
3578 priv->d_info,
3579 &ksmbd_kstat);
3580 dput(dent);
3581 if (rc)
3582 return rc;
3583 }
3584 return 0;
3585}
3586
3587static int reserve_populate_dentry(struct ksmbd_dir_info *d_info,
Namjae Jeon070fb212021-05-26 17:57:12 +09003588 int info_level)
Namjae Jeone2f34482021-03-16 10:49:09 +09003589{
3590 int struct_sz;
3591 int conv_len;
3592 int next_entry_offset;
3593
3594 struct_sz = readdir_info_level_struct_sz(info_level);
3595 if (struct_sz == -EOPNOTSUPP)
3596 return -EOPNOTSUPP;
3597
3598 conv_len = (d_info->name_len + 1) * 2;
3599 next_entry_offset = ALIGN(struct_sz - 1 + conv_len,
3600 KSMBD_DIR_INFO_ALIGNMENT);
3601
3602 if (next_entry_offset > d_info->out_buf_len) {
3603 d_info->out_buf_len = 0;
3604 return -ENOSPC;
3605 }
3606
3607 switch (info_level) {
3608 case FILE_FULL_DIRECTORY_INFORMATION:
3609 {
3610 struct file_full_directory_info *ffdinfo;
3611
3612 ffdinfo = (struct file_full_directory_info *)d_info->wptr;
3613 memcpy(ffdinfo->FileName, d_info->name, d_info->name_len);
3614 ffdinfo->FileName[d_info->name_len] = 0x00;
3615 ffdinfo->FileNameLength = cpu_to_le32(d_info->name_len);
3616 ffdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3617 break;
3618 }
3619 case FILE_BOTH_DIRECTORY_INFORMATION:
3620 {
3621 struct file_both_directory_info *fbdinfo;
3622
3623 fbdinfo = (struct file_both_directory_info *)d_info->wptr;
3624 memcpy(fbdinfo->FileName, d_info->name, d_info->name_len);
3625 fbdinfo->FileName[d_info->name_len] = 0x00;
3626 fbdinfo->FileNameLength = cpu_to_le32(d_info->name_len);
3627 fbdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3628 break;
3629 }
3630 case FILE_DIRECTORY_INFORMATION:
3631 {
3632 struct file_directory_info *fdinfo;
3633
3634 fdinfo = (struct file_directory_info *)d_info->wptr;
3635 memcpy(fdinfo->FileName, d_info->name, d_info->name_len);
3636 fdinfo->FileName[d_info->name_len] = 0x00;
3637 fdinfo->FileNameLength = cpu_to_le32(d_info->name_len);
3638 fdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3639 break;
3640 }
3641 case FILE_NAMES_INFORMATION:
3642 {
3643 struct file_names_info *fninfo;
3644
3645 fninfo = (struct file_names_info *)d_info->wptr;
3646 memcpy(fninfo->FileName, d_info->name, d_info->name_len);
3647 fninfo->FileName[d_info->name_len] = 0x00;
3648 fninfo->FileNameLength = cpu_to_le32(d_info->name_len);
3649 fninfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3650 break;
3651 }
3652 case FILEID_FULL_DIRECTORY_INFORMATION:
3653 {
3654 struct file_id_full_dir_info *dinfo;
3655
3656 dinfo = (struct file_id_full_dir_info *)d_info->wptr;
3657 memcpy(dinfo->FileName, d_info->name, d_info->name_len);
3658 dinfo->FileName[d_info->name_len] = 0x00;
3659 dinfo->FileNameLength = cpu_to_le32(d_info->name_len);
3660 dinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3661 break;
3662 }
3663 case FILEID_BOTH_DIRECTORY_INFORMATION:
3664 {
3665 struct file_id_both_directory_info *fibdinfo;
3666
3667 fibdinfo = (struct file_id_both_directory_info *)d_info->wptr;
3668 memcpy(fibdinfo->FileName, d_info->name, d_info->name_len);
3669 fibdinfo->FileName[d_info->name_len] = 0x00;
3670 fibdinfo->FileNameLength = cpu_to_le32(d_info->name_len);
3671 fibdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset);
3672 break;
3673 }
3674 case SMB_FIND_FILE_POSIX_INFO:
3675 {
3676 struct smb2_posix_info *posix_info;
3677
3678 posix_info = (struct smb2_posix_info *)d_info->wptr;
3679 memcpy(posix_info->name, d_info->name, d_info->name_len);
3680 posix_info->name[d_info->name_len] = 0x00;
3681 posix_info->name_len = cpu_to_le32(d_info->name_len);
3682 posix_info->NextEntryOffset =
3683 cpu_to_le32(next_entry_offset);
3684 break;
3685 }
3686 } /* switch (info_level) */
3687
3688 d_info->num_entry++;
3689 d_info->out_buf_len -= next_entry_offset;
3690 d_info->wptr += next_entry_offset;
3691 return 0;
3692}
3693
Namjae Jeon64b39f42021-03-30 14:25:35 +09003694static int __query_dir(struct dir_context *ctx, const char *name, int namlen,
Namjae Jeon070fb212021-05-26 17:57:12 +09003695 loff_t offset, u64 ino, unsigned int d_type)
Namjae Jeone2f34482021-03-16 10:49:09 +09003696{
3697 struct ksmbd_readdir_data *buf;
3698 struct smb2_query_dir_private *priv;
3699 struct ksmbd_dir_info *d_info;
3700 int rc;
3701
3702 buf = container_of(ctx, struct ksmbd_readdir_data, ctx);
3703 priv = buf->private;
3704 d_info = priv->d_info;
3705
3706 /* dot and dotdot entries are already reserved */
3707 if (!strcmp(".", name) || !strcmp("..", name))
3708 return 0;
3709 if (ksmbd_share_veto_filename(priv->work->tcon->share_conf, name))
3710 return 0;
Namjae Jeonb24c9332021-03-21 17:32:19 +09003711 if (!match_pattern(name, namlen, priv->search_pattern))
Namjae Jeone2f34482021-03-16 10:49:09 +09003712 return 0;
3713
3714 d_info->name = name;
3715 d_info->name_len = namlen;
3716 rc = reserve_populate_dentry(d_info, priv->info_level);
3717 if (rc)
3718 return rc;
3719 if (d_info->flags & SMB2_RETURN_SINGLE_ENTRY) {
3720 d_info->out_buf_len = 0;
3721 return 0;
3722 }
3723 return 0;
3724}
3725
3726static void restart_ctx(struct dir_context *ctx)
3727{
3728 ctx->pos = 0;
3729}
3730
3731static int verify_info_level(int info_level)
3732{
3733 switch (info_level) {
3734 case FILE_FULL_DIRECTORY_INFORMATION:
3735 case FILE_BOTH_DIRECTORY_INFORMATION:
3736 case FILE_DIRECTORY_INFORMATION:
3737 case FILE_NAMES_INFORMATION:
3738 case FILEID_FULL_DIRECTORY_INFORMATION:
3739 case FILEID_BOTH_DIRECTORY_INFORMATION:
3740 case SMB_FIND_FILE_POSIX_INFO:
3741 break;
3742 default:
3743 return -EOPNOTSUPP;
3744 }
3745
3746 return 0;
3747}
3748
3749int smb2_query_dir(struct ksmbd_work *work)
3750{
3751 struct ksmbd_conn *conn = work->conn;
3752 struct smb2_query_directory_req *req;
3753 struct smb2_query_directory_rsp *rsp, *rsp_org;
3754 struct ksmbd_share_config *share = work->tcon->share_conf;
3755 struct ksmbd_file *dir_fp = NULL;
3756 struct ksmbd_dir_info d_info;
3757 int rc = 0;
3758 char *srch_ptr = NULL;
3759 unsigned char srch_flag;
3760 int buffer_sz;
3761 struct smb2_query_dir_private query_dir_private = {NULL, };
3762
Namjae Jeone5066492021-03-30 12:35:23 +09003763 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09003764 WORK_BUFFERS(work, req, rsp);
3765
3766 if (ksmbd_override_fsids(work)) {
3767 rsp->hdr.Status = STATUS_NO_MEMORY;
3768 smb2_set_err_rsp(work);
3769 return -ENOMEM;
3770 }
3771
3772 rc = verify_info_level(req->FileInformationClass);
3773 if (rc) {
3774 rc = -EFAULT;
3775 goto err_out2;
3776 }
3777
3778 dir_fp = ksmbd_lookup_fd_slow(work,
Namjae Jeon070fb212021-05-26 17:57:12 +09003779 le64_to_cpu(req->VolatileFileId),
3780 le64_to_cpu(req->PersistentFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09003781 if (!dir_fp) {
3782 rc = -EBADF;
3783 goto err_out2;
3784 }
3785
3786 if (!(dir_fp->daccess & FILE_LIST_DIRECTORY_LE) ||
Hyunchul Leeaf349832021-06-30 18:25:53 +09003787 inode_permission(file_mnt_user_ns(dir_fp->filp),
3788 file_inode(dir_fp->filp),
Namjae Jeon070fb212021-05-26 17:57:12 +09003789 MAY_READ | MAY_EXEC)) {
Namjae Jeon493fa2f2021-06-29 09:22:16 +09003790 pr_err("no right to enumerate directory (%pd)\n",
3791 dir_fp->filp->f_path.dentry);
Namjae Jeone2f34482021-03-16 10:49:09 +09003792 rc = -EACCES;
3793 goto err_out2;
3794 }
3795
3796 if (!S_ISDIR(file_inode(dir_fp->filp)->i_mode)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09003797 pr_err("can't do query dir for a file\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09003798 rc = -EINVAL;
3799 goto err_out2;
3800 }
3801
3802 srch_flag = req->Flags;
3803 srch_ptr = smb_strndup_from_utf16(req->Buffer,
Namjae Jeon070fb212021-05-26 17:57:12 +09003804 le16_to_cpu(req->FileNameLength), 1,
3805 conn->local_nls);
Namjae Jeone2f34482021-03-16 10:49:09 +09003806 if (IS_ERR(srch_ptr)) {
3807 ksmbd_debug(SMB, "Search Pattern not found\n");
3808 rc = -EINVAL;
3809 goto err_out2;
Namjae Jeon64b39f42021-03-30 14:25:35 +09003810 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09003811 ksmbd_debug(SMB, "Search pattern is %s\n", srch_ptr);
Namjae Jeon64b39f42021-03-30 14:25:35 +09003812 }
Namjae Jeone2f34482021-03-16 10:49:09 +09003813
3814 ksmbd_debug(SMB, "Directory name is %s\n", dir_fp->filename);
3815
3816 if (srch_flag & SMB2_REOPEN || srch_flag & SMB2_RESTART_SCANS) {
3817 ksmbd_debug(SMB, "Restart directory scan\n");
3818 generic_file_llseek(dir_fp->filp, 0, SEEK_SET);
3819 restart_ctx(&dir_fp->readdir_data.ctx);
3820 }
3821
3822 memset(&d_info, 0, sizeof(struct ksmbd_dir_info));
3823 d_info.wptr = (char *)rsp->Buffer;
3824 d_info.rptr = (char *)rsp->Buffer;
Namjae Jeon64b39f42021-03-30 14:25:35 +09003825 d_info.out_buf_len = (work->response_sz - (get_rfc1002_len(rsp_org) + 4));
Namjae Jeon070fb212021-05-26 17:57:12 +09003826 d_info.out_buf_len = min_t(int, d_info.out_buf_len, le32_to_cpu(req->OutputBufferLength)) -
3827 sizeof(struct smb2_query_directory_rsp);
Namjae Jeone2f34482021-03-16 10:49:09 +09003828 d_info.flags = srch_flag;
3829
3830 /*
3831 * reserve dot and dotdot entries in head of buffer
3832 * in first response
3833 */
3834 rc = ksmbd_populate_dot_dotdot_entries(work, req->FileInformationClass,
Namjae Jeon070fb212021-05-26 17:57:12 +09003835 dir_fp, &d_info, srch_ptr,
3836 smb2_populate_readdir_entry);
Namjae Jeone2f34482021-03-16 10:49:09 +09003837 if (rc == -ENOSPC)
3838 rc = 0;
3839 else if (rc)
3840 goto err_out;
3841
3842 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_HIDE_DOT_FILES))
3843 d_info.hide_dot_file = true;
3844
3845 buffer_sz = d_info.out_buf_len;
3846 d_info.rptr = d_info.wptr;
3847 query_dir_private.work = work;
3848 query_dir_private.search_pattern = srch_ptr;
3849 query_dir_private.dir_fp = dir_fp;
3850 query_dir_private.d_info = &d_info;
3851 query_dir_private.info_level = req->FileInformationClass;
3852 dir_fp->readdir_data.private = &query_dir_private;
3853 set_ctx_actor(&dir_fp->readdir_data.ctx, __query_dir);
3854
Namjae Jeone8c06192021-06-22 11:06:11 +09003855 rc = iterate_dir(dir_fp->filp, &dir_fp->readdir_data.ctx);
Namjae Jeone2f34482021-03-16 10:49:09 +09003856 if (rc == 0)
3857 restart_ctx(&dir_fp->readdir_data.ctx);
3858 if (rc == -ENOSPC)
3859 rc = 0;
3860 if (rc)
3861 goto err_out;
3862
3863 d_info.wptr = d_info.rptr;
3864 d_info.out_buf_len = buffer_sz;
3865 rc = process_query_dir_entries(&query_dir_private);
3866 if (rc)
3867 goto err_out;
3868
3869 if (!d_info.data_count && d_info.out_buf_len >= 0) {
Namjae Jeon64b39f42021-03-30 14:25:35 +09003870 if (srch_flag & SMB2_RETURN_SINGLE_ENTRY && !is_asterisk(srch_ptr)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09003871 rsp->hdr.Status = STATUS_NO_SUCH_FILE;
Namjae Jeon64b39f42021-03-30 14:25:35 +09003872 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09003873 dir_fp->dot_dotdot[0] = dir_fp->dot_dotdot[1] = 0;
3874 rsp->hdr.Status = STATUS_NO_MORE_FILES;
3875 }
3876 rsp->StructureSize = cpu_to_le16(9);
3877 rsp->OutputBufferOffset = cpu_to_le16(0);
3878 rsp->OutputBufferLength = cpu_to_le32(0);
3879 rsp->Buffer[0] = 0;
3880 inc_rfc1001_len(rsp_org, 9);
3881 } else {
3882 ((struct file_directory_info *)
3883 ((char *)rsp->Buffer + d_info.last_entry_offset))
3884 ->NextEntryOffset = 0;
3885
3886 rsp->StructureSize = cpu_to_le16(9);
3887 rsp->OutputBufferOffset = cpu_to_le16(72);
3888 rsp->OutputBufferLength = cpu_to_le32(d_info.data_count);
3889 inc_rfc1001_len(rsp_org, 8 + d_info.data_count);
3890 }
3891
3892 kfree(srch_ptr);
3893 ksmbd_fd_put(work, dir_fp);
3894 ksmbd_revert_fsids(work);
3895 return 0;
3896
3897err_out:
Namjae Jeonbde16942021-06-28 15:23:19 +09003898 pr_err("error while processing smb2 query dir rc = %d\n", rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09003899 kfree(srch_ptr);
3900
3901err_out2:
3902 if (rc == -EINVAL)
3903 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
3904 else if (rc == -EACCES)
3905 rsp->hdr.Status = STATUS_ACCESS_DENIED;
3906 else if (rc == -ENOENT)
3907 rsp->hdr.Status = STATUS_NO_SUCH_FILE;
3908 else if (rc == -EBADF)
3909 rsp->hdr.Status = STATUS_FILE_CLOSED;
3910 else if (rc == -ENOMEM)
3911 rsp->hdr.Status = STATUS_NO_MEMORY;
3912 else if (rc == -EFAULT)
3913 rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;
3914 if (!rsp->hdr.Status)
3915 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
3916
3917 smb2_set_err_rsp(work);
3918 ksmbd_fd_put(work, dir_fp);
3919 ksmbd_revert_fsids(work);
3920 return 0;
3921}
3922
3923/**
3924 * buffer_check_err() - helper function to check buffer errors
3925 * @reqOutputBufferLength: max buffer length expected in command response
3926 * @rsp: query info response buffer contains output buffer length
3927 * @infoclass_size: query info class response buffer size
3928 *
3929 * Return: 0 on success, otherwise error
3930 */
3931static int buffer_check_err(int reqOutputBufferLength,
Namjae Jeon070fb212021-05-26 17:57:12 +09003932 struct smb2_query_info_rsp *rsp, int infoclass_size)
Namjae Jeone2f34482021-03-16 10:49:09 +09003933{
3934 if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) {
3935 if (reqOutputBufferLength < infoclass_size) {
Namjae Jeonbde16942021-06-28 15:23:19 +09003936 pr_err("Invalid Buffer Size Requested\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09003937 rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH;
Namjae Jeon64b39f42021-03-30 14:25:35 +09003938 rsp->hdr.smb2_buf_length = cpu_to_be32(sizeof(struct smb2_hdr) - 4);
Namjae Jeone2f34482021-03-16 10:49:09 +09003939 return -EINVAL;
3940 }
3941
3942 ksmbd_debug(SMB, "Buffer Overflow\n");
3943 rsp->hdr.Status = STATUS_BUFFER_OVERFLOW;
Namjae Jeon64b39f42021-03-30 14:25:35 +09003944 rsp->hdr.smb2_buf_length = cpu_to_be32(sizeof(struct smb2_hdr) - 4 +
3945 reqOutputBufferLength);
3946 rsp->OutputBufferLength = cpu_to_le32(reqOutputBufferLength);
Namjae Jeone2f34482021-03-16 10:49:09 +09003947 }
3948 return 0;
3949}
3950
3951static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp)
3952{
3953 struct smb2_file_standard_info *sinfo;
3954
3955 sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
3956
3957 sinfo->AllocationSize = cpu_to_le64(4096);
3958 sinfo->EndOfFile = cpu_to_le64(0);
3959 sinfo->NumberOfLinks = cpu_to_le32(1);
3960 sinfo->DeletePending = 1;
3961 sinfo->Directory = 0;
3962 rsp->OutputBufferLength =
3963 cpu_to_le32(sizeof(struct smb2_file_standard_info));
3964 inc_rfc1001_len(rsp, sizeof(struct smb2_file_standard_info));
3965}
3966
Namjae Jeon070fb212021-05-26 17:57:12 +09003967static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num)
Namjae Jeone2f34482021-03-16 10:49:09 +09003968{
3969 struct smb2_file_internal_info *file_info;
3970
3971 file_info = (struct smb2_file_internal_info *)rsp->Buffer;
3972
3973 /* any unique number */
3974 file_info->IndexNumber = cpu_to_le64(num | (1ULL << 63));
3975 rsp->OutputBufferLength =
3976 cpu_to_le32(sizeof(struct smb2_file_internal_info));
3977 inc_rfc1001_len(rsp, sizeof(struct smb2_file_internal_info));
3978}
3979
Namjae Jeone2f34482021-03-16 10:49:09 +09003980static int smb2_get_info_file_pipe(struct ksmbd_session *sess,
Namjae Jeon070fb212021-05-26 17:57:12 +09003981 struct smb2_query_info_req *req,
3982 struct smb2_query_info_rsp *rsp)
Namjae Jeone2f34482021-03-16 10:49:09 +09003983{
Namjae Jeon64b39f42021-03-30 14:25:35 +09003984 u64 id;
Namjae Jeone2f34482021-03-16 10:49:09 +09003985 int rc;
3986
3987 /*
3988 * Windows can sometime send query file info request on
3989 * pipe without opening it, checking error condition here
3990 */
3991 id = le64_to_cpu(req->VolatileFileId);
3992 if (!ksmbd_session_rpc_method(sess, id))
3993 return -ENOENT;
3994
3995 ksmbd_debug(SMB, "FileInfoClass %u, FileId 0x%llx\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09003996 req->FileInfoClass, le64_to_cpu(req->VolatileFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09003997
3998 switch (req->FileInfoClass) {
3999 case FILE_STANDARD_INFORMATION:
4000 get_standard_info_pipe(rsp);
4001 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
Namjae Jeon070fb212021-05-26 17:57:12 +09004002 rsp, FILE_STANDARD_INFORMATION_SIZE);
Namjae Jeone2f34482021-03-16 10:49:09 +09004003 break;
4004 case FILE_INTERNAL_INFORMATION:
4005 get_internal_info_pipe(rsp, id);
4006 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
Namjae Jeon070fb212021-05-26 17:57:12 +09004007 rsp, FILE_INTERNAL_INFORMATION_SIZE);
Namjae Jeone2f34482021-03-16 10:49:09 +09004008 break;
4009 default:
4010 ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09004011 req->FileInfoClass);
Namjae Jeone2f34482021-03-16 10:49:09 +09004012 rc = -EOPNOTSUPP;
4013 }
4014 return rc;
4015}
4016
4017/**
4018 * smb2_get_ea() - handler for smb2 get extended attribute command
4019 * @work: smb work containing query info command buffer
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +09004020 * @fp: ksmbd_file pointer
4021 * @req: get extended attribute request
4022 * @rsp: response buffer pointer
4023 * @rsp_org: base response buffer pointer in case of chained response
Namjae Jeone2f34482021-03-16 10:49:09 +09004024 *
4025 * Return: 0 on success, otherwise error
4026 */
Namjae Jeon64b39f42021-03-30 14:25:35 +09004027static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004028 struct smb2_query_info_req *req,
4029 struct smb2_query_info_rsp *rsp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004030{
4031 struct smb2_ea_info *eainfo, *prev_eainfo;
4032 char *name, *ptr, *xattr_list = NULL, *buf;
4033 int rc, name_len, value_len, xattr_list_len, idx;
4034 ssize_t buf_free_len, alignment_bytes, next_offset, rsp_data_cnt = 0;
4035 struct smb2_ea_info_req *ea_req = NULL;
4036 struct path *path;
Hyunchul Lee465d7202021-07-03 12:10:36 +09004037 struct user_namespace *user_ns = file_mnt_user_ns(fp->filp);
Namjae Jeone2f34482021-03-16 10:49:09 +09004038
4039 if (!(fp->daccess & FILE_READ_EA_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004040 pr_err("Not permitted to read ext attr : 0x%x\n",
4041 fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09004042 return -EACCES;
4043 }
4044
4045 path = &fp->filp->f_path;
4046 /* single EA entry is requested with given user.* name */
Namjae Jeon64b39f42021-03-30 14:25:35 +09004047 if (req->InputBufferLength) {
Namjae Jeon6d562622021-09-18 18:45:12 +09004048 if (le32_to_cpu(req->InputBufferLength) <
4049 sizeof(struct smb2_ea_info_req))
4050 return -EINVAL;
4051
Namjae Jeone2f34482021-03-16 10:49:09 +09004052 ea_req = (struct smb2_ea_info_req *)req->Buffer;
Namjae Jeon64b39f42021-03-30 14:25:35 +09004053 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09004054 /* need to send all EAs, if no specific EA is requested*/
4055 if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY)
4056 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09004057 "All EAs are requested but need to send single EA entry in rsp flags 0x%x\n",
4058 le32_to_cpu(req->Flags));
Namjae Jeone2f34482021-03-16 10:49:09 +09004059 }
4060
4061 buf_free_len = work->response_sz -
4062 (get_rfc1002_len(rsp_org) + 4) -
4063 sizeof(struct smb2_query_info_rsp);
4064
4065 if (le32_to_cpu(req->OutputBufferLength) < buf_free_len)
4066 buf_free_len = le32_to_cpu(req->OutputBufferLength);
4067
4068 rc = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
4069 if (rc < 0) {
4070 rsp->hdr.Status = STATUS_INVALID_HANDLE;
4071 goto out;
4072 } else if (!rc) { /* there is no EA in the file */
4073 ksmbd_debug(SMB, "no ea data in the file\n");
4074 goto done;
4075 }
4076 xattr_list_len = rc;
4077
4078 ptr = (char *)rsp->Buffer;
4079 eainfo = (struct smb2_ea_info *)ptr;
4080 prev_eainfo = eainfo;
4081 idx = 0;
4082
4083 while (idx < xattr_list_len) {
4084 name = xattr_list + idx;
4085 name_len = strlen(name);
4086
4087 ksmbd_debug(SMB, "%s, len %d\n", name, name_len);
4088 idx += name_len + 1;
4089
4090 /*
4091 * CIFS does not support EA other than user.* namespace,
4092 * still keep the framework generic, to list other attrs
4093 * in future.
4094 */
4095 if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
4096 continue;
4097
4098 if (!strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,
Namjae Jeon64b39f42021-03-30 14:25:35 +09004099 STREAM_PREFIX_LEN))
Namjae Jeone2f34482021-03-16 10:49:09 +09004100 continue;
4101
4102 if (req->InputBufferLength &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09004103 strncmp(&name[XATTR_USER_PREFIX_LEN], ea_req->name,
4104 ea_req->EaNameLength))
Namjae Jeone2f34482021-03-16 10:49:09 +09004105 continue;
4106
4107 if (!strncmp(&name[XATTR_USER_PREFIX_LEN],
Namjae Jeon64b39f42021-03-30 14:25:35 +09004108 DOS_ATTRIBUTE_PREFIX, DOS_ATTRIBUTE_PREFIX_LEN))
Namjae Jeone2f34482021-03-16 10:49:09 +09004109 continue;
4110
4111 if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
4112 name_len -= XATTR_USER_PREFIX_LEN;
4113
4114 ptr = (char *)(&eainfo->name + name_len + 1);
4115 buf_free_len -= (offsetof(struct smb2_ea_info, name) +
4116 name_len + 1);
4117 /* bailout if xattr can't fit in buf_free_len */
Hyunchul Lee465d7202021-07-03 12:10:36 +09004118 value_len = ksmbd_vfs_getxattr(user_ns, path->dentry,
4119 name, &buf);
Namjae Jeone2f34482021-03-16 10:49:09 +09004120 if (value_len <= 0) {
4121 rc = -ENOENT;
4122 rsp->hdr.Status = STATUS_INVALID_HANDLE;
4123 goto out;
4124 }
4125
4126 buf_free_len -= value_len;
4127 if (buf_free_len < 0) {
Namjae Jeon79f6b112021-04-02 12:47:14 +09004128 kfree(buf);
Namjae Jeone2f34482021-03-16 10:49:09 +09004129 break;
4130 }
4131
4132 memcpy(ptr, buf, value_len);
Namjae Jeon79f6b112021-04-02 12:47:14 +09004133 kfree(buf);
Namjae Jeone2f34482021-03-16 10:49:09 +09004134
4135 ptr += value_len;
4136 eainfo->Flags = 0;
4137 eainfo->EaNameLength = name_len;
4138
Namjae Jeon64b39f42021-03-30 14:25:35 +09004139 if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
Namjae Jeone2f34482021-03-16 10:49:09 +09004140 memcpy(eainfo->name, &name[XATTR_USER_PREFIX_LEN],
Namjae Jeon070fb212021-05-26 17:57:12 +09004141 name_len);
Namjae Jeone2f34482021-03-16 10:49:09 +09004142 else
4143 memcpy(eainfo->name, name, name_len);
4144
4145 eainfo->name[name_len] = '\0';
4146 eainfo->EaValueLength = cpu_to_le16(value_len);
4147 next_offset = offsetof(struct smb2_ea_info, name) +
4148 name_len + 1 + value_len;
4149
4150 /* align next xattr entry at 4 byte bundary */
4151 alignment_bytes = ((next_offset + 3) & ~3) - next_offset;
4152 if (alignment_bytes) {
4153 memset(ptr, '\0', alignment_bytes);
4154 ptr += alignment_bytes;
4155 next_offset += alignment_bytes;
4156 buf_free_len -= alignment_bytes;
4157 }
4158 eainfo->NextEntryOffset = cpu_to_le32(next_offset);
4159 prev_eainfo = eainfo;
4160 eainfo = (struct smb2_ea_info *)ptr;
4161 rsp_data_cnt += next_offset;
4162
4163 if (req->InputBufferLength) {
4164 ksmbd_debug(SMB, "single entry requested\n");
4165 break;
4166 }
4167 }
4168
4169 /* no more ea entries */
4170 prev_eainfo->NextEntryOffset = 0;
4171done:
4172 rc = 0;
4173 if (rsp_data_cnt == 0)
4174 rsp->hdr.Status = STATUS_NO_EAS_ON_FILE;
4175 rsp->OutputBufferLength = cpu_to_le32(rsp_data_cnt);
4176 inc_rfc1001_len(rsp_org, rsp_data_cnt);
4177out:
Namjae Jeon79f6b112021-04-02 12:47:14 +09004178 kvfree(xattr_list);
Namjae Jeone2f34482021-03-16 10:49:09 +09004179 return rc;
4180}
4181
4182static void get_file_access_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004183 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004184{
4185 struct smb2_file_access_info *file_info;
4186
4187 file_info = (struct smb2_file_access_info *)rsp->Buffer;
4188 file_info->AccessFlags = fp->daccess;
4189 rsp->OutputBufferLength =
4190 cpu_to_le32(sizeof(struct smb2_file_access_info));
4191 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_access_info));
4192}
4193
4194static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004195 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004196{
4197 struct smb2_file_all_info *basic_info;
4198 struct kstat stat;
4199 u64 time;
4200
4201 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004202 pr_err("no right to read the attributes : 0x%x\n",
4203 fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09004204 return -EACCES;
4205 }
4206
4207 basic_info = (struct smb2_file_all_info *)rsp->Buffer;
Hyunchul Leeaf349832021-06-30 18:25:53 +09004208 generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp),
4209 &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09004210 basic_info->CreationTime = cpu_to_le64(fp->create_time);
4211 time = ksmbd_UnixTimeToNT(stat.atime);
4212 basic_info->LastAccessTime = cpu_to_le64(time);
4213 time = ksmbd_UnixTimeToNT(stat.mtime);
4214 basic_info->LastWriteTime = cpu_to_le64(time);
4215 time = ksmbd_UnixTimeToNT(stat.ctime);
4216 basic_info->ChangeTime = cpu_to_le64(time);
4217 basic_info->Attributes = fp->f_ci->m_fattr;
4218 basic_info->Pad1 = 0;
4219 rsp->OutputBufferLength =
Namjae Jeon64b39f42021-03-30 14:25:35 +09004220 cpu_to_le32(offsetof(struct smb2_file_all_info, AllocationSize));
Namjae Jeone2f34482021-03-16 10:49:09 +09004221 inc_rfc1001_len(rsp_org, offsetof(struct smb2_file_all_info,
4222 AllocationSize));
4223 return 0;
4224}
4225
4226static unsigned long long get_allocation_size(struct inode *inode,
Namjae Jeon070fb212021-05-26 17:57:12 +09004227 struct kstat *stat)
Namjae Jeone2f34482021-03-16 10:49:09 +09004228{
4229 unsigned long long alloc_size = 0;
4230
4231 if (!S_ISDIR(stat->mode)) {
4232 if ((inode->i_blocks << 9) <= stat->size)
4233 alloc_size = stat->size;
4234 else
4235 alloc_size = inode->i_blocks << 9;
Namjae Jeone2f34482021-03-16 10:49:09 +09004236 }
4237
4238 return alloc_size;
4239}
4240
4241static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004242 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004243{
4244 struct smb2_file_standard_info *sinfo;
4245 unsigned int delete_pending;
4246 struct inode *inode;
4247 struct kstat stat;
4248
Namjae Jeonab0b2632021-06-29 09:20:13 +09004249 inode = file_inode(fp->filp);
Hyunchul Leeaf349832021-06-30 18:25:53 +09004250 generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09004251
4252 sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
4253 delete_pending = ksmbd_inode_pending_delete(fp);
4254
4255 sinfo->AllocationSize = cpu_to_le64(get_allocation_size(inode, &stat));
4256 sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
4257 sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);
4258 sinfo->DeletePending = delete_pending;
4259 sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0;
4260 rsp->OutputBufferLength =
4261 cpu_to_le32(sizeof(struct smb2_file_standard_info));
4262 inc_rfc1001_len(rsp_org,
4263 sizeof(struct smb2_file_standard_info));
4264}
4265
4266static void get_file_alignment_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004267 void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004268{
4269 struct smb2_file_alignment_info *file_info;
4270
4271 file_info = (struct smb2_file_alignment_info *)rsp->Buffer;
4272 file_info->AlignmentRequirement = 0;
4273 rsp->OutputBufferLength =
4274 cpu_to_le32(sizeof(struct smb2_file_alignment_info));
4275 inc_rfc1001_len(rsp_org,
4276 sizeof(struct smb2_file_alignment_info));
4277}
4278
4279static int get_file_all_info(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09004280 struct smb2_query_info_rsp *rsp,
4281 struct ksmbd_file *fp,
4282 void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004283{
4284 struct ksmbd_conn *conn = work->conn;
4285 struct smb2_file_all_info *file_info;
4286 unsigned int delete_pending;
4287 struct inode *inode;
4288 struct kstat stat;
4289 int conv_len;
4290 char *filename;
4291 u64 time;
4292
4293 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
4294 ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09004295 fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09004296 return -EACCES;
4297 }
4298
4299 filename = convert_to_nt_pathname(fp->filename,
4300 work->tcon->share_conf->path);
4301 if (!filename)
4302 return -ENOMEM;
4303
Namjae Jeonab0b2632021-06-29 09:20:13 +09004304 inode = file_inode(fp->filp);
Hyunchul Leeaf349832021-06-30 18:25:53 +09004305 generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09004306
4307 ksmbd_debug(SMB, "filename = %s\n", filename);
4308 delete_pending = ksmbd_inode_pending_delete(fp);
4309 file_info = (struct smb2_file_all_info *)rsp->Buffer;
4310
4311 file_info->CreationTime = cpu_to_le64(fp->create_time);
4312 time = ksmbd_UnixTimeToNT(stat.atime);
4313 file_info->LastAccessTime = cpu_to_le64(time);
4314 time = ksmbd_UnixTimeToNT(stat.mtime);
4315 file_info->LastWriteTime = cpu_to_le64(time);
4316 time = ksmbd_UnixTimeToNT(stat.ctime);
4317 file_info->ChangeTime = cpu_to_le64(time);
4318 file_info->Attributes = fp->f_ci->m_fattr;
4319 file_info->Pad1 = 0;
4320 file_info->AllocationSize =
4321 cpu_to_le64(get_allocation_size(inode, &stat));
4322 file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
4323 file_info->NumberOfLinks =
4324 cpu_to_le32(get_nlink(&stat) - delete_pending);
4325 file_info->DeletePending = delete_pending;
4326 file_info->Directory = S_ISDIR(stat.mode) ? 1 : 0;
4327 file_info->Pad2 = 0;
4328 file_info->IndexNumber = cpu_to_le64(stat.ino);
4329 file_info->EASize = 0;
4330 file_info->AccessFlags = fp->daccess;
4331 file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
4332 file_info->Mode = fp->coption;
4333 file_info->AlignmentRequirement = 0;
Namjae Jeon070fb212021-05-26 17:57:12 +09004334 conv_len = smbConvertToUTF16((__le16 *)file_info->FileName, filename,
4335 PATH_MAX, conn->local_nls, 0);
Namjae Jeone2f34482021-03-16 10:49:09 +09004336 conv_len *= 2;
4337 file_info->FileNameLength = cpu_to_le32(conv_len);
4338 rsp->OutputBufferLength =
4339 cpu_to_le32(sizeof(struct smb2_file_all_info) + conv_len - 1);
4340 kfree(filename);
4341 inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength));
4342 return 0;
4343}
4344
4345static void get_file_alternate_info(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09004346 struct smb2_query_info_rsp *rsp,
4347 struct ksmbd_file *fp,
4348 void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004349{
4350 struct ksmbd_conn *conn = work->conn;
4351 struct smb2_file_alt_name_info *file_info;
Namjae Jeon493fa2f2021-06-29 09:22:16 +09004352 struct dentry *dentry = fp->filp->f_path.dentry;
Namjae Jeone2f34482021-03-16 10:49:09 +09004353 int conv_len;
Namjae Jeone2f34482021-03-16 10:49:09 +09004354
Namjae Jeon493fa2f2021-06-29 09:22:16 +09004355 spin_lock(&dentry->d_lock);
Namjae Jeone2f34482021-03-16 10:49:09 +09004356 file_info = (struct smb2_file_alt_name_info *)rsp->Buffer;
4357 conv_len = ksmbd_extract_shortname(conn,
Namjae Jeon493fa2f2021-06-29 09:22:16 +09004358 dentry->d_name.name,
Namjae Jeone2f34482021-03-16 10:49:09 +09004359 file_info->FileName);
Namjae Jeon493fa2f2021-06-29 09:22:16 +09004360 spin_unlock(&dentry->d_lock);
Namjae Jeone2f34482021-03-16 10:49:09 +09004361 file_info->FileNameLength = cpu_to_le32(conv_len);
4362 rsp->OutputBufferLength =
4363 cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len);
4364 inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength));
4365}
4366
4367static void get_file_stream_info(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09004368 struct smb2_query_info_rsp *rsp,
4369 struct ksmbd_file *fp,
4370 void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004371{
4372 struct ksmbd_conn *conn = work->conn;
4373 struct smb2_file_stream_info *file_info;
4374 char *stream_name, *xattr_list = NULL, *stream_buf;
4375 struct kstat stat;
4376 struct path *path = &fp->filp->f_path;
4377 ssize_t xattr_list_len;
4378 int nbytes = 0, streamlen, stream_name_len, next, idx = 0;
4379
Hyunchul Leeaf349832021-06-30 18:25:53 +09004380 generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp),
4381 &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09004382 file_info = (struct smb2_file_stream_info *)rsp->Buffer;
4383
4384 xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
4385 if (xattr_list_len < 0) {
4386 goto out;
4387 } else if (!xattr_list_len) {
4388 ksmbd_debug(SMB, "empty xattr in the file\n");
4389 goto out;
4390 }
4391
4392 while (idx < xattr_list_len) {
4393 stream_name = xattr_list + idx;
4394 streamlen = strlen(stream_name);
4395 idx += streamlen + 1;
4396
4397 ksmbd_debug(SMB, "%s, len %d\n", stream_name, streamlen);
4398
4399 if (strncmp(&stream_name[XATTR_USER_PREFIX_LEN],
Namjae Jeon64b39f42021-03-30 14:25:35 +09004400 STREAM_PREFIX, STREAM_PREFIX_LEN))
Namjae Jeone2f34482021-03-16 10:49:09 +09004401 continue;
4402
4403 stream_name_len = streamlen - (XATTR_USER_PREFIX_LEN +
4404 STREAM_PREFIX_LEN);
4405 streamlen = stream_name_len;
4406
4407 /* plus : size */
4408 streamlen += 1;
4409 stream_buf = kmalloc(streamlen + 1, GFP_KERNEL);
4410 if (!stream_buf)
4411 break;
4412
4413 streamlen = snprintf(stream_buf, streamlen + 1,
Namjae Jeon070fb212021-05-26 17:57:12 +09004414 ":%s", &stream_name[XATTR_NAME_STREAM_LEN]);
Namjae Jeone2f34482021-03-16 10:49:09 +09004415
Namjae Jeon070fb212021-05-26 17:57:12 +09004416 file_info = (struct smb2_file_stream_info *)&rsp->Buffer[nbytes];
Namjae Jeone2f34482021-03-16 10:49:09 +09004417 streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName,
Namjae Jeon070fb212021-05-26 17:57:12 +09004418 stream_buf, streamlen,
4419 conn->local_nls, 0);
Namjae Jeone2f34482021-03-16 10:49:09 +09004420 streamlen *= 2;
4421 kfree(stream_buf);
4422 file_info->StreamNameLength = cpu_to_le32(streamlen);
4423 file_info->StreamSize = cpu_to_le64(stream_name_len);
4424 file_info->StreamAllocationSize = cpu_to_le64(stream_name_len);
4425
4426 next = sizeof(struct smb2_file_stream_info) + streamlen;
4427 nbytes += next;
4428 file_info->NextEntryOffset = cpu_to_le32(next);
4429 }
4430
4431 if (nbytes) {
4432 file_info = (struct smb2_file_stream_info *)
4433 &rsp->Buffer[nbytes];
4434 streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName,
Namjae Jeon070fb212021-05-26 17:57:12 +09004435 "::$DATA", 7, conn->local_nls, 0);
Namjae Jeone2f34482021-03-16 10:49:09 +09004436 streamlen *= 2;
4437 file_info->StreamNameLength = cpu_to_le32(streamlen);
4438 file_info->StreamSize = S_ISDIR(stat.mode) ? 0 :
4439 cpu_to_le64(stat.size);
4440 file_info->StreamAllocationSize = S_ISDIR(stat.mode) ? 0 :
4441 cpu_to_le64(stat.size);
4442 nbytes += sizeof(struct smb2_file_stream_info) + streamlen;
4443 }
4444
4445 /* last entry offset should be 0 */
4446 file_info->NextEntryOffset = 0;
4447out:
Namjae Jeon79f6b112021-04-02 12:47:14 +09004448 kvfree(xattr_list);
Namjae Jeone2f34482021-03-16 10:49:09 +09004449
4450 rsp->OutputBufferLength = cpu_to_le32(nbytes);
4451 inc_rfc1001_len(rsp_org, nbytes);
4452}
4453
4454static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004455 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004456{
4457 struct smb2_file_internal_info *file_info;
4458 struct kstat stat;
4459
Hyunchul Leeaf349832021-06-30 18:25:53 +09004460 generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp),
4461 &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09004462 file_info = (struct smb2_file_internal_info *)rsp->Buffer;
4463 file_info->IndexNumber = cpu_to_le64(stat.ino);
4464 rsp->OutputBufferLength =
4465 cpu_to_le32(sizeof(struct smb2_file_internal_info));
4466 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info));
4467}
4468
4469static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004470 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004471{
4472 struct smb2_file_ntwrk_info *file_info;
4473 struct inode *inode;
4474 struct kstat stat;
4475 u64 time;
4476
4477 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004478 pr_err("no right to read the attributes : 0x%x\n",
4479 fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09004480 return -EACCES;
4481 }
4482
4483 file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;
4484
Namjae Jeonab0b2632021-06-29 09:20:13 +09004485 inode = file_inode(fp->filp);
Hyunchul Leeaf349832021-06-30 18:25:53 +09004486 generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09004487
4488 file_info->CreationTime = cpu_to_le64(fp->create_time);
4489 time = ksmbd_UnixTimeToNT(stat.atime);
4490 file_info->LastAccessTime = cpu_to_le64(time);
4491 time = ksmbd_UnixTimeToNT(stat.mtime);
4492 file_info->LastWriteTime = cpu_to_le64(time);
4493 time = ksmbd_UnixTimeToNT(stat.ctime);
4494 file_info->ChangeTime = cpu_to_le64(time);
4495 file_info->Attributes = fp->f_ci->m_fattr;
4496 file_info->AllocationSize =
4497 cpu_to_le64(get_allocation_size(inode, &stat));
4498 file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
4499 file_info->Reserved = cpu_to_le32(0);
4500 rsp->OutputBufferLength =
4501 cpu_to_le32(sizeof(struct smb2_file_ntwrk_info));
4502 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ntwrk_info));
4503 return 0;
4504}
4505
Namjae Jeon64b39f42021-03-30 14:25:35 +09004506static void get_file_ea_info(struct smb2_query_info_rsp *rsp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004507{
4508 struct smb2_file_ea_info *file_info;
4509
4510 file_info = (struct smb2_file_ea_info *)rsp->Buffer;
4511 file_info->EASize = 0;
4512 rsp->OutputBufferLength =
4513 cpu_to_le32(sizeof(struct smb2_file_ea_info));
4514 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ea_info));
4515}
4516
4517static void get_file_position_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004518 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004519{
4520 struct smb2_file_pos_info *file_info;
4521
4522 file_info = (struct smb2_file_pos_info *)rsp->Buffer;
4523 file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
4524 rsp->OutputBufferLength =
4525 cpu_to_le32(sizeof(struct smb2_file_pos_info));
4526 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_pos_info));
4527}
4528
4529static void get_file_mode_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004530 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004531{
4532 struct smb2_file_mode_info *file_info;
4533
4534 file_info = (struct smb2_file_mode_info *)rsp->Buffer;
4535 file_info->Mode = fp->coption & FILE_MODE_INFO_MASK;
4536 rsp->OutputBufferLength =
4537 cpu_to_le32(sizeof(struct smb2_file_mode_info));
4538 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_mode_info));
4539}
4540
4541static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004542 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004543{
4544 struct smb2_file_comp_info *file_info;
4545 struct kstat stat;
4546
Hyunchul Leeaf349832021-06-30 18:25:53 +09004547 generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp),
4548 &stat);
Namjae Jeone2f34482021-03-16 10:49:09 +09004549
4550 file_info = (struct smb2_file_comp_info *)rsp->Buffer;
4551 file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9);
4552 file_info->CompressionFormat = COMPRESSION_FORMAT_NONE;
4553 file_info->CompressionUnitShift = 0;
4554 file_info->ChunkShift = 0;
4555 file_info->ClusterShift = 0;
4556 memset(&file_info->Reserved[0], 0, 3);
4557
4558 rsp->OutputBufferLength =
4559 cpu_to_le32(sizeof(struct smb2_file_comp_info));
4560 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_comp_info));
4561}
4562
4563static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004564 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004565{
4566 struct smb2_file_attr_tag_info *file_info;
4567
4568 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004569 pr_err("no right to read the attributes : 0x%x\n",
4570 fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09004571 return -EACCES;
4572 }
4573
4574 file_info = (struct smb2_file_attr_tag_info *)rsp->Buffer;
4575 file_info->FileAttributes = fp->f_ci->m_fattr;
4576 file_info->ReparseTag = 0;
4577 rsp->OutputBufferLength =
4578 cpu_to_le32(sizeof(struct smb2_file_attr_tag_info));
Namjae Jeon070fb212021-05-26 17:57:12 +09004579 inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_attr_tag_info));
Namjae Jeone2f34482021-03-16 10:49:09 +09004580 return 0;
4581}
4582
4583static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09004584 struct ksmbd_file *fp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004585{
4586 struct smb311_posix_qinfo *file_info;
Namjae Jeonab0b2632021-06-29 09:20:13 +09004587 struct inode *inode = file_inode(fp->filp);
Namjae Jeone2f34482021-03-16 10:49:09 +09004588 u64 time;
4589
4590 file_info = (struct smb311_posix_qinfo *)rsp->Buffer;
4591 file_info->CreationTime = cpu_to_le64(fp->create_time);
4592 time = ksmbd_UnixTimeToNT(inode->i_atime);
4593 file_info->LastAccessTime = cpu_to_le64(time);
4594 time = ksmbd_UnixTimeToNT(inode->i_mtime);
4595 file_info->LastWriteTime = cpu_to_le64(time);
4596 time = ksmbd_UnixTimeToNT(inode->i_ctime);
4597 file_info->ChangeTime = cpu_to_le64(time);
4598 file_info->DosAttributes = fp->f_ci->m_fattr;
4599 file_info->Inode = cpu_to_le64(inode->i_ino);
4600 file_info->EndOfFile = cpu_to_le64(inode->i_size);
4601 file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
4602 file_info->HardLinks = cpu_to_le32(inode->i_nlink);
4603 file_info->Mode = cpu_to_le32(inode->i_mode);
4604 file_info->DeviceId = cpu_to_le32(inode->i_rdev);
4605 rsp->OutputBufferLength =
4606 cpu_to_le32(sizeof(struct smb311_posix_qinfo));
Namjae Jeon64b39f42021-03-30 14:25:35 +09004607 inc_rfc1001_len(rsp_org, sizeof(struct smb311_posix_qinfo));
Namjae Jeone2f34482021-03-16 10:49:09 +09004608 return 0;
4609}
4610
Namjae Jeone2f34482021-03-16 10:49:09 +09004611static int smb2_get_info_file(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09004612 struct smb2_query_info_req *req,
4613 struct smb2_query_info_rsp *rsp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004614{
4615 struct ksmbd_file *fp;
4616 int fileinfoclass = 0;
4617 int rc = 0;
4618 int file_infoclass_size;
4619 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
4620
4621 if (test_share_config_flag(work->tcon->share_conf,
Namjae Jeon64b39f42021-03-30 14:25:35 +09004622 KSMBD_SHARE_FLAG_PIPE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09004623 /* smb2 info file called for pipe */
4624 return smb2_get_info_file_pipe(work->sess, req, rsp);
4625 }
4626
4627 if (work->next_smb2_rcv_hdr_off) {
Namjae Jeon38673692021-07-08 12:32:27 +09004628 if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
4629 ksmbd_debug(SMB, "Compound request set FID = %llu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09004630 work->compound_fid);
Namjae Jeone2f34482021-03-16 10:49:09 +09004631 id = work->compound_fid;
4632 pid = work->compound_pfid;
4633 }
4634 }
4635
Namjae Jeon38673692021-07-08 12:32:27 +09004636 if (!has_file_id(id)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09004637 id = le64_to_cpu(req->VolatileFileId);
4638 pid = le64_to_cpu(req->PersistentFileId);
4639 }
4640
4641 fp = ksmbd_lookup_fd_slow(work, id, pid);
4642 if (!fp)
4643 return -ENOENT;
4644
4645 fileinfoclass = req->FileInfoClass;
4646
4647 switch (fileinfoclass) {
4648 case FILE_ACCESS_INFORMATION:
4649 get_file_access_info(rsp, fp, rsp_org);
4650 file_infoclass_size = FILE_ACCESS_INFORMATION_SIZE;
4651 break;
4652
4653 case FILE_BASIC_INFORMATION:
4654 rc = get_file_basic_info(rsp, fp, rsp_org);
4655 file_infoclass_size = FILE_BASIC_INFORMATION_SIZE;
4656 break;
4657
4658 case FILE_STANDARD_INFORMATION:
4659 get_file_standard_info(rsp, fp, rsp_org);
4660 file_infoclass_size = FILE_STANDARD_INFORMATION_SIZE;
4661 break;
4662
4663 case FILE_ALIGNMENT_INFORMATION:
4664 get_file_alignment_info(rsp, rsp_org);
4665 file_infoclass_size = FILE_ALIGNMENT_INFORMATION_SIZE;
4666 break;
4667
4668 case FILE_ALL_INFORMATION:
4669 rc = get_file_all_info(work, rsp, fp, rsp_org);
4670 file_infoclass_size = FILE_ALL_INFORMATION_SIZE;
4671 break;
4672
4673 case FILE_ALTERNATE_NAME_INFORMATION:
4674 get_file_alternate_info(work, rsp, fp, rsp_org);
4675 file_infoclass_size = FILE_ALTERNATE_NAME_INFORMATION_SIZE;
4676 break;
4677
4678 case FILE_STREAM_INFORMATION:
4679 get_file_stream_info(work, rsp, fp, rsp_org);
4680 file_infoclass_size = FILE_STREAM_INFORMATION_SIZE;
4681 break;
4682
4683 case FILE_INTERNAL_INFORMATION:
4684 get_file_internal_info(rsp, fp, rsp_org);
4685 file_infoclass_size = FILE_INTERNAL_INFORMATION_SIZE;
4686 break;
4687
4688 case FILE_NETWORK_OPEN_INFORMATION:
4689 rc = get_file_network_open_info(rsp, fp, rsp_org);
4690 file_infoclass_size = FILE_NETWORK_OPEN_INFORMATION_SIZE;
4691 break;
4692
4693 case FILE_EA_INFORMATION:
4694 get_file_ea_info(rsp, rsp_org);
4695 file_infoclass_size = FILE_EA_INFORMATION_SIZE;
4696 break;
4697
4698 case FILE_FULL_EA_INFORMATION:
4699 rc = smb2_get_ea(work, fp, req, rsp, rsp_org);
4700 file_infoclass_size = FILE_FULL_EA_INFORMATION_SIZE;
4701 break;
4702
4703 case FILE_POSITION_INFORMATION:
4704 get_file_position_info(rsp, fp, rsp_org);
4705 file_infoclass_size = FILE_POSITION_INFORMATION_SIZE;
4706 break;
4707
4708 case FILE_MODE_INFORMATION:
4709 get_file_mode_info(rsp, fp, rsp_org);
4710 file_infoclass_size = FILE_MODE_INFORMATION_SIZE;
4711 break;
4712
4713 case FILE_COMPRESSION_INFORMATION:
4714 get_file_compression_info(rsp, fp, rsp_org);
4715 file_infoclass_size = FILE_COMPRESSION_INFORMATION_SIZE;
4716 break;
4717
4718 case FILE_ATTRIBUTE_TAG_INFORMATION:
4719 rc = get_file_attribute_tag_info(rsp, fp, rsp_org);
4720 file_infoclass_size = FILE_ATTRIBUTE_TAG_INFORMATION_SIZE;
4721 break;
4722 case SMB_FIND_FILE_POSIX_INFO:
4723 if (!work->tcon->posix_extensions) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004724 pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09004725 rc = -EOPNOTSUPP;
4726 } else {
4727 rc = find_file_posix_info(rsp, fp, rsp_org);
4728 file_infoclass_size = sizeof(struct smb311_posix_qinfo);
4729 }
4730 break;
4731 default:
4732 ksmbd_debug(SMB, "fileinfoclass %d not supported yet\n",
4733 fileinfoclass);
4734 rc = -EOPNOTSUPP;
4735 }
4736 if (!rc)
4737 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
4738 rsp,
4739 file_infoclass_size);
4740 ksmbd_fd_put(work, fp);
4741 return rc;
4742}
4743
Namjae Jeone2f34482021-03-16 10:49:09 +09004744static int smb2_get_info_filesystem(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09004745 struct smb2_query_info_req *req,
4746 struct smb2_query_info_rsp *rsp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004747{
4748 struct ksmbd_session *sess = work->sess;
4749 struct ksmbd_conn *conn = sess->conn;
4750 struct ksmbd_share_config *share = work->tcon->share_conf;
4751 int fsinfoclass = 0;
4752 struct kstatfs stfs;
4753 struct path path;
4754 int rc = 0, len;
4755 int fs_infoclass_size = 0;
Hyunchul Leea6a5fa72021-05-26 18:59:06 +09004756 int lookup_flags = 0;
Namjae Jeone2f34482021-03-16 10:49:09 +09004757
Hyunchul Leea6a5fa72021-05-26 18:59:06 +09004758 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
4759 lookup_flags = LOOKUP_FOLLOW;
4760
4761 rc = ksmbd_vfs_kern_path(share->path, lookup_flags, &path, 0);
Namjae Jeone2f34482021-03-16 10:49:09 +09004762 if (rc) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004763 pr_err("cannot create vfs path\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09004764 return -EIO;
4765 }
4766
4767 rc = vfs_statfs(&path, &stfs);
4768 if (rc) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004769 pr_err("cannot do stat of path %s\n", share->path);
Namjae Jeone2f34482021-03-16 10:49:09 +09004770 path_put(&path);
4771 return -EIO;
4772 }
4773
4774 fsinfoclass = req->FileInfoClass;
4775
4776 switch (fsinfoclass) {
4777 case FS_DEVICE_INFORMATION:
4778 {
4779 struct filesystem_device_info *info;
4780
4781 info = (struct filesystem_device_info *)rsp->Buffer;
4782
4783 info->DeviceType = cpu_to_le32(stfs.f_type);
4784 info->DeviceCharacteristics = cpu_to_le32(0x00000020);
4785 rsp->OutputBufferLength = cpu_to_le32(8);
4786 inc_rfc1001_len(rsp_org, 8);
4787 fs_infoclass_size = FS_DEVICE_INFORMATION_SIZE;
4788 break;
4789 }
4790 case FS_ATTRIBUTE_INFORMATION:
4791 {
4792 struct filesystem_attribute_info *info;
4793 size_t sz;
4794
4795 info = (struct filesystem_attribute_info *)rsp->Buffer;
4796 info->Attributes = cpu_to_le32(FILE_SUPPORTS_OBJECT_IDS |
4797 FILE_PERSISTENT_ACLS |
4798 FILE_UNICODE_ON_DISK |
4799 FILE_CASE_PRESERVED_NAMES |
Namjae Jeoneb817362021-05-18 10:37:59 +09004800 FILE_CASE_SENSITIVE_SEARCH |
4801 FILE_SUPPORTS_BLOCK_REFCOUNTING);
Namjae Jeone2f34482021-03-16 10:49:09 +09004802
4803 info->Attributes |= cpu_to_le32(server_conf.share_fake_fscaps);
4804
4805 info->MaxPathNameComponentLength = cpu_to_le32(stfs.f_namelen);
4806 len = smbConvertToUTF16((__le16 *)info->FileSystemName,
4807 "NTFS", PATH_MAX, conn->local_nls, 0);
4808 len = len * 2;
4809 info->FileSystemNameLen = cpu_to_le32(len);
4810 sz = sizeof(struct filesystem_attribute_info) - 2 + len;
4811 rsp->OutputBufferLength = cpu_to_le32(sz);
4812 inc_rfc1001_len(rsp_org, sz);
4813 fs_infoclass_size = FS_ATTRIBUTE_INFORMATION_SIZE;
4814 break;
4815 }
4816 case FS_VOLUME_INFORMATION:
4817 {
4818 struct filesystem_vol_info *info;
4819 size_t sz;
4820
4821 info = (struct filesystem_vol_info *)(rsp->Buffer);
4822 info->VolumeCreationTime = 0;
4823 /* Taking dummy value of serial number*/
4824 info->SerialNumber = cpu_to_le32(0xbc3ac512);
4825 len = smbConvertToUTF16((__le16 *)info->VolumeLabel,
4826 share->name, PATH_MAX,
4827 conn->local_nls, 0);
4828 len = len * 2;
4829 info->VolumeLabelSize = cpu_to_le32(len);
4830 info->Reserved = 0;
4831 sz = sizeof(struct filesystem_vol_info) - 2 + len;
4832 rsp->OutputBufferLength = cpu_to_le32(sz);
4833 inc_rfc1001_len(rsp_org, sz);
4834 fs_infoclass_size = FS_VOLUME_INFORMATION_SIZE;
4835 break;
4836 }
4837 case FS_SIZE_INFORMATION:
4838 {
4839 struct filesystem_info *info;
Namjae Jeone2f34482021-03-16 10:49:09 +09004840
4841 info = (struct filesystem_info *)(rsp->Buffer);
Namjae Jeone2f34482021-03-16 10:49:09 +09004842 info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks);
4843 info->FreeAllocationUnits = cpu_to_le64(stfs.f_bfree);
Namjae Jeonee81cae2021-06-26 22:32:34 +09004844 info->SectorsPerAllocationUnit = cpu_to_le32(1);
4845 info->BytesPerSector = cpu_to_le32(stfs.f_bsize);
Namjae Jeone2f34482021-03-16 10:49:09 +09004846 rsp->OutputBufferLength = cpu_to_le32(24);
4847 inc_rfc1001_len(rsp_org, 24);
4848 fs_infoclass_size = FS_SIZE_INFORMATION_SIZE;
4849 break;
4850 }
4851 case FS_FULL_SIZE_INFORMATION:
4852 {
4853 struct smb2_fs_full_size_info *info;
Namjae Jeone2f34482021-03-16 10:49:09 +09004854
4855 info = (struct smb2_fs_full_size_info *)(rsp->Buffer);
Namjae Jeone2f34482021-03-16 10:49:09 +09004856 info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks);
4857 info->CallerAvailableAllocationUnits =
4858 cpu_to_le64(stfs.f_bavail);
4859 info->ActualAvailableAllocationUnits =
4860 cpu_to_le64(stfs.f_bfree);
Namjae Jeonee81cae2021-06-26 22:32:34 +09004861 info->SectorsPerAllocationUnit = cpu_to_le32(1);
4862 info->BytesPerSector = cpu_to_le32(stfs.f_bsize);
Namjae Jeone2f34482021-03-16 10:49:09 +09004863 rsp->OutputBufferLength = cpu_to_le32(32);
4864 inc_rfc1001_len(rsp_org, 32);
4865 fs_infoclass_size = FS_FULL_SIZE_INFORMATION_SIZE;
4866 break;
4867 }
4868 case FS_OBJECT_ID_INFORMATION:
4869 {
4870 struct object_id_info *info;
4871
4872 info = (struct object_id_info *)(rsp->Buffer);
4873
4874 if (!user_guest(sess->user))
4875 memcpy(info->objid, user_passkey(sess->user), 16);
4876 else
4877 memset(info->objid, 0, 16);
4878
4879 info->extended_info.magic = cpu_to_le32(EXTENDED_INFO_MAGIC);
4880 info->extended_info.version = cpu_to_le32(1);
4881 info->extended_info.release = cpu_to_le32(1);
4882 info->extended_info.rel_date = 0;
Namjae Jeon64b39f42021-03-30 14:25:35 +09004883 memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0"));
Namjae Jeone2f34482021-03-16 10:49:09 +09004884 rsp->OutputBufferLength = cpu_to_le32(64);
4885 inc_rfc1001_len(rsp_org, 64);
4886 fs_infoclass_size = FS_OBJECT_ID_INFORMATION_SIZE;
4887 break;
4888 }
4889 case FS_SECTOR_SIZE_INFORMATION:
4890 {
4891 struct smb3_fs_ss_info *info;
Namjae Jeone2f34482021-03-16 10:49:09 +09004892
4893 info = (struct smb3_fs_ss_info *)(rsp->Buffer);
Namjae Jeone2f34482021-03-16 10:49:09 +09004894
Namjae Jeon131bac12021-06-22 16:20:47 +09004895 info->LogicalBytesPerSector = cpu_to_le32(stfs.f_bsize);
Namjae Jeone2f34482021-03-16 10:49:09 +09004896 info->PhysicalBytesPerSectorForAtomicity =
Namjae Jeon131bac12021-06-22 16:20:47 +09004897 cpu_to_le32(stfs.f_bsize);
4898 info->PhysicalBytesPerSectorForPerf = cpu_to_le32(stfs.f_bsize);
Namjae Jeone2f34482021-03-16 10:49:09 +09004899 info->FSEffPhysicalBytesPerSectorForAtomicity =
Namjae Jeon131bac12021-06-22 16:20:47 +09004900 cpu_to_le32(stfs.f_bsize);
Namjae Jeone2f34482021-03-16 10:49:09 +09004901 info->Flags = cpu_to_le32(SSINFO_FLAGS_ALIGNED_DEVICE |
4902 SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE);
4903 info->ByteOffsetForSectorAlignment = 0;
4904 info->ByteOffsetForPartitionAlignment = 0;
4905 rsp->OutputBufferLength = cpu_to_le32(28);
4906 inc_rfc1001_len(rsp_org, 28);
4907 fs_infoclass_size = FS_SECTOR_SIZE_INFORMATION_SIZE;
4908 break;
4909 }
4910 case FS_CONTROL_INFORMATION:
4911 {
4912 /*
4913 * TODO : The current implementation is based on
4914 * test result with win7(NTFS) server. It's need to
4915 * modify this to get valid Quota values
4916 * from Linux kernel
4917 */
4918 struct smb2_fs_control_info *info;
4919
4920 info = (struct smb2_fs_control_info *)(rsp->Buffer);
4921 info->FreeSpaceStartFiltering = 0;
4922 info->FreeSpaceThreshold = 0;
4923 info->FreeSpaceStopFiltering = 0;
4924 info->DefaultQuotaThreshold = cpu_to_le64(SMB2_NO_FID);
4925 info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID);
4926 info->Padding = 0;
4927 rsp->OutputBufferLength = cpu_to_le32(48);
4928 inc_rfc1001_len(rsp_org, 48);
4929 fs_infoclass_size = FS_CONTROL_INFORMATION_SIZE;
4930 break;
4931 }
4932 case FS_POSIX_INFORMATION:
4933 {
4934 struct filesystem_posix_info *info;
Namjae Jeone2f34482021-03-16 10:49:09 +09004935
4936 if (!work->tcon->posix_extensions) {
Namjae Jeonbde16942021-06-28 15:23:19 +09004937 pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09004938 rc = -EOPNOTSUPP;
4939 } else {
4940 info = (struct filesystem_posix_info *)(rsp->Buffer);
Namjae Jeonee81cae2021-06-26 22:32:34 +09004941 info->OptimalTransferSize = cpu_to_le32(stfs.f_bsize);
Namjae Jeone2f34482021-03-16 10:49:09 +09004942 info->BlockSize = cpu_to_le32(stfs.f_bsize);
4943 info->TotalBlocks = cpu_to_le64(stfs.f_blocks);
4944 info->BlocksAvail = cpu_to_le64(stfs.f_bfree);
4945 info->UserBlocksAvail = cpu_to_le64(stfs.f_bavail);
4946 info->TotalFileNodes = cpu_to_le64(stfs.f_files);
4947 info->FreeFileNodes = cpu_to_le64(stfs.f_ffree);
4948 rsp->OutputBufferLength = cpu_to_le32(56);
4949 inc_rfc1001_len(rsp_org, 56);
4950 fs_infoclass_size = FS_POSIX_INFORMATION_SIZE;
4951 }
4952 break;
4953 }
4954 default:
4955 path_put(&path);
4956 return -EOPNOTSUPP;
4957 }
4958 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
4959 rsp,
4960 fs_infoclass_size);
4961 path_put(&path);
4962 return rc;
4963}
4964
4965static int smb2_get_info_sec(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09004966 struct smb2_query_info_req *req,
4967 struct smb2_query_info_rsp *rsp, void *rsp_org)
Namjae Jeone2f34482021-03-16 10:49:09 +09004968{
4969 struct ksmbd_file *fp;
Hyunchul Lee465d7202021-07-03 12:10:36 +09004970 struct user_namespace *user_ns;
Namjae Jeone2f34482021-03-16 10:49:09 +09004971 struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL;
4972 struct smb_fattr fattr = {{0}};
4973 struct inode *inode;
4974 __u32 secdesclen;
4975 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
4976 int addition_info = le32_to_cpu(req->AdditionalInformation);
4977 int rc;
4978
Namjae Jeone294f782021-06-28 15:26:37 +09004979 if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
4980 PROTECTED_DACL_SECINFO |
4981 UNPROTECTED_DACL_SECINFO)) {
4982 pr_err("Unsupported addition info: 0x%x)\n",
4983 addition_info);
Sebastian Gottschallced2b262021-04-27 15:33:54 +09004984
4985 pntsd->revision = cpu_to_le16(1);
4986 pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED);
4987 pntsd->osidoffset = 0;
4988 pntsd->gsidoffset = 0;
4989 pntsd->sacloffset = 0;
4990 pntsd->dacloffset = 0;
4991
4992 secdesclen = sizeof(struct smb_ntsd);
4993 rsp->OutputBufferLength = cpu_to_le32(secdesclen);
4994 inc_rfc1001_len(rsp_org, secdesclen);
4995
4996 return 0;
4997 }
4998
Namjae Jeone2f34482021-03-16 10:49:09 +09004999 if (work->next_smb2_rcv_hdr_off) {
Namjae Jeon38673692021-07-08 12:32:27 +09005000 if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
5001 ksmbd_debug(SMB, "Compound request set FID = %llu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005002 work->compound_fid);
Namjae Jeone2f34482021-03-16 10:49:09 +09005003 id = work->compound_fid;
5004 pid = work->compound_pfid;
5005 }
5006 }
5007
Namjae Jeon38673692021-07-08 12:32:27 +09005008 if (!has_file_id(id)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09005009 id = le64_to_cpu(req->VolatileFileId);
5010 pid = le64_to_cpu(req->PersistentFileId);
5011 }
5012
5013 fp = ksmbd_lookup_fd_slow(work, id, pid);
5014 if (!fp)
5015 return -ENOENT;
5016
Hyunchul Lee465d7202021-07-03 12:10:36 +09005017 user_ns = file_mnt_user_ns(fp->filp);
Namjae Jeonab0b2632021-06-29 09:20:13 +09005018 inode = file_inode(fp->filp);
Christian Brauner43205ca2021-08-23 17:13:50 +02005019 ksmbd_acls_fattr(&fattr, user_ns, inode);
Namjae Jeone2f34482021-03-16 10:49:09 +09005020
5021 if (test_share_config_flag(work->tcon->share_conf,
Namjae Jeon64b39f42021-03-30 14:25:35 +09005022 KSMBD_SHARE_FLAG_ACL_XATTR))
Hyunchul Lee465d7202021-07-03 12:10:36 +09005023 ksmbd_vfs_get_sd_xattr(work->conn, user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09005024 fp->filp->f_path.dentry, &ppntsd);
Namjae Jeone2f34482021-03-16 10:49:09 +09005025
Hyunchul Lee465d7202021-07-03 12:10:36 +09005026 rc = build_sec_desc(user_ns, pntsd, ppntsd, addition_info,
5027 &secdesclen, &fattr);
Namjae Jeone2f34482021-03-16 10:49:09 +09005028 posix_acl_release(fattr.cf_acls);
5029 posix_acl_release(fattr.cf_dacls);
5030 kfree(ppntsd);
5031 ksmbd_fd_put(work, fp);
5032 if (rc)
5033 return rc;
5034
5035 rsp->OutputBufferLength = cpu_to_le32(secdesclen);
5036 inc_rfc1001_len(rsp_org, secdesclen);
5037 return 0;
5038}
5039
5040/**
5041 * smb2_query_info() - handler for smb2 query info command
5042 * @work: smb work containing query info request buffer
5043 *
5044 * Return: 0 on success, otherwise error
5045 */
5046int smb2_query_info(struct ksmbd_work *work)
5047{
5048 struct smb2_query_info_req *req;
5049 struct smb2_query_info_rsp *rsp, *rsp_org;
5050 int rc = 0;
5051
Namjae Jeone5066492021-03-30 12:35:23 +09005052 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09005053 WORK_BUFFERS(work, req, rsp);
5054
5055 ksmbd_debug(SMB, "GOT query info request\n");
5056
5057 switch (req->InfoType) {
5058 case SMB2_O_INFO_FILE:
5059 ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n");
5060 rc = smb2_get_info_file(work, req, rsp, (void *)rsp_org);
5061 break;
5062 case SMB2_O_INFO_FILESYSTEM:
5063 ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILESYSTEM\n");
5064 rc = smb2_get_info_filesystem(work, req, rsp, (void *)rsp_org);
5065 break;
5066 case SMB2_O_INFO_SECURITY:
5067 ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n");
5068 rc = smb2_get_info_sec(work, req, rsp, (void *)rsp_org);
5069 break;
5070 default:
5071 ksmbd_debug(SMB, "InfoType %d not supported yet\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005072 req->InfoType);
Namjae Jeone2f34482021-03-16 10:49:09 +09005073 rc = -EOPNOTSUPP;
5074 }
5075
5076 if (rc < 0) {
5077 if (rc == -EACCES)
5078 rsp->hdr.Status = STATUS_ACCESS_DENIED;
5079 else if (rc == -ENOENT)
5080 rsp->hdr.Status = STATUS_FILE_CLOSED;
5081 else if (rc == -EIO)
5082 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
5083 else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0)
5084 rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;
5085 smb2_set_err_rsp(work);
5086
5087 ksmbd_debug(SMB, "error while processing smb2 query rc = %d\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005088 rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09005089 return rc;
5090 }
5091 rsp->StructureSize = cpu_to_le16(9);
5092 rsp->OutputBufferOffset = cpu_to_le16(72);
5093 inc_rfc1001_len(rsp_org, 8);
5094 return 0;
5095}
5096
5097/**
5098 * smb2_close_pipe() - handler for closing IPC pipe
5099 * @work: smb work containing close request buffer
5100 *
5101 * Return: 0
5102 */
5103static noinline int smb2_close_pipe(struct ksmbd_work *work)
5104{
Namjae Jeon64b39f42021-03-30 14:25:35 +09005105 u64 id;
Namjae Jeone5066492021-03-30 12:35:23 +09005106 struct smb2_close_req *req = work->request_buf;
5107 struct smb2_close_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09005108
5109 id = le64_to_cpu(req->VolatileFileId);
5110 ksmbd_session_rpc_close(work->sess, id);
5111
5112 rsp->StructureSize = cpu_to_le16(60);
5113 rsp->Flags = 0;
5114 rsp->Reserved = 0;
5115 rsp->CreationTime = 0;
5116 rsp->LastAccessTime = 0;
5117 rsp->LastWriteTime = 0;
5118 rsp->ChangeTime = 0;
5119 rsp->AllocationSize = 0;
5120 rsp->EndOfFile = 0;
5121 rsp->Attributes = 0;
5122 inc_rfc1001_len(rsp, 60);
5123 return 0;
5124}
5125
5126/**
5127 * smb2_close() - handler for smb2 close file command
5128 * @work: smb work containing close request buffer
5129 *
5130 * Return: 0
5131 */
5132int smb2_close(struct ksmbd_work *work)
5133{
Namjae Jeon38673692021-07-08 12:32:27 +09005134 u64 volatile_id = KSMBD_NO_FID;
Namjae Jeon64b39f42021-03-30 14:25:35 +09005135 u64 sess_id;
Namjae Jeone2f34482021-03-16 10:49:09 +09005136 struct smb2_close_req *req;
5137 struct smb2_close_rsp *rsp;
5138 struct smb2_close_rsp *rsp_org;
5139 struct ksmbd_conn *conn = work->conn;
5140 struct ksmbd_file *fp;
5141 struct inode *inode;
5142 u64 time;
5143 int err = 0;
5144
Namjae Jeone5066492021-03-30 12:35:23 +09005145 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09005146 WORK_BUFFERS(work, req, rsp);
5147
5148 if (test_share_config_flag(work->tcon->share_conf,
5149 KSMBD_SHARE_FLAG_PIPE)) {
5150 ksmbd_debug(SMB, "IPC pipe close request\n");
5151 return smb2_close_pipe(work);
5152 }
5153
5154 sess_id = le64_to_cpu(req->hdr.SessionId);
5155 if (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS)
5156 sess_id = work->compound_sid;
5157
5158 work->compound_sid = 0;
Namjae Jeon64b39f42021-03-30 14:25:35 +09005159 if (check_session_id(conn, sess_id)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09005160 work->compound_sid = sess_id;
Namjae Jeon64b39f42021-03-30 14:25:35 +09005161 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09005162 rsp->hdr.Status = STATUS_USER_SESSION_DELETED;
5163 if (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS)
5164 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
5165 err = -EBADF;
5166 goto out;
5167 }
5168
5169 if (work->next_smb2_rcv_hdr_off &&
Namjae Jeon38673692021-07-08 12:32:27 +09005170 !has_file_id(le64_to_cpu(req->VolatileFileId))) {
5171 if (!has_file_id(work->compound_fid)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09005172 /* file already closed, return FILE_CLOSED */
5173 ksmbd_debug(SMB, "file already closed\n");
5174 rsp->hdr.Status = STATUS_FILE_CLOSED;
5175 err = -EBADF;
5176 goto out;
5177 } else {
Namjae Jeon38673692021-07-08 12:32:27 +09005178 ksmbd_debug(SMB,
5179 "Compound request set FID = %llu:%llu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005180 work->compound_fid,
5181 work->compound_pfid);
Namjae Jeone2f34482021-03-16 10:49:09 +09005182 volatile_id = work->compound_fid;
5183
5184 /* file closed, stored id is not valid anymore */
5185 work->compound_fid = KSMBD_NO_FID;
5186 work->compound_pfid = KSMBD_NO_FID;
5187 }
5188 } else {
5189 volatile_id = le64_to_cpu(req->VolatileFileId);
5190 }
Namjae Jeon38673692021-07-08 12:32:27 +09005191 ksmbd_debug(SMB, "volatile_id = %llu\n", volatile_id);
Namjae Jeone2f34482021-03-16 10:49:09 +09005192
5193 rsp->StructureSize = cpu_to_le16(60);
5194 rsp->Reserved = 0;
5195
5196 if (req->Flags == SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB) {
5197 fp = ksmbd_lookup_fd_fast(work, volatile_id);
5198 if (!fp) {
5199 err = -ENOENT;
5200 goto out;
5201 }
5202
Namjae Jeonab0b2632021-06-29 09:20:13 +09005203 inode = file_inode(fp->filp);
Namjae Jeone2f34482021-03-16 10:49:09 +09005204 rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
5205 rsp->AllocationSize = S_ISDIR(inode->i_mode) ? 0 :
5206 cpu_to_le64(inode->i_blocks << 9);
5207 rsp->EndOfFile = cpu_to_le64(inode->i_size);
5208 rsp->Attributes = fp->f_ci->m_fattr;
5209 rsp->CreationTime = cpu_to_le64(fp->create_time);
5210 time = ksmbd_UnixTimeToNT(inode->i_atime);
5211 rsp->LastAccessTime = cpu_to_le64(time);
5212 time = ksmbd_UnixTimeToNT(inode->i_mtime);
5213 rsp->LastWriteTime = cpu_to_le64(time);
5214 time = ksmbd_UnixTimeToNT(inode->i_ctime);
5215 rsp->ChangeTime = cpu_to_le64(time);
5216 ksmbd_fd_put(work, fp);
5217 } else {
5218 rsp->Flags = 0;
5219 rsp->AllocationSize = 0;
5220 rsp->EndOfFile = 0;
5221 rsp->Attributes = 0;
5222 rsp->CreationTime = 0;
5223 rsp->LastAccessTime = 0;
5224 rsp->LastWriteTime = 0;
5225 rsp->ChangeTime = 0;
5226 }
5227
5228 err = ksmbd_close_fd(work, volatile_id);
5229out:
5230 if (err) {
5231 if (rsp->hdr.Status == 0)
5232 rsp->hdr.Status = STATUS_FILE_CLOSED;
5233 smb2_set_err_rsp(work);
5234 } else {
5235 inc_rfc1001_len(rsp_org, 60);
5236 }
5237
5238 return 0;
5239}
5240
5241/**
5242 * smb2_echo() - handler for smb2 echo(ping) command
5243 * @work: smb work containing echo request buffer
5244 *
5245 * Return: 0
5246 */
5247int smb2_echo(struct ksmbd_work *work)
5248{
Namjae Jeone5066492021-03-30 12:35:23 +09005249 struct smb2_echo_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09005250
5251 rsp->StructureSize = cpu_to_le16(4);
5252 rsp->Reserved = 0;
5253 inc_rfc1001_len(rsp, 4);
5254 return 0;
5255}
5256
Christian Braunerda1e7ad2021-08-23 17:13:47 +02005257static int smb2_rename(struct ksmbd_work *work,
5258 struct ksmbd_file *fp,
5259 struct user_namespace *user_ns,
Namjae Jeon070fb212021-05-26 17:57:12 +09005260 struct smb2_file_rename_info *file_info,
5261 struct nls_table *local_nls)
Namjae Jeone2f34482021-03-16 10:49:09 +09005262{
5263 struct ksmbd_share_config *share = fp->tcon->share_conf;
5264 char *new_name = NULL, *abs_oldname = NULL, *old_name = NULL;
5265 char *pathname = NULL;
5266 struct path path;
5267 bool file_present = true;
5268 int rc;
5269
5270 ksmbd_debug(SMB, "setting FILE_RENAME_INFO\n");
5271 pathname = kmalloc(PATH_MAX, GFP_KERNEL);
5272 if (!pathname)
5273 return -ENOMEM;
5274
5275 abs_oldname = d_path(&fp->filp->f_path, pathname, PATH_MAX);
5276 if (IS_ERR(abs_oldname)) {
5277 rc = -EINVAL;
5278 goto out;
5279 }
5280 old_name = strrchr(abs_oldname, '/');
Namjae Jeon64b39f42021-03-30 14:25:35 +09005281 if (old_name && old_name[1] != '\0') {
Namjae Jeone2f34482021-03-16 10:49:09 +09005282 old_name++;
Namjae Jeon64b39f42021-03-30 14:25:35 +09005283 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09005284 ksmbd_debug(SMB, "can't get last component in path %s\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005285 abs_oldname);
Namjae Jeone2f34482021-03-16 10:49:09 +09005286 rc = -ENOENT;
5287 goto out;
5288 }
5289
5290 new_name = smb2_get_name(share,
5291 file_info->FileName,
5292 le32_to_cpu(file_info->FileNameLength),
5293 local_nls);
5294 if (IS_ERR(new_name)) {
5295 rc = PTR_ERR(new_name);
5296 goto out;
5297 }
5298
5299 if (strchr(new_name, ':')) {
5300 int s_type;
5301 char *xattr_stream_name, *stream_name = NULL;
5302 size_t xattr_stream_size;
5303 int len;
5304
5305 rc = parse_stream_name(new_name, &stream_name, &s_type);
5306 if (rc < 0)
5307 goto out;
5308
5309 len = strlen(new_name);
5310 if (new_name[len - 1] != '/') {
Namjae Jeonbde16942021-06-28 15:23:19 +09005311 pr_err("not allow base filename in rename\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09005312 rc = -ESHARE;
5313 goto out;
5314 }
5315
5316 rc = ksmbd_vfs_xattr_stream_name(stream_name,
5317 &xattr_stream_name,
5318 &xattr_stream_size,
5319 s_type);
5320 if (rc)
5321 goto out;
5322
Christian Braunerda1e7ad2021-08-23 17:13:47 +02005323 rc = ksmbd_vfs_setxattr(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09005324 fp->filp->f_path.dentry,
Namjae Jeone2f34482021-03-16 10:49:09 +09005325 xattr_stream_name,
5326 NULL, 0, 0);
5327 if (rc < 0) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005328 pr_err("failed to store stream name in xattr: %d\n",
5329 rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09005330 rc = -EINVAL;
5331 goto out;
5332 }
5333
5334 goto out;
5335 }
5336
5337 ksmbd_debug(SMB, "new name %s\n", new_name);
5338 rc = ksmbd_vfs_kern_path(new_name, 0, &path, 1);
5339 if (rc)
5340 file_present = false;
5341 else
5342 path_put(&path);
5343
5344 if (ksmbd_share_veto_filename(share, new_name)) {
5345 rc = -ENOENT;
5346 ksmbd_debug(SMB, "Can't rename vetoed file: %s\n", new_name);
5347 goto out;
5348 }
5349
5350 if (file_info->ReplaceIfExists) {
5351 if (file_present) {
5352 rc = ksmbd_vfs_remove_file(work, new_name);
5353 if (rc) {
5354 if (rc != -ENOTEMPTY)
5355 rc = -EINVAL;
5356 ksmbd_debug(SMB, "cannot delete %s, rc %d\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005357 new_name, rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09005358 goto out;
5359 }
5360 }
5361 } else {
5362 if (file_present &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09005363 strncmp(old_name, path.dentry->d_name.name, strlen(old_name))) {
Namjae Jeone2f34482021-03-16 10:49:09 +09005364 rc = -EEXIST;
5365 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09005366 "cannot rename already existing file\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09005367 goto out;
5368 }
5369 }
5370
5371 rc = ksmbd_vfs_fp_rename(work, fp, new_name);
5372out:
5373 kfree(pathname);
5374 if (!IS_ERR(new_name))
Marios Makassikis915f5702021-04-13 13:25:57 +09005375 kfree(new_name);
Namjae Jeone2f34482021-03-16 10:49:09 +09005376 return rc;
5377}
5378
Namjae Jeone2f34482021-03-16 10:49:09 +09005379static int smb2_create_link(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09005380 struct ksmbd_share_config *share,
5381 struct smb2_file_link_info *file_info,
5382 struct file *filp,
5383 struct nls_table *local_nls)
Namjae Jeone2f34482021-03-16 10:49:09 +09005384{
5385 char *link_name = NULL, *target_name = NULL, *pathname = NULL;
5386 struct path path;
5387 bool file_present = true;
5388 int rc;
5389
5390 ksmbd_debug(SMB, "setting FILE_LINK_INFORMATION\n");
5391 pathname = kmalloc(PATH_MAX, GFP_KERNEL);
5392 if (!pathname)
5393 return -ENOMEM;
5394
5395 link_name = smb2_get_name(share,
5396 file_info->FileName,
5397 le32_to_cpu(file_info->FileNameLength),
5398 local_nls);
5399 if (IS_ERR(link_name) || S_ISDIR(file_inode(filp)->i_mode)) {
5400 rc = -EINVAL;
5401 goto out;
5402 }
5403
5404 ksmbd_debug(SMB, "link name is %s\n", link_name);
5405 target_name = d_path(&filp->f_path, pathname, PATH_MAX);
5406 if (IS_ERR(target_name)) {
5407 rc = -EINVAL;
5408 goto out;
5409 }
5410
5411 ksmbd_debug(SMB, "target name is %s\n", target_name);
5412 rc = ksmbd_vfs_kern_path(link_name, 0, &path, 0);
5413 if (rc)
5414 file_present = false;
5415 else
5416 path_put(&path);
5417
5418 if (file_info->ReplaceIfExists) {
5419 if (file_present) {
5420 rc = ksmbd_vfs_remove_file(work, link_name);
5421 if (rc) {
5422 rc = -EINVAL;
5423 ksmbd_debug(SMB, "cannot delete %s\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005424 link_name);
Namjae Jeone2f34482021-03-16 10:49:09 +09005425 goto out;
5426 }
5427 }
5428 } else {
5429 if (file_present) {
5430 rc = -EEXIST;
5431 ksmbd_debug(SMB, "link already exists\n");
5432 goto out;
5433 }
5434 }
5435
5436 rc = ksmbd_vfs_link(work, target_name, link_name);
5437 if (rc)
5438 rc = -EINVAL;
5439out:
5440 if (!IS_ERR(link_name))
Marios Makassikis915f5702021-04-13 13:25:57 +09005441 kfree(link_name);
Namjae Jeone2f34482021-03-16 10:49:09 +09005442 kfree(pathname);
5443 return rc;
5444}
5445
Namjae Jeon64b39f42021-03-30 14:25:35 +09005446static int set_file_basic_info(struct ksmbd_file *fp, char *buf,
Namjae Jeon070fb212021-05-26 17:57:12 +09005447 struct ksmbd_share_config *share)
Namjae Jeone2f34482021-03-16 10:49:09 +09005448{
5449 struct smb2_file_all_info *file_info;
5450 struct iattr attrs;
Christian Braunerdb7fb6f2021-08-26 10:07:05 +09005451 struct timespec64 ctime;
Namjae Jeone2f34482021-03-16 10:49:09 +09005452 struct file *filp;
5453 struct inode *inode;
Hyunchul Lee465d7202021-07-03 12:10:36 +09005454 struct user_namespace *user_ns;
Namjae Jeon4ffd5262021-09-07 08:15:21 +09005455 int rc = 0;
Namjae Jeone2f34482021-03-16 10:49:09 +09005456
Marios Makassikis7adfd4f2021-04-27 15:30:22 +09005457 if (!(fp->daccess & FILE_WRITE_ATTRIBUTES_LE))
Namjae Jeone2f34482021-03-16 10:49:09 +09005458 return -EACCES;
5459
5460 file_info = (struct smb2_file_all_info *)buf;
5461 attrs.ia_valid = 0;
5462 filp = fp->filp;
5463 inode = file_inode(filp);
Hyunchul Lee465d7202021-07-03 12:10:36 +09005464 user_ns = file_mnt_user_ns(filp);
Namjae Jeone2f34482021-03-16 10:49:09 +09005465
5466 if (file_info->CreationTime)
5467 fp->create_time = le64_to_cpu(file_info->CreationTime);
5468
5469 if (file_info->LastAccessTime) {
5470 attrs.ia_atime = ksmbd_NTtimeToUnix(file_info->LastAccessTime);
5471 attrs.ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
5472 }
5473
5474 if (file_info->ChangeTime) {
Christian Braunerdb7fb6f2021-08-26 10:07:05 +09005475 attrs.ia_ctime = ksmbd_NTtimeToUnix(file_info->ChangeTime);
5476 ctime = attrs.ia_ctime;
Namjae Jeone2f34482021-03-16 10:49:09 +09005477 attrs.ia_valid |= ATTR_CTIME;
Namjae Jeon64b39f42021-03-30 14:25:35 +09005478 } else {
Christian Braunerdb7fb6f2021-08-26 10:07:05 +09005479 ctime = inode->i_ctime;
Namjae Jeon64b39f42021-03-30 14:25:35 +09005480 }
Namjae Jeone2f34482021-03-16 10:49:09 +09005481
5482 if (file_info->LastWriteTime) {
5483 attrs.ia_mtime = ksmbd_NTtimeToUnix(file_info->LastWriteTime);
5484 attrs.ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
5485 }
5486
5487 if (file_info->Attributes) {
5488 if (!S_ISDIR(inode->i_mode) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09005489 file_info->Attributes & ATTR_DIRECTORY_LE) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005490 pr_err("can't change a file to a directory\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09005491 return -EINVAL;
5492 }
5493
5494 if (!(S_ISDIR(inode->i_mode) && file_info->Attributes == ATTR_NORMAL_LE))
5495 fp->f_ci->m_fattr = file_info->Attributes |
5496 (fp->f_ci->m_fattr & ATTR_DIRECTORY_LE);
5497 }
5498
5499 if (test_share_config_flag(share, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS) &&
5500 (file_info->CreationTime || file_info->Attributes)) {
5501 struct xattr_dos_attrib da = {0};
5502
5503 da.version = 4;
5504 da.itime = fp->itime;
5505 da.create_time = fp->create_time;
5506 da.attr = le32_to_cpu(fp->f_ci->m_fattr);
5507 da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
5508 XATTR_DOSINFO_ITIME;
5509
Hyunchul Lee465d7202021-07-03 12:10:36 +09005510 rc = ksmbd_vfs_set_dos_attrib_xattr(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09005511 filp->f_path.dentry, &da);
Namjae Jeone2f34482021-03-16 10:49:09 +09005512 if (rc)
5513 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09005514 "failed to restore file attribute in EA\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09005515 rc = 0;
5516 }
5517
Namjae Jeone2f34482021-03-16 10:49:09 +09005518 if (attrs.ia_valid) {
5519 struct dentry *dentry = filp->f_path.dentry;
5520 struct inode *inode = d_inode(dentry);
5521
5522 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
5523 return -EACCES;
5524
Namjae Jeone2f34482021-03-16 10:49:09 +09005525 inode_lock(inode);
Hyunchul Lee465d7202021-07-03 12:10:36 +09005526 rc = notify_change(user_ns, dentry, &attrs, NULL);
Christian Braunerdb7fb6f2021-08-26 10:07:05 +09005527 if (!rc) {
5528 inode->i_ctime = ctime;
5529 mark_inode_dirty(inode);
5530 }
Namjae Jeone2f34482021-03-16 10:49:09 +09005531 inode_unlock(inode);
5532 }
Christian Braunereb5784f2021-08-23 17:13:55 +02005533 return rc;
Namjae Jeone2f34482021-03-16 10:49:09 +09005534}
5535
5536static int set_file_allocation_info(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09005537 struct ksmbd_file *fp, char *buf)
Namjae Jeone2f34482021-03-16 10:49:09 +09005538{
5539 /*
5540 * TODO : It's working fine only when store dos attributes
5541 * is not yes. need to implement a logic which works
5542 * properly with any smb.conf option
5543 */
5544
5545 struct smb2_file_alloc_info *file_alloc_info;
5546 loff_t alloc_blks;
5547 struct inode *inode;
5548 int rc;
5549
Marios Makassikisa2996692021-04-27 15:29:01 +09005550 if (!(fp->daccess & FILE_WRITE_DATA_LE))
Namjae Jeone2f34482021-03-16 10:49:09 +09005551 return -EACCES;
5552
5553 file_alloc_info = (struct smb2_file_alloc_info *)buf;
5554 alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9;
5555 inode = file_inode(fp->filp);
5556
5557 if (alloc_blks > inode->i_blocks) {
Namjae Jeone8c06192021-06-22 11:06:11 +09005558 smb_break_all_levII_oplock(work, fp, 1);
5559 rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,
5560 alloc_blks * 512);
Namjae Jeone2f34482021-03-16 10:49:09 +09005561 if (rc && rc != -EOPNOTSUPP) {
Namjae Jeone8c06192021-06-22 11:06:11 +09005562 pr_err("vfs_fallocate is failed : %d\n", rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09005563 return rc;
5564 }
5565 } else if (alloc_blks < inode->i_blocks) {
5566 loff_t size;
5567
5568 /*
5569 * Allocation size could be smaller than original one
5570 * which means allocated blocks in file should be
5571 * deallocated. use truncate to cut out it, but inode
5572 * size is also updated with truncate offset.
5573 * inode size is retained by backup inode size.
5574 */
5575 size = i_size_read(inode);
5576 rc = ksmbd_vfs_truncate(work, NULL, fp, alloc_blks * 512);
5577 if (rc) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005578 pr_err("truncate failed! filename : %s, err %d\n",
5579 fp->filename, rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09005580 return rc;
5581 }
5582 if (size < alloc_blks * 512)
5583 i_size_write(inode, size);
5584 }
5585 return 0;
5586}
5587
Namjae Jeon64b39f42021-03-30 14:25:35 +09005588static int set_end_of_file_info(struct ksmbd_work *work, struct ksmbd_file *fp,
Namjae Jeon070fb212021-05-26 17:57:12 +09005589 char *buf)
Namjae Jeone2f34482021-03-16 10:49:09 +09005590{
5591 struct smb2_file_eof_info *file_eof_info;
5592 loff_t newsize;
5593 struct inode *inode;
5594 int rc;
5595
Marios Makassikisa2996692021-04-27 15:29:01 +09005596 if (!(fp->daccess & FILE_WRITE_DATA_LE))
Namjae Jeone2f34482021-03-16 10:49:09 +09005597 return -EACCES;
5598
5599 file_eof_info = (struct smb2_file_eof_info *)buf;
5600 newsize = le64_to_cpu(file_eof_info->EndOfFile);
5601 inode = file_inode(fp->filp);
5602
5603 /*
5604 * If FILE_END_OF_FILE_INFORMATION of set_info_file is called
5605 * on FAT32 shared device, truncate execution time is too long
5606 * and network error could cause from windows client. because
5607 * truncate of some filesystem like FAT32 fill zero data in
5608 * truncated range.
5609 */
5610 if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) {
5611 ksmbd_debug(SMB, "filename : %s truncated to newsize %lld\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005612 fp->filename, newsize);
Namjae Jeone2f34482021-03-16 10:49:09 +09005613 rc = ksmbd_vfs_truncate(work, NULL, fp, newsize);
5614 if (rc) {
Namjae Jeon64b39f42021-03-30 14:25:35 +09005615 ksmbd_debug(SMB, "truncate failed! filename : %s err %d\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005616 fp->filename, rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09005617 if (rc != -EAGAIN)
5618 rc = -EBADF;
5619 return rc;
5620 }
5621 }
5622 return 0;
5623}
5624
Namjae Jeon64b39f42021-03-30 14:25:35 +09005625static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
Namjae Jeon070fb212021-05-26 17:57:12 +09005626 char *buf)
Namjae Jeone2f34482021-03-16 10:49:09 +09005627{
Christian Braunerda1e7ad2021-08-23 17:13:47 +02005628 struct user_namespace *user_ns;
Namjae Jeone2f34482021-03-16 10:49:09 +09005629 struct ksmbd_file *parent_fp;
Namjae Jeon12202c02021-06-29 09:23:56 +09005630 struct dentry *parent;
5631 struct dentry *dentry = fp->filp->f_path.dentry;
5632 int ret;
Namjae Jeone2f34482021-03-16 10:49:09 +09005633
5634 if (!(fp->daccess & FILE_DELETE_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005635 pr_err("no right to delete : 0x%x\n", fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09005636 return -EACCES;
5637 }
5638
Christian Braunerda1e7ad2021-08-23 17:13:47 +02005639 user_ns = file_mnt_user_ns(fp->filp);
Namjae Jeone2f34482021-03-16 10:49:09 +09005640 if (ksmbd_stream_fd(fp))
5641 goto next;
5642
Namjae Jeon12202c02021-06-29 09:23:56 +09005643 parent = dget_parent(dentry);
Christian Braunerda1e7ad2021-08-23 17:13:47 +02005644 ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry);
Namjae Jeon12202c02021-06-29 09:23:56 +09005645 if (ret) {
5646 dput(parent);
5647 return ret;
5648 }
5649
5650 parent_fp = ksmbd_lookup_fd_inode(d_inode(parent));
5651 inode_unlock(d_inode(parent));
5652 dput(parent);
5653
Namjae Jeone2f34482021-03-16 10:49:09 +09005654 if (parent_fp) {
5655 if (parent_fp->daccess & FILE_DELETE_LE) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005656 pr_err("parent dir is opened with delete access\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09005657 return -ESHARE;
5658 }
5659 }
5660next:
Christian Braunerda1e7ad2021-08-23 17:13:47 +02005661 return smb2_rename(work, fp, user_ns,
Namjae Jeone2f34482021-03-16 10:49:09 +09005662 (struct smb2_file_rename_info *)buf,
5663 work->sess->conn->local_nls);
5664}
5665
Namjae Jeon64b39f42021-03-30 14:25:35 +09005666static int set_file_disposition_info(struct ksmbd_file *fp, char *buf)
Namjae Jeone2f34482021-03-16 10:49:09 +09005667{
5668 struct smb2_file_disposition_info *file_info;
5669 struct inode *inode;
5670
5671 if (!(fp->daccess & FILE_DELETE_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005672 pr_err("no right to delete : 0x%x\n", fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09005673 return -EACCES;
5674 }
5675
5676 inode = file_inode(fp->filp);
5677 file_info = (struct smb2_file_disposition_info *)buf;
5678 if (file_info->DeletePending) {
5679 if (S_ISDIR(inode->i_mode) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09005680 ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY)
Namjae Jeone2f34482021-03-16 10:49:09 +09005681 return -EBUSY;
5682 ksmbd_set_inode_pending_delete(fp);
5683 } else {
5684 ksmbd_clear_inode_pending_delete(fp);
5685 }
5686 return 0;
5687}
5688
Namjae Jeon64b39f42021-03-30 14:25:35 +09005689static int set_file_position_info(struct ksmbd_file *fp, char *buf)
Namjae Jeone2f34482021-03-16 10:49:09 +09005690{
5691 struct smb2_file_pos_info *file_info;
5692 loff_t current_byte_offset;
Namjae Jeonee81cae2021-06-26 22:32:34 +09005693 unsigned long sector_size;
Namjae Jeone2f34482021-03-16 10:49:09 +09005694 struct inode *inode;
5695
5696 inode = file_inode(fp->filp);
5697 file_info = (struct smb2_file_pos_info *)buf;
5698 current_byte_offset = le64_to_cpu(file_info->CurrentByteOffset);
Namjae Jeonee81cae2021-06-26 22:32:34 +09005699 sector_size = inode->i_sb->s_blocksize;
Namjae Jeone2f34482021-03-16 10:49:09 +09005700
5701 if (current_byte_offset < 0 ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09005702 (fp->coption == FILE_NO_INTERMEDIATE_BUFFERING_LE &&
5703 current_byte_offset & (sector_size - 1))) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005704 pr_err("CurrentByteOffset is not valid : %llu\n",
5705 current_byte_offset);
Namjae Jeone2f34482021-03-16 10:49:09 +09005706 return -EINVAL;
5707 }
5708
5709 fp->filp->f_pos = current_byte_offset;
5710 return 0;
5711}
5712
Namjae Jeon64b39f42021-03-30 14:25:35 +09005713static int set_file_mode_info(struct ksmbd_file *fp, char *buf)
Namjae Jeone2f34482021-03-16 10:49:09 +09005714{
5715 struct smb2_file_mode_info *file_info;
5716 __le32 mode;
5717
5718 file_info = (struct smb2_file_mode_info *)buf;
5719 mode = file_info->Mode;
5720
Namjae Jeon64b39f42021-03-30 14:25:35 +09005721 if ((mode & ~FILE_MODE_INFO_MASK) ||
5722 (mode & FILE_SYNCHRONOUS_IO_ALERT_LE &&
5723 mode & FILE_SYNCHRONOUS_IO_NONALERT_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005724 pr_err("Mode is not valid : 0x%x\n", le32_to_cpu(mode));
Namjae Jeone2f34482021-03-16 10:49:09 +09005725 return -EINVAL;
5726 }
5727
5728 /*
5729 * TODO : need to implement consideration for
5730 * FILE_SYNCHRONOUS_IO_ALERT and FILE_SYNCHRONOUS_IO_NONALERT
5731 */
5732 ksmbd_vfs_set_fadvise(fp->filp, mode);
5733 fp->coption = mode;
5734 return 0;
5735}
5736
5737/**
5738 * smb2_set_info_file() - handler for smb2 set info command
5739 * @work: smb work containing set info command buffer
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +09005740 * @fp: ksmbd_file pointer
5741 * @info_class: smb2 set info class
5742 * @share: ksmbd_share_config pointer
Namjae Jeone2f34482021-03-16 10:49:09 +09005743 *
5744 * Return: 0 on success, otherwise error
5745 * TODO: need to implement an error handling for STATUS_INFO_LENGTH_MISMATCH
5746 */
Namjae Jeon64b39f42021-03-30 14:25:35 +09005747static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
Namjae Jeon070fb212021-05-26 17:57:12 +09005748 int info_class, char *buf,
5749 struct ksmbd_share_config *share)
Namjae Jeone2f34482021-03-16 10:49:09 +09005750{
5751 switch (info_class) {
5752 case FILE_BASIC_INFORMATION:
5753 return set_file_basic_info(fp, buf, share);
5754
5755 case FILE_ALLOCATION_INFORMATION:
5756 return set_file_allocation_info(work, fp, buf);
5757
5758 case FILE_END_OF_FILE_INFORMATION:
5759 return set_end_of_file_info(work, fp, buf);
5760
5761 case FILE_RENAME_INFORMATION:
Namjae Jeon64b39f42021-03-30 14:25:35 +09005762 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09005763 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09005764 "User does not have write permission\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09005765 return -EACCES;
5766 }
5767 return set_rename_info(work, fp, buf);
5768
5769 case FILE_LINK_INFORMATION:
5770 return smb2_create_link(work, work->tcon->share_conf,
Namjae Jeon070fb212021-05-26 17:57:12 +09005771 (struct smb2_file_link_info *)buf, fp->filp,
5772 work->sess->conn->local_nls);
Namjae Jeone2f34482021-03-16 10:49:09 +09005773
5774 case FILE_DISPOSITION_INFORMATION:
Namjae Jeon64b39f42021-03-30 14:25:35 +09005775 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09005776 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09005777 "User does not have write permission\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09005778 return -EACCES;
5779 }
5780 return set_file_disposition_info(fp, buf);
5781
5782 case FILE_FULL_EA_INFORMATION:
5783 {
5784 if (!(fp->daccess & FILE_WRITE_EA_LE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09005785 pr_err("Not permitted to write ext attr: 0x%x\n",
5786 fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09005787 return -EACCES;
5788 }
5789
5790 return smb2_set_ea((struct smb2_ea_info *)buf,
5791 &fp->filp->f_path);
5792 }
5793
5794 case FILE_POSITION_INFORMATION:
5795 return set_file_position_info(fp, buf);
5796
5797 case FILE_MODE_INFORMATION:
5798 return set_file_mode_info(fp, buf);
5799 }
5800
Namjae Jeonbde16942021-06-28 15:23:19 +09005801 pr_err("Unimplemented Fileinfoclass :%d\n", info_class);
Namjae Jeone2f34482021-03-16 10:49:09 +09005802 return -EOPNOTSUPP;
5803}
5804
Namjae Jeon64b39f42021-03-30 14:25:35 +09005805static int smb2_set_info_sec(struct ksmbd_file *fp, int addition_info,
Namjae Jeon070fb212021-05-26 17:57:12 +09005806 char *buffer, int buf_len)
Namjae Jeone2f34482021-03-16 10:49:09 +09005807{
5808 struct smb_ntsd *pntsd = (struct smb_ntsd *)buffer;
5809
5810 fp->saccess |= FILE_SHARE_DELETE_LE;
5811
Hyunchul Leeef24c962021-06-30 18:25:52 +09005812 return set_info_sec(fp->conn, fp->tcon, &fp->filp->f_path, pntsd,
Namjae Jeone2f34482021-03-16 10:49:09 +09005813 buf_len, false);
5814}
5815
5816/**
5817 * smb2_set_info() - handler for smb2 set info command handler
5818 * @work: smb work containing set info request buffer
5819 *
5820 * Return: 0 on success, otherwise error
5821 */
5822int smb2_set_info(struct ksmbd_work *work)
5823{
5824 struct smb2_set_info_req *req;
5825 struct smb2_set_info_rsp *rsp, *rsp_org;
5826 struct ksmbd_file *fp;
5827 int rc = 0;
5828 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
5829
5830 ksmbd_debug(SMB, "Received set info request\n");
5831
Namjae Jeone5066492021-03-30 12:35:23 +09005832 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09005833 if (work->next_smb2_rcv_hdr_off) {
Namjae Jeon8a893312021-06-25 13:43:37 +09005834 req = ksmbd_req_buf_next(work);
5835 rsp = ksmbd_resp_buf_next(work);
Namjae Jeon38673692021-07-08 12:32:27 +09005836 if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
5837 ksmbd_debug(SMB, "Compound request set FID = %llu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09005838 work->compound_fid);
Namjae Jeone2f34482021-03-16 10:49:09 +09005839 id = work->compound_fid;
5840 pid = work->compound_pfid;
5841 }
5842 } else {
Namjae Jeone5066492021-03-30 12:35:23 +09005843 req = work->request_buf;
5844 rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09005845 }
5846
Namjae Jeon38673692021-07-08 12:32:27 +09005847 if (!has_file_id(id)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09005848 id = le64_to_cpu(req->VolatileFileId);
5849 pid = le64_to_cpu(req->PersistentFileId);
5850 }
5851
5852 fp = ksmbd_lookup_fd_slow(work, id, pid);
5853 if (!fp) {
5854 ksmbd_debug(SMB, "Invalid id for close: %u\n", id);
5855 rc = -ENOENT;
5856 goto err_out;
5857 }
5858
5859 switch (req->InfoType) {
5860 case SMB2_O_INFO_FILE:
5861 ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n");
5862 rc = smb2_set_info_file(work, fp, req->FileInfoClass,
5863 req->Buffer, work->tcon->share_conf);
5864 break;
5865 case SMB2_O_INFO_SECURITY:
5866 ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n");
Namjae Jeone70e3922021-08-21 23:26:01 +09005867 if (ksmbd_override_fsids(work)) {
5868 rc = -ENOMEM;
5869 goto err_out;
5870 }
Namjae Jeone2f34482021-03-16 10:49:09 +09005871 rc = smb2_set_info_sec(fp,
Namjae Jeon070fb212021-05-26 17:57:12 +09005872 le32_to_cpu(req->AdditionalInformation),
5873 req->Buffer,
5874 le32_to_cpu(req->BufferLength));
Namjae Jeone70e3922021-08-21 23:26:01 +09005875 ksmbd_revert_fsids(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09005876 break;
5877 default:
5878 rc = -EOPNOTSUPP;
5879 }
5880
5881 if (rc < 0)
5882 goto err_out;
5883
5884 rsp->StructureSize = cpu_to_le16(2);
5885 inc_rfc1001_len(rsp_org, 2);
5886 ksmbd_fd_put(work, fp);
5887 return 0;
5888
5889err_out:
5890 if (rc == -EACCES || rc == -EPERM)
5891 rsp->hdr.Status = STATUS_ACCESS_DENIED;
5892 else if (rc == -EINVAL)
5893 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
5894 else if (rc == -ESHARE)
5895 rsp->hdr.Status = STATUS_SHARING_VIOLATION;
5896 else if (rc == -ENOENT)
5897 rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID;
5898 else if (rc == -EBUSY || rc == -ENOTEMPTY)
5899 rsp->hdr.Status = STATUS_DIRECTORY_NOT_EMPTY;
5900 else if (rc == -EAGAIN)
5901 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
Namjae Jeonff1d5722021-04-13 13:18:10 +09005902 else if (rc == -EBADF || rc == -ESTALE)
Namjae Jeone2f34482021-03-16 10:49:09 +09005903 rsp->hdr.Status = STATUS_INVALID_HANDLE;
5904 else if (rc == -EEXIST)
5905 rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION;
5906 else if (rsp->hdr.Status == 0 || rc == -EOPNOTSUPP)
5907 rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;
5908 smb2_set_err_rsp(work);
5909 ksmbd_fd_put(work, fp);
Namjae Jeon070fb212021-05-26 17:57:12 +09005910 ksmbd_debug(SMB, "error while processing smb2 query rc = %d\n", rc);
Namjae Jeone2f34482021-03-16 10:49:09 +09005911 return rc;
5912}
5913
5914/**
5915 * smb2_read_pipe() - handler for smb2 read from IPC pipe
5916 * @work: smb work containing read IPC pipe command buffer
5917 *
5918 * Return: 0 on success, otherwise error
5919 */
5920static noinline int smb2_read_pipe(struct ksmbd_work *work)
5921{
5922 int nbytes = 0, err;
Namjae Jeon64b39f42021-03-30 14:25:35 +09005923 u64 id;
Namjae Jeone2f34482021-03-16 10:49:09 +09005924 struct ksmbd_rpc_command *rpc_resp;
Namjae Jeone5066492021-03-30 12:35:23 +09005925 struct smb2_read_req *req = work->request_buf;
5926 struct smb2_read_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09005927
5928 id = le64_to_cpu(req->VolatileFileId);
5929
5930 inc_rfc1001_len(rsp, 16);
5931 rpc_resp = ksmbd_rpc_read(work->sess, id);
5932 if (rpc_resp) {
5933 if (rpc_resp->flags != KSMBD_RPC_OK) {
5934 err = -EINVAL;
5935 goto out;
5936 }
5937
5938 work->aux_payload_buf =
Namjae Jeon79f6b112021-04-02 12:47:14 +09005939 kvmalloc(rpc_resp->payload_sz, GFP_KERNEL | __GFP_ZERO);
Namjae Jeone2f34482021-03-16 10:49:09 +09005940 if (!work->aux_payload_buf) {
5941 err = -ENOMEM;
5942 goto out;
5943 }
5944
5945 memcpy(work->aux_payload_buf, rpc_resp->payload,
Namjae Jeon070fb212021-05-26 17:57:12 +09005946 rpc_resp->payload_sz);
Namjae Jeone2f34482021-03-16 10:49:09 +09005947
5948 nbytes = rpc_resp->payload_sz;
5949 work->resp_hdr_sz = get_rfc1002_len(rsp) + 4;
5950 work->aux_payload_sz = nbytes;
Namjae Jeon79f6b112021-04-02 12:47:14 +09005951 kvfree(rpc_resp);
Namjae Jeone2f34482021-03-16 10:49:09 +09005952 }
5953
5954 rsp->StructureSize = cpu_to_le16(17);
5955 rsp->DataOffset = 80;
5956 rsp->Reserved = 0;
5957 rsp->DataLength = cpu_to_le32(nbytes);
5958 rsp->DataRemaining = 0;
5959 rsp->Reserved2 = 0;
5960 inc_rfc1001_len(rsp, nbytes);
5961 return 0;
5962
5963out:
5964 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
5965 smb2_set_err_rsp(work);
Namjae Jeon79f6b112021-04-02 12:47:14 +09005966 kvfree(rpc_resp);
Namjae Jeone2f34482021-03-16 10:49:09 +09005967 return err;
5968}
5969
5970static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09005971 struct smb2_read_req *req, void *data_buf,
5972 size_t length)
Namjae Jeone2f34482021-03-16 10:49:09 +09005973{
5974 struct smb2_buffer_desc_v1 *desc =
5975 (struct smb2_buffer_desc_v1 *)&req->Buffer[0];
5976 int err;
5977
Namjae Jeon64b39f42021-03-30 14:25:35 +09005978 if (work->conn->dialect == SMB30_PROT_ID &&
5979 req->Channel != SMB2_CHANNEL_RDMA_V1)
Namjae Jeone2f34482021-03-16 10:49:09 +09005980 return -EINVAL;
5981
Namjae Jeon64b39f42021-03-30 14:25:35 +09005982 if (req->ReadChannelInfoOffset == 0 ||
5983 le16_to_cpu(req->ReadChannelInfoLength) < sizeof(*desc))
Namjae Jeone2f34482021-03-16 10:49:09 +09005984 return -EINVAL;
5985
5986 work->need_invalidate_rkey =
5987 (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
5988 work->remote_key = le32_to_cpu(desc->token);
5989
Namjae Jeon64b39f42021-03-30 14:25:35 +09005990 err = ksmbd_conn_rdma_write(work->conn, data_buf, length,
Namjae Jeon070fb212021-05-26 17:57:12 +09005991 le32_to_cpu(desc->token),
5992 le64_to_cpu(desc->offset),
5993 le32_to_cpu(desc->length));
Namjae Jeone2f34482021-03-16 10:49:09 +09005994 if (err)
5995 return err;
5996
5997 return length;
5998}
5999
6000/**
6001 * smb2_read() - handler for smb2 read from file
6002 * @work: smb work containing read command buffer
6003 *
6004 * Return: 0 on success, otherwise error
6005 */
6006int smb2_read(struct ksmbd_work *work)
6007{
6008 struct ksmbd_conn *conn = work->conn;
6009 struct smb2_read_req *req;
6010 struct smb2_read_rsp *rsp, *rsp_org;
6011 struct ksmbd_file *fp;
6012 loff_t offset;
6013 size_t length, mincount;
6014 ssize_t nbytes = 0, remain_bytes = 0;
6015 int err = 0;
6016
Namjae Jeone5066492021-03-30 12:35:23 +09006017 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006018 WORK_BUFFERS(work, req, rsp);
6019
6020 if (test_share_config_flag(work->tcon->share_conf,
6021 KSMBD_SHARE_FLAG_PIPE)) {
6022 ksmbd_debug(SMB, "IPC pipe read request\n");
6023 return smb2_read_pipe(work);
6024 }
6025
Namjae Jeon070fb212021-05-26 17:57:12 +09006026 fp = ksmbd_lookup_fd_slow(work, le64_to_cpu(req->VolatileFileId),
6027 le64_to_cpu(req->PersistentFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09006028 if (!fp) {
Marios Makassikisa4382db2021-05-06 11:34:52 +09006029 err = -ENOENT;
6030 goto out;
Namjae Jeone2f34482021-03-16 10:49:09 +09006031 }
6032
6033 if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_READ_ATTRIBUTES_LE))) {
Namjae Jeonbde16942021-06-28 15:23:19 +09006034 pr_err("Not permitted to read : 0x%x\n", fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09006035 err = -EACCES;
6036 goto out;
6037 }
6038
6039 offset = le64_to_cpu(req->Offset);
6040 length = le32_to_cpu(req->Length);
6041 mincount = le32_to_cpu(req->MinimumCount);
6042
6043 if (length > conn->vals->max_read_size) {
6044 ksmbd_debug(SMB, "limiting read size to max size(%u)\n",
6045 conn->vals->max_read_size);
6046 err = -EINVAL;
6047 goto out;
6048 }
6049
Namjae Jeon493fa2f2021-06-29 09:22:16 +09006050 ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n",
6051 fp->filp->f_path.dentry, offset, length);
Namjae Jeone2f34482021-03-16 10:49:09 +09006052
Namjae Jeonc30f4eb2021-06-18 10:17:37 +09006053 work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO);
Namjae Jeone2f34482021-03-16 10:49:09 +09006054 if (!work->aux_payload_buf) {
Dan Carpenterc1ea1112021-03-22 17:50:11 +03006055 err = -ENOMEM;
Namjae Jeone2f34482021-03-16 10:49:09 +09006056 goto out;
6057 }
6058
6059 nbytes = ksmbd_vfs_read(work, fp, length, &offset);
6060 if (nbytes < 0) {
6061 err = nbytes;
6062 goto out;
6063 }
6064
6065 if ((nbytes == 0 && length != 0) || nbytes < mincount) {
Namjae Jeonc30f4eb2021-06-18 10:17:37 +09006066 kvfree(work->aux_payload_buf);
Namjae Jeone5066492021-03-30 12:35:23 +09006067 work->aux_payload_buf = NULL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006068 rsp->hdr.Status = STATUS_END_OF_FILE;
6069 smb2_set_err_rsp(work);
6070 ksmbd_fd_put(work, fp);
6071 return 0;
6072 }
6073
6074 ksmbd_debug(SMB, "nbytes %zu, offset %lld mincount %zu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09006075 nbytes, offset, mincount);
Namjae Jeone2f34482021-03-16 10:49:09 +09006076
6077 if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09006078 req->Channel == SMB2_CHANNEL_RDMA_V1) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006079 /* write data to the client using rdma channel */
6080 remain_bytes = smb2_read_rdma_channel(work, req,
Namjae Jeon070fb212021-05-26 17:57:12 +09006081 work->aux_payload_buf,
6082 nbytes);
Namjae Jeonc30f4eb2021-06-18 10:17:37 +09006083 kvfree(work->aux_payload_buf);
Namjae Jeone5066492021-03-30 12:35:23 +09006084 work->aux_payload_buf = NULL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006085
6086 nbytes = 0;
6087 if (remain_bytes < 0) {
6088 err = (int)remain_bytes;
6089 goto out;
6090 }
6091 }
6092
6093 rsp->StructureSize = cpu_to_le16(17);
6094 rsp->DataOffset = 80;
6095 rsp->Reserved = 0;
6096 rsp->DataLength = cpu_to_le32(nbytes);
6097 rsp->DataRemaining = cpu_to_le32(remain_bytes);
6098 rsp->Reserved2 = 0;
6099 inc_rfc1001_len(rsp_org, 16);
6100 work->resp_hdr_sz = get_rfc1002_len(rsp_org) + 4;
6101 work->aux_payload_sz = nbytes;
6102 inc_rfc1001_len(rsp_org, nbytes);
6103 ksmbd_fd_put(work, fp);
6104 return 0;
6105
6106out:
6107 if (err) {
6108 if (err == -EISDIR)
6109 rsp->hdr.Status = STATUS_INVALID_DEVICE_REQUEST;
6110 else if (err == -EAGAIN)
6111 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
6112 else if (err == -ENOENT)
6113 rsp->hdr.Status = STATUS_FILE_CLOSED;
6114 else if (err == -EACCES)
6115 rsp->hdr.Status = STATUS_ACCESS_DENIED;
6116 else if (err == -ESHARE)
6117 rsp->hdr.Status = STATUS_SHARING_VIOLATION;
6118 else if (err == -EINVAL)
6119 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
6120 else
6121 rsp->hdr.Status = STATUS_INVALID_HANDLE;
6122
6123 smb2_set_err_rsp(work);
6124 }
6125 ksmbd_fd_put(work, fp);
6126 return err;
6127}
6128
6129/**
6130 * smb2_write_pipe() - handler for smb2 write on IPC pipe
6131 * @work: smb work containing write IPC pipe command buffer
6132 *
6133 * Return: 0 on success, otherwise error
6134 */
6135static noinline int smb2_write_pipe(struct ksmbd_work *work)
6136{
Namjae Jeone5066492021-03-30 12:35:23 +09006137 struct smb2_write_req *req = work->request_buf;
6138 struct smb2_write_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006139 struct ksmbd_rpc_command *rpc_resp;
Namjae Jeon64b39f42021-03-30 14:25:35 +09006140 u64 id = 0;
Namjae Jeone2f34482021-03-16 10:49:09 +09006141 int err = 0, ret = 0;
6142 char *data_buf;
6143 size_t length;
6144
6145 length = le32_to_cpu(req->Length);
6146 id = le64_to_cpu(req->VolatileFileId);
6147
6148 if (le16_to_cpu(req->DataOffset) ==
Namjae Jeon64b39f42021-03-30 14:25:35 +09006149 (offsetof(struct smb2_write_req, Buffer) - 4)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006150 data_buf = (char *)&req->Buffer[0];
6151 } else {
6152 if ((le16_to_cpu(req->DataOffset) > get_rfc1002_len(req)) ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09006153 (le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req))) {
Namjae Jeonbde16942021-06-28 15:23:19 +09006154 pr_err("invalid write data offset %u, smb_len %u\n",
6155 le16_to_cpu(req->DataOffset),
6156 get_rfc1002_len(req));
Namjae Jeone2f34482021-03-16 10:49:09 +09006157 err = -EINVAL;
6158 goto out;
6159 }
6160
6161 data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
6162 le16_to_cpu(req->DataOffset));
6163 }
6164
6165 rpc_resp = ksmbd_rpc_write(work->sess, id, data_buf, length);
6166 if (rpc_resp) {
6167 if (rpc_resp->flags == KSMBD_RPC_ENOTIMPLEMENTED) {
6168 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
Namjae Jeon79f6b112021-04-02 12:47:14 +09006169 kvfree(rpc_resp);
Namjae Jeone2f34482021-03-16 10:49:09 +09006170 smb2_set_err_rsp(work);
6171 return -EOPNOTSUPP;
6172 }
6173 if (rpc_resp->flags != KSMBD_RPC_OK) {
6174 rsp->hdr.Status = STATUS_INVALID_HANDLE;
6175 smb2_set_err_rsp(work);
Namjae Jeon79f6b112021-04-02 12:47:14 +09006176 kvfree(rpc_resp);
Namjae Jeone2f34482021-03-16 10:49:09 +09006177 return ret;
6178 }
Namjae Jeon79f6b112021-04-02 12:47:14 +09006179 kvfree(rpc_resp);
Namjae Jeone2f34482021-03-16 10:49:09 +09006180 }
6181
6182 rsp->StructureSize = cpu_to_le16(17);
6183 rsp->DataOffset = 0;
6184 rsp->Reserved = 0;
6185 rsp->DataLength = cpu_to_le32(length);
6186 rsp->DataRemaining = 0;
6187 rsp->Reserved2 = 0;
6188 inc_rfc1001_len(rsp, 16);
6189 return 0;
6190out:
6191 if (err) {
6192 rsp->hdr.Status = STATUS_INVALID_HANDLE;
6193 smb2_set_err_rsp(work);
6194 }
6195
6196 return err;
6197}
6198
6199static ssize_t smb2_write_rdma_channel(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09006200 struct smb2_write_req *req,
6201 struct ksmbd_file *fp,
6202 loff_t offset, size_t length, bool sync)
Namjae Jeone2f34482021-03-16 10:49:09 +09006203{
6204 struct smb2_buffer_desc_v1 *desc;
6205 char *data_buf;
6206 int ret;
6207 ssize_t nbytes;
6208
6209 desc = (struct smb2_buffer_desc_v1 *)&req->Buffer[0];
6210
6211 if (work->conn->dialect == SMB30_PROT_ID &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09006212 req->Channel != SMB2_CHANNEL_RDMA_V1)
Namjae Jeone2f34482021-03-16 10:49:09 +09006213 return -EINVAL;
6214
6215 if (req->Length != 0 || req->DataOffset != 0)
6216 return -EINVAL;
6217
Namjae Jeon64b39f42021-03-30 14:25:35 +09006218 if (req->WriteChannelInfoOffset == 0 ||
6219 le16_to_cpu(req->WriteChannelInfoLength) < sizeof(*desc))
Namjae Jeone2f34482021-03-16 10:49:09 +09006220 return -EINVAL;
6221
6222 work->need_invalidate_rkey =
6223 (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
6224 work->remote_key = le32_to_cpu(desc->token);
6225
Namjae Jeon79f6b112021-04-02 12:47:14 +09006226 data_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO);
Namjae Jeone2f34482021-03-16 10:49:09 +09006227 if (!data_buf)
6228 return -ENOMEM;
6229
6230 ret = ksmbd_conn_rdma_read(work->conn, data_buf, length,
Namjae Jeon070fb212021-05-26 17:57:12 +09006231 le32_to_cpu(desc->token),
6232 le64_to_cpu(desc->offset),
6233 le32_to_cpu(desc->length));
Namjae Jeone2f34482021-03-16 10:49:09 +09006234 if (ret < 0) {
Namjae Jeon79f6b112021-04-02 12:47:14 +09006235 kvfree(data_buf);
Namjae Jeone2f34482021-03-16 10:49:09 +09006236 return ret;
6237 }
6238
Namjae Jeon64b39f42021-03-30 14:25:35 +09006239 ret = ksmbd_vfs_write(work, fp, data_buf, length, &offset, sync, &nbytes);
Namjae Jeon79f6b112021-04-02 12:47:14 +09006240 kvfree(data_buf);
Namjae Jeone2f34482021-03-16 10:49:09 +09006241 if (ret < 0)
6242 return ret;
6243
6244 return nbytes;
6245}
6246
6247/**
6248 * smb2_write() - handler for smb2 write from file
6249 * @work: smb work containing write command buffer
6250 *
6251 * Return: 0 on success, otherwise error
6252 */
6253int smb2_write(struct ksmbd_work *work)
6254{
6255 struct smb2_write_req *req;
6256 struct smb2_write_rsp *rsp, *rsp_org;
Namjae Jeonbcd62a32021-05-10 09:08:19 +09006257 struct ksmbd_file *fp = NULL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006258 loff_t offset;
6259 size_t length;
6260 ssize_t nbytes;
6261 char *data_buf;
6262 bool writethrough = false;
6263 int err = 0;
6264
Namjae Jeone5066492021-03-30 12:35:23 +09006265 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006266 WORK_BUFFERS(work, req, rsp);
6267
Namjae Jeon64b39f42021-03-30 14:25:35 +09006268 if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006269 ksmbd_debug(SMB, "IPC pipe write request\n");
6270 return smb2_write_pipe(work);
6271 }
6272
6273 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
6274 ksmbd_debug(SMB, "User does not have write permission\n");
6275 err = -EACCES;
6276 goto out;
6277 }
6278
Namjae Jeon64b39f42021-03-30 14:25:35 +09006279 fp = ksmbd_lookup_fd_slow(work, le64_to_cpu(req->VolatileFileId),
Namjae Jeon070fb212021-05-26 17:57:12 +09006280 le64_to_cpu(req->PersistentFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09006281 if (!fp) {
Marios Makassikisa4382db2021-05-06 11:34:52 +09006282 err = -ENOENT;
6283 goto out;
Namjae Jeone2f34482021-03-16 10:49:09 +09006284 }
6285
6286 if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_READ_ATTRIBUTES_LE))) {
Namjae Jeonbde16942021-06-28 15:23:19 +09006287 pr_err("Not permitted to write : 0x%x\n", fp->daccess);
Namjae Jeone2f34482021-03-16 10:49:09 +09006288 err = -EACCES;
6289 goto out;
6290 }
6291
6292 offset = le64_to_cpu(req->Offset);
6293 length = le32_to_cpu(req->Length);
6294
6295 if (length > work->conn->vals->max_write_size) {
6296 ksmbd_debug(SMB, "limiting write size to max size(%u)\n",
6297 work->conn->vals->max_write_size);
6298 err = -EINVAL;
6299 goto out;
6300 }
6301
6302 if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH)
6303 writethrough = true;
6304
6305 if (req->Channel != SMB2_CHANNEL_RDMA_V1 &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09006306 req->Channel != SMB2_CHANNEL_RDMA_V1_INVALIDATE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006307 if (le16_to_cpu(req->DataOffset) ==
Namjae Jeon070fb212021-05-26 17:57:12 +09006308 (offsetof(struct smb2_write_req, Buffer) - 4)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006309 data_buf = (char *)&req->Buffer[0];
6310 } else {
Namjae Jeon64b39f42021-03-30 14:25:35 +09006311 if ((le16_to_cpu(req->DataOffset) > get_rfc1002_len(req)) ||
6312 (le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req))) {
Namjae Jeonbde16942021-06-28 15:23:19 +09006313 pr_err("invalid write data offset %u, smb_len %u\n",
6314 le16_to_cpu(req->DataOffset),
6315 get_rfc1002_len(req));
Namjae Jeone2f34482021-03-16 10:49:09 +09006316 err = -EINVAL;
6317 goto out;
6318 }
6319
6320 data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
6321 le16_to_cpu(req->DataOffset));
6322 }
6323
6324 ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags));
6325 if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH)
6326 writethrough = true;
6327
Namjae Jeon493fa2f2021-06-29 09:22:16 +09006328 ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n",
6329 fp->filp->f_path.dentry, offset, length);
Namjae Jeone2f34482021-03-16 10:49:09 +09006330 err = ksmbd_vfs_write(work, fp, data_buf, length, &offset,
6331 writethrough, &nbytes);
6332 if (err < 0)
6333 goto out;
6334 } else {
6335 /* read data from the client using rdma channel, and
6336 * write the data.
6337 */
6338 nbytes = smb2_write_rdma_channel(work, req, fp, offset,
Namjae Jeon070fb212021-05-26 17:57:12 +09006339 le32_to_cpu(req->RemainingBytes),
6340 writethrough);
Namjae Jeone2f34482021-03-16 10:49:09 +09006341 if (nbytes < 0) {
6342 err = (int)nbytes;
6343 goto out;
6344 }
6345 }
6346
6347 rsp->StructureSize = cpu_to_le16(17);
6348 rsp->DataOffset = 0;
6349 rsp->Reserved = 0;
6350 rsp->DataLength = cpu_to_le32(nbytes);
6351 rsp->DataRemaining = 0;
6352 rsp->Reserved2 = 0;
6353 inc_rfc1001_len(rsp_org, 16);
6354 ksmbd_fd_put(work, fp);
6355 return 0;
6356
6357out:
6358 if (err == -EAGAIN)
6359 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
6360 else if (err == -ENOSPC || err == -EFBIG)
6361 rsp->hdr.Status = STATUS_DISK_FULL;
6362 else if (err == -ENOENT)
6363 rsp->hdr.Status = STATUS_FILE_CLOSED;
6364 else if (err == -EACCES)
6365 rsp->hdr.Status = STATUS_ACCESS_DENIED;
6366 else if (err == -ESHARE)
6367 rsp->hdr.Status = STATUS_SHARING_VIOLATION;
6368 else if (err == -EINVAL)
6369 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
6370 else
6371 rsp->hdr.Status = STATUS_INVALID_HANDLE;
6372
6373 smb2_set_err_rsp(work);
6374 ksmbd_fd_put(work, fp);
6375 return err;
6376}
6377
6378/**
6379 * smb2_flush() - handler for smb2 flush file - fsync
6380 * @work: smb work containing flush command buffer
6381 *
6382 * Return: 0 on success, otherwise error
6383 */
6384int smb2_flush(struct ksmbd_work *work)
6385{
6386 struct smb2_flush_req *req;
6387 struct smb2_flush_rsp *rsp, *rsp_org;
6388 int err;
6389
Namjae Jeone5066492021-03-30 12:35:23 +09006390 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006391 WORK_BUFFERS(work, req, rsp);
6392
6393 ksmbd_debug(SMB, "SMB2_FLUSH called for fid %llu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09006394 le64_to_cpu(req->VolatileFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09006395
6396 err = ksmbd_vfs_fsync(work,
6397 le64_to_cpu(req->VolatileFileId),
6398 le64_to_cpu(req->PersistentFileId));
6399 if (err)
6400 goto out;
6401
6402 rsp->StructureSize = cpu_to_le16(4);
6403 rsp->Reserved = 0;
6404 inc_rfc1001_len(rsp_org, 4);
6405 return 0;
6406
6407out:
6408 if (err) {
6409 rsp->hdr.Status = STATUS_INVALID_HANDLE;
6410 smb2_set_err_rsp(work);
6411 }
6412
6413 return err;
6414}
6415
6416/**
6417 * smb2_cancel() - handler for smb2 cancel command
6418 * @work: smb work containing cancel command buffer
6419 *
6420 * Return: 0 on success, otherwise error
6421 */
6422int smb2_cancel(struct ksmbd_work *work)
6423{
6424 struct ksmbd_conn *conn = work->conn;
Namjae Jeone5066492021-03-30 12:35:23 +09006425 struct smb2_hdr *hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006426 struct smb2_hdr *chdr;
6427 struct ksmbd_work *cancel_work = NULL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006428 int canceled = 0;
6429 struct list_head *command_list;
6430
6431 ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09006432 hdr->MessageId, hdr->Flags);
Namjae Jeone2f34482021-03-16 10:49:09 +09006433
6434 if (hdr->Flags & SMB2_FLAGS_ASYNC_COMMAND) {
6435 command_list = &conn->async_requests;
6436
6437 spin_lock(&conn->request_lock);
Namjae Jeon6f3d5ee2021-06-18 10:28:52 +09006438 list_for_each_entry(cancel_work, command_list,
6439 async_request_entry) {
Namjae Jeone5066492021-03-30 12:35:23 +09006440 chdr = cancel_work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006441
6442 if (cancel_work->async_id !=
Namjae Jeon64b39f42021-03-30 14:25:35 +09006443 le64_to_cpu(hdr->Id.AsyncId))
Namjae Jeone2f34482021-03-16 10:49:09 +09006444 continue;
6445
6446 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09006447 "smb2 with AsyncId %llu cancelled command = 0x%x\n",
6448 le64_to_cpu(hdr->Id.AsyncId),
6449 le16_to_cpu(chdr->Command));
Namjae Jeone2f34482021-03-16 10:49:09 +09006450 canceled = 1;
6451 break;
6452 }
6453 spin_unlock(&conn->request_lock);
6454 } else {
6455 command_list = &conn->requests;
6456
6457 spin_lock(&conn->request_lock);
Namjae Jeon6f3d5ee2021-06-18 10:28:52 +09006458 list_for_each_entry(cancel_work, command_list, request_entry) {
Namjae Jeone5066492021-03-30 12:35:23 +09006459 chdr = cancel_work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006460
6461 if (chdr->MessageId != hdr->MessageId ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09006462 cancel_work == work)
Namjae Jeone2f34482021-03-16 10:49:09 +09006463 continue;
6464
6465 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09006466 "smb2 with mid %llu cancelled command = 0x%x\n",
6467 le64_to_cpu(hdr->MessageId),
6468 le16_to_cpu(chdr->Command));
Namjae Jeone2f34482021-03-16 10:49:09 +09006469 canceled = 1;
6470 break;
6471 }
6472 spin_unlock(&conn->request_lock);
6473 }
6474
6475 if (canceled) {
6476 cancel_work->state = KSMBD_WORK_CANCELLED;
6477 if (cancel_work->cancel_fn)
6478 cancel_work->cancel_fn(cancel_work->cancel_argv);
6479 }
6480
6481 /* For SMB2_CANCEL command itself send no response*/
6482 work->send_no_response = 1;
6483 return 0;
6484}
6485
6486struct file_lock *smb_flock_init(struct file *f)
6487{
6488 struct file_lock *fl;
6489
6490 fl = locks_alloc_lock();
6491 if (!fl)
6492 goto out;
6493
6494 locks_init_lock(fl);
6495
6496 fl->fl_owner = f;
6497 fl->fl_pid = current->tgid;
6498 fl->fl_file = f;
6499 fl->fl_flags = FL_POSIX;
6500 fl->fl_ops = NULL;
6501 fl->fl_lmops = NULL;
6502
6503out:
6504 return fl;
6505}
6506
6507static int smb2_set_flock_flags(struct file_lock *flock, int flags)
6508{
6509 int cmd = -EINVAL;
6510
6511 /* Checking for wrong flag combination during lock request*/
6512 switch (flags) {
6513 case SMB2_LOCKFLAG_SHARED:
6514 ksmbd_debug(SMB, "received shared request\n");
6515 cmd = F_SETLKW;
6516 flock->fl_type = F_RDLCK;
6517 flock->fl_flags |= FL_SLEEP;
6518 break;
6519 case SMB2_LOCKFLAG_EXCLUSIVE:
6520 ksmbd_debug(SMB, "received exclusive request\n");
6521 cmd = F_SETLKW;
6522 flock->fl_type = F_WRLCK;
6523 flock->fl_flags |= FL_SLEEP;
6524 break;
Namjae Jeon64b39f42021-03-30 14:25:35 +09006525 case SMB2_LOCKFLAG_SHARED | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
Namjae Jeone2f34482021-03-16 10:49:09 +09006526 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09006527 "received shared & fail immediately request\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09006528 cmd = F_SETLK;
6529 flock->fl_type = F_RDLCK;
6530 break;
Namjae Jeon64b39f42021-03-30 14:25:35 +09006531 case SMB2_LOCKFLAG_EXCLUSIVE | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
Namjae Jeone2f34482021-03-16 10:49:09 +09006532 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09006533 "received exclusive & fail immediately request\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09006534 cmd = F_SETLK;
6535 flock->fl_type = F_WRLCK;
6536 break;
6537 case SMB2_LOCKFLAG_UNLOCK:
6538 ksmbd_debug(SMB, "received unlock request\n");
6539 flock->fl_type = F_UNLCK;
6540 cmd = 0;
6541 break;
6542 }
6543
6544 return cmd;
6545}
6546
6547static struct ksmbd_lock *smb2_lock_init(struct file_lock *flock,
Namjae Jeon070fb212021-05-26 17:57:12 +09006548 unsigned int cmd, int flags,
6549 struct list_head *lock_list)
Namjae Jeone2f34482021-03-16 10:49:09 +09006550{
6551 struct ksmbd_lock *lock;
6552
6553 lock = kzalloc(sizeof(struct ksmbd_lock), GFP_KERNEL);
6554 if (!lock)
6555 return NULL;
6556
6557 lock->cmd = cmd;
6558 lock->fl = flock;
6559 lock->start = flock->fl_start;
6560 lock->end = flock->fl_end;
6561 lock->flags = flags;
6562 if (lock->start == lock->end)
6563 lock->zero_len = 1;
Hyunchul Leed63528e2021-07-10 16:22:41 +09006564 INIT_LIST_HEAD(&lock->clist);
6565 INIT_LIST_HEAD(&lock->flist);
Namjae Jeone2f34482021-03-16 10:49:09 +09006566 INIT_LIST_HEAD(&lock->llist);
Namjae Jeone2f34482021-03-16 10:49:09 +09006567 list_add_tail(&lock->llist, lock_list);
6568
6569 return lock;
6570}
6571
6572static void smb2_remove_blocked_lock(void **argv)
6573{
6574 struct file_lock *flock = (struct file_lock *)argv[0];
6575
6576 ksmbd_vfs_posix_lock_unblock(flock);
6577 wake_up(&flock->fl_wait);
6578}
6579
6580static inline bool lock_defer_pending(struct file_lock *fl)
6581{
6582 /* check pending lock waiters */
6583 return waitqueue_active(&fl->fl_wait);
6584}
6585
6586/**
6587 * smb2_lock() - handler for smb2 file lock command
6588 * @work: smb work containing lock command buffer
6589 *
6590 * Return: 0 on success, otherwise error
6591 */
6592int smb2_lock(struct ksmbd_work *work)
6593{
Namjae Jeone5066492021-03-30 12:35:23 +09006594 struct smb2_lock_req *req = work->request_buf;
6595 struct smb2_lock_rsp *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09006596 struct smb2_lock_element *lock_ele;
6597 struct ksmbd_file *fp = NULL;
6598 struct file_lock *flock = NULL;
6599 struct file *filp = NULL;
6600 int lock_count;
6601 int flags = 0;
6602 int cmd = 0;
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006603 int err = -EIO, i, rc = 0;
Namjae Jeon50bf80a2021-05-14 12:20:07 +09006604 u64 lock_start, lock_length;
Hyunchul Leed63528e2021-07-10 16:22:41 +09006605 struct ksmbd_lock *smb_lock = NULL, *cmp_lock, *tmp, *tmp2;
6606 struct ksmbd_conn *conn;
Namjae Jeone2f34482021-03-16 10:49:09 +09006607 int nolock = 0;
6608 LIST_HEAD(lock_list);
6609 LIST_HEAD(rollback_list);
6610 int prior_lock = 0;
6611
6612 ksmbd_debug(SMB, "Received lock request\n");
6613 fp = ksmbd_lookup_fd_slow(work,
Namjae Jeon070fb212021-05-26 17:57:12 +09006614 le64_to_cpu(req->VolatileFileId),
6615 le64_to_cpu(req->PersistentFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09006616 if (!fp) {
6617 ksmbd_debug(SMB, "Invalid file id for lock : %llu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09006618 le64_to_cpu(req->VolatileFileId));
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006619 err = -ENOENT;
Namjae Jeone2f34482021-03-16 10:49:09 +09006620 goto out2;
6621 }
6622
6623 filp = fp->filp;
6624 lock_count = le16_to_cpu(req->LockCount);
6625 lock_ele = req->locks;
6626
6627 ksmbd_debug(SMB, "lock count is %d\n", lock_count);
Namjae Jeon070fb212021-05-26 17:57:12 +09006628 if (!lock_count) {
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006629 err = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006630 goto out2;
6631 }
6632
6633 for (i = 0; i < lock_count; i++) {
6634 flags = le32_to_cpu(lock_ele[i].Flags);
6635
6636 flock = smb_flock_init(filp);
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006637 if (!flock)
Namjae Jeone2f34482021-03-16 10:49:09 +09006638 goto out;
Namjae Jeone2f34482021-03-16 10:49:09 +09006639
6640 cmd = smb2_set_flock_flags(flock, flags);
6641
Namjae Jeon50bf80a2021-05-14 12:20:07 +09006642 lock_start = le64_to_cpu(lock_ele[i].Offset);
6643 lock_length = le64_to_cpu(lock_ele[i].Length);
6644 if (lock_start > U64_MAX - lock_length) {
Namjae Jeonbde16942021-06-28 15:23:19 +09006645 pr_err("Invalid lock range requested\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09006646 rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE;
6647 goto out;
6648 }
6649
Namjae Jeon50bf80a2021-05-14 12:20:07 +09006650 if (lock_start > OFFSET_MAX)
6651 flock->fl_start = OFFSET_MAX;
6652 else
6653 flock->fl_start = lock_start;
6654
Namjae Jeone2f34482021-03-16 10:49:09 +09006655 lock_length = le64_to_cpu(lock_ele[i].Length);
Namjae Jeon50bf80a2021-05-14 12:20:07 +09006656 if (lock_length > OFFSET_MAX - flock->fl_start)
6657 lock_length = OFFSET_MAX - flock->fl_start;
Namjae Jeone2f34482021-03-16 10:49:09 +09006658
6659 flock->fl_end = flock->fl_start + lock_length;
6660
6661 if (flock->fl_end < flock->fl_start) {
6662 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09006663 "the end offset(%llx) is smaller than the start offset(%llx)\n",
6664 flock->fl_end, flock->fl_start);
Namjae Jeone2f34482021-03-16 10:49:09 +09006665 rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE;
6666 goto out;
6667 }
6668
6669 /* Check conflict locks in one request */
6670 list_for_each_entry(cmp_lock, &lock_list, llist) {
6671 if (cmp_lock->fl->fl_start <= flock->fl_start &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09006672 cmp_lock->fl->fl_end >= flock->fl_end) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006673 if (cmp_lock->fl->fl_type != F_UNLCK &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09006674 flock->fl_type != F_UNLCK) {
Namjae Jeonbde16942021-06-28 15:23:19 +09006675 pr_err("conflict two locks in one request\n");
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006676 err = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006677 goto out;
6678 }
6679 }
6680 }
6681
6682 smb_lock = smb2_lock_init(flock, cmd, flags, &lock_list);
6683 if (!smb_lock) {
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006684 err = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006685 goto out;
6686 }
6687 }
6688
6689 list_for_each_entry_safe(smb_lock, tmp, &lock_list, llist) {
6690 if (smb_lock->cmd < 0) {
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006691 err = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006692 goto out;
6693 }
6694
6695 if (!(smb_lock->flags & SMB2_LOCKFLAG_MASK)) {
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006696 err = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006697 goto out;
6698 }
6699
Namjae Jeon64b39f42021-03-30 14:25:35 +09006700 if ((prior_lock & (SMB2_LOCKFLAG_EXCLUSIVE | SMB2_LOCKFLAG_SHARED) &&
6701 smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) ||
6702 (prior_lock == SMB2_LOCKFLAG_UNLOCK &&
6703 !(smb_lock->flags & SMB2_LOCKFLAG_UNLOCK))) {
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006704 err = -EINVAL;
Namjae Jeone2f34482021-03-16 10:49:09 +09006705 goto out;
6706 }
6707
6708 prior_lock = smb_lock->flags;
6709
6710 if (!(smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09006711 !(smb_lock->flags & SMB2_LOCKFLAG_FAIL_IMMEDIATELY))
Hyunchul Leed63528e2021-07-10 16:22:41 +09006712 goto no_check_cl;
Namjae Jeone2f34482021-03-16 10:49:09 +09006713
6714 nolock = 1;
Hyunchul Leed63528e2021-07-10 16:22:41 +09006715 /* check locks in connection list */
6716 read_lock(&conn_list_lock);
6717 list_for_each_entry(conn, &conn_list, conns_list) {
6718 spin_lock(&conn->llist_lock);
6719 list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) {
6720 if (file_inode(cmp_lock->fl->fl_file) !=
6721 file_inode(smb_lock->fl->fl_file))
6722 continue;
Namjae Jeone2f34482021-03-16 10:49:09 +09006723
Hyunchul Leed63528e2021-07-10 16:22:41 +09006724 if (smb_lock->fl->fl_type == F_UNLCK) {
6725 if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file &&
6726 cmp_lock->start == smb_lock->start &&
6727 cmp_lock->end == smb_lock->end &&
6728 !lock_defer_pending(cmp_lock->fl)) {
6729 nolock = 0;
6730 list_del(&cmp_lock->flist);
6731 list_del(&cmp_lock->clist);
6732 spin_unlock(&conn->llist_lock);
6733 read_unlock(&conn_list_lock);
6734
6735 locks_free_lock(cmp_lock->fl);
6736 kfree(cmp_lock);
6737 goto out_check_cl;
6738 }
6739 continue;
Namjae Jeone2f34482021-03-16 10:49:09 +09006740 }
Namjae Jeone2f34482021-03-16 10:49:09 +09006741
Hyunchul Leed63528e2021-07-10 16:22:41 +09006742 if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file) {
6743 if (smb_lock->flags & SMB2_LOCKFLAG_SHARED)
6744 continue;
6745 } else {
6746 if (cmp_lock->flags & SMB2_LOCKFLAG_SHARED)
6747 continue;
6748 }
Namjae Jeone2f34482021-03-16 10:49:09 +09006749
Hyunchul Leed63528e2021-07-10 16:22:41 +09006750 /* check zero byte lock range */
6751 if (cmp_lock->zero_len && !smb_lock->zero_len &&
6752 cmp_lock->start > smb_lock->start &&
6753 cmp_lock->start < smb_lock->end) {
6754 spin_unlock(&conn->llist_lock);
6755 read_unlock(&conn_list_lock);
6756 pr_err("previous lock conflict with zero byte lock range\n");
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006757 goto out;
Hyunchul Leed63528e2021-07-10 16:22:41 +09006758 }
Namjae Jeone2f34482021-03-16 10:49:09 +09006759
Hyunchul Leed63528e2021-07-10 16:22:41 +09006760 if (smb_lock->zero_len && !cmp_lock->zero_len &&
6761 smb_lock->start > cmp_lock->start &&
6762 smb_lock->start < cmp_lock->end) {
6763 spin_unlock(&conn->llist_lock);
6764 read_unlock(&conn_list_lock);
6765 pr_err("current lock conflict with zero byte lock range\n");
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006766 goto out;
Hyunchul Leed63528e2021-07-10 16:22:41 +09006767 }
Namjae Jeone2f34482021-03-16 10:49:09 +09006768
Hyunchul Leed63528e2021-07-10 16:22:41 +09006769 if (((cmp_lock->start <= smb_lock->start &&
6770 cmp_lock->end > smb_lock->start) ||
6771 (cmp_lock->start < smb_lock->end &&
6772 cmp_lock->end >= smb_lock->end)) &&
6773 !cmp_lock->zero_len && !smb_lock->zero_len) {
6774 spin_unlock(&conn->llist_lock);
6775 read_unlock(&conn_list_lock);
6776 pr_err("Not allow lock operation on exclusive lock range\n");
Hyunchul Leed63528e2021-07-10 16:22:41 +09006777 goto out;
6778 }
Namjae Jeone2f34482021-03-16 10:49:09 +09006779 }
Hyunchul Leed63528e2021-07-10 16:22:41 +09006780 spin_unlock(&conn->llist_lock);
Namjae Jeone2f34482021-03-16 10:49:09 +09006781 }
Hyunchul Leed63528e2021-07-10 16:22:41 +09006782 read_unlock(&conn_list_lock);
6783out_check_cl:
Namjae Jeone2f34482021-03-16 10:49:09 +09006784 if (smb_lock->fl->fl_type == F_UNLCK && nolock) {
Namjae Jeonbde16942021-06-28 15:23:19 +09006785 pr_err("Try to unlock nolocked range\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09006786 rsp->hdr.Status = STATUS_RANGE_NOT_LOCKED;
6787 goto out;
6788 }
6789
Hyunchul Leed63528e2021-07-10 16:22:41 +09006790no_check_cl:
Namjae Jeone2f34482021-03-16 10:49:09 +09006791 if (smb_lock->zero_len) {
6792 err = 0;
6793 goto skip;
6794 }
6795
6796 flock = smb_lock->fl;
6797 list_del(&smb_lock->llist);
6798retry:
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006799 rc = vfs_lock_file(filp, smb_lock->cmd, flock, NULL);
Namjae Jeone2f34482021-03-16 10:49:09 +09006800skip:
6801 if (flags & SMB2_LOCKFLAG_UNLOCK) {
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006802 if (!rc) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006803 ksmbd_debug(SMB, "File unlocked\n");
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006804 } else if (rc == -ENOENT) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006805 rsp->hdr.Status = STATUS_NOT_LOCKED;
6806 goto out;
6807 }
6808 locks_free_lock(flock);
6809 kfree(smb_lock);
6810 } else {
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006811 if (rc == FILE_LOCK_DEFERRED) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006812 void **argv;
6813
6814 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09006815 "would have to wait for getting lock\n");
Hyunchul Leed63528e2021-07-10 16:22:41 +09006816 spin_lock(&work->conn->llist_lock);
6817 list_add_tail(&smb_lock->clist,
6818 &work->conn->lock_list);
6819 spin_unlock(&work->conn->llist_lock);
Namjae Jeone2f34482021-03-16 10:49:09 +09006820 list_add(&smb_lock->llist, &rollback_list);
6821
6822 argv = kmalloc(sizeof(void *), GFP_KERNEL);
6823 if (!argv) {
6824 err = -ENOMEM;
6825 goto out;
6826 }
6827 argv[0] = flock;
6828
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006829 rc = setup_async_work(work,
6830 smb2_remove_blocked_lock,
6831 argv);
6832 if (rc) {
6833 err = -ENOMEM;
Namjae Jeone2f34482021-03-16 10:49:09 +09006834 goto out;
6835 }
6836 spin_lock(&fp->f_lock);
6837 list_add(&work->fp_entry, &fp->blocked_works);
6838 spin_unlock(&fp->f_lock);
6839
6840 smb2_send_interim_resp(work, STATUS_PENDING);
6841
Hyunchul Lee45a64e82021-07-10 09:34:20 +09006842 ksmbd_vfs_posix_lock_wait(flock);
Namjae Jeone2f34482021-03-16 10:49:09 +09006843
Hyunchul Leed4075ab2021-06-25 07:02:10 +09006844 if (work->state != KSMBD_WORK_ACTIVE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006845 list_del(&smb_lock->llist);
Hyunchul Leed63528e2021-07-10 16:22:41 +09006846 spin_lock(&work->conn->llist_lock);
6847 list_del(&smb_lock->clist);
6848 spin_unlock(&work->conn->llist_lock);
Namjae Jeone2f34482021-03-16 10:49:09 +09006849 locks_free_lock(flock);
6850
Hyunchul Leed4075ab2021-06-25 07:02:10 +09006851 if (work->state == KSMBD_WORK_CANCELLED) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006852 spin_lock(&fp->f_lock);
6853 list_del(&work->fp_entry);
6854 spin_unlock(&fp->f_lock);
6855 rsp->hdr.Status =
6856 STATUS_CANCELLED;
6857 kfree(smb_lock);
6858 smb2_send_interim_resp(work,
Namjae Jeon070fb212021-05-26 17:57:12 +09006859 STATUS_CANCELLED);
Namjae Jeone2f34482021-03-16 10:49:09 +09006860 work->send_no_response = 1;
6861 goto out;
6862 }
6863 init_smb2_rsp_hdr(work);
6864 smb2_set_err_rsp(work);
6865 rsp->hdr.Status =
6866 STATUS_RANGE_NOT_LOCKED;
6867 kfree(smb_lock);
6868 goto out2;
6869 }
6870
6871 list_del(&smb_lock->llist);
Hyunchul Leed63528e2021-07-10 16:22:41 +09006872 spin_lock(&work->conn->llist_lock);
6873 list_del(&smb_lock->clist);
6874 spin_unlock(&work->conn->llist_lock);
6875
Namjae Jeone2f34482021-03-16 10:49:09 +09006876 spin_lock(&fp->f_lock);
6877 list_del(&work->fp_entry);
6878 spin_unlock(&fp->f_lock);
6879 goto retry;
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006880 } else if (!rc) {
Hyunchul Leed63528e2021-07-10 16:22:41 +09006881 spin_lock(&work->conn->llist_lock);
6882 list_add_tail(&smb_lock->clist,
6883 &work->conn->lock_list);
6884 list_add_tail(&smb_lock->flist,
6885 &fp->lock_list);
6886 spin_unlock(&work->conn->llist_lock);
Namjae Jeone2f34482021-03-16 10:49:09 +09006887 list_add(&smb_lock->llist, &rollback_list);
6888 ksmbd_debug(SMB, "successful in taking lock\n");
6889 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09006890 goto out;
6891 }
6892 }
6893 }
6894
6895 if (atomic_read(&fp->f_ci->op_count) > 1)
6896 smb_break_all_oplock(work, fp);
6897
6898 rsp->StructureSize = cpu_to_le16(4);
6899 ksmbd_debug(SMB, "successful in taking lock\n");
6900 rsp->hdr.Status = STATUS_SUCCESS;
6901 rsp->Reserved = 0;
6902 inc_rfc1001_len(rsp, 4);
6903 ksmbd_fd_put(work, fp);
Namjae Jeon96ad4ec2021-07-13 17:17:28 +09006904 return 0;
Namjae Jeone2f34482021-03-16 10:49:09 +09006905
6906out:
6907 list_for_each_entry_safe(smb_lock, tmp, &lock_list, llist) {
6908 locks_free_lock(smb_lock->fl);
6909 list_del(&smb_lock->llist);
6910 kfree(smb_lock);
6911 }
6912
6913 list_for_each_entry_safe(smb_lock, tmp, &rollback_list, llist) {
6914 struct file_lock *rlock = NULL;
6915
6916 rlock = smb_flock_init(filp);
6917 rlock->fl_type = F_UNLCK;
6918 rlock->fl_start = smb_lock->start;
6919 rlock->fl_end = smb_lock->end;
6920
Namjae Jeon96ad4ec2021-07-13 17:17:28 +09006921 rc = vfs_lock_file(filp, 0, rlock, NULL);
6922 if (rc)
6923 pr_err("rollback unlock fail : %d\n", rc);
Hyunchul Leed63528e2021-07-10 16:22:41 +09006924
Namjae Jeone2f34482021-03-16 10:49:09 +09006925 list_del(&smb_lock->llist);
Hyunchul Leed63528e2021-07-10 16:22:41 +09006926 spin_lock(&work->conn->llist_lock);
6927 if (!list_empty(&smb_lock->flist))
6928 list_del(&smb_lock->flist);
6929 list_del(&smb_lock->clist);
6930 spin_unlock(&work->conn->llist_lock);
6931
Namjae Jeone2f34482021-03-16 10:49:09 +09006932 locks_free_lock(smb_lock->fl);
6933 locks_free_lock(rlock);
6934 kfree(smb_lock);
6935 }
6936out2:
Namjae Jeon6c99dfc2021-07-27 09:40:05 +09006937 ksmbd_debug(SMB, "failed in taking lock(flags : %x), err : %d\n", flags, err);
6938
6939 if (!rsp->hdr.Status) {
6940 if (err == -EINVAL)
6941 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
6942 else if (err == -ENOMEM)
6943 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
6944 else if (err == -ENOENT)
6945 rsp->hdr.Status = STATUS_FILE_CLOSED;
6946 else
6947 rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED;
6948 }
6949
Namjae Jeone2f34482021-03-16 10:49:09 +09006950 smb2_set_err_rsp(work);
6951 ksmbd_fd_put(work, fp);
Namjae Jeon96ad4ec2021-07-13 17:17:28 +09006952 return err;
Namjae Jeone2f34482021-03-16 10:49:09 +09006953}
6954
Namjae Jeon64b39f42021-03-30 14:25:35 +09006955static int fsctl_copychunk(struct ksmbd_work *work, struct smb2_ioctl_req *req,
Namjae Jeon070fb212021-05-26 17:57:12 +09006956 struct smb2_ioctl_rsp *rsp)
Namjae Jeone2f34482021-03-16 10:49:09 +09006957{
6958 struct copychunk_ioctl_req *ci_req;
6959 struct copychunk_ioctl_rsp *ci_rsp;
6960 struct ksmbd_file *src_fp = NULL, *dst_fp = NULL;
6961 struct srv_copychunk *chunks;
6962 unsigned int i, chunk_count, chunk_count_written = 0;
6963 unsigned int chunk_size_written = 0;
6964 loff_t total_size_written = 0;
6965 int ret, cnt_code;
6966
6967 cnt_code = le32_to_cpu(req->CntCode);
6968 ci_req = (struct copychunk_ioctl_req *)&req->Buffer[0];
6969 ci_rsp = (struct copychunk_ioctl_rsp *)&rsp->Buffer[0];
6970
6971 rsp->VolatileFileId = req->VolatileFileId;
6972 rsp->PersistentFileId = req->PersistentFileId;
Namjae Jeon64b39f42021-03-30 14:25:35 +09006973 ci_rsp->ChunksWritten =
6974 cpu_to_le32(ksmbd_server_side_copy_max_chunk_count());
6975 ci_rsp->ChunkBytesWritten =
6976 cpu_to_le32(ksmbd_server_side_copy_max_chunk_size());
6977 ci_rsp->TotalBytesWritten =
6978 cpu_to_le32(ksmbd_server_side_copy_max_total_size());
Namjae Jeone2f34482021-03-16 10:49:09 +09006979
6980 chunks = (struct srv_copychunk *)&ci_req->Chunks[0];
6981 chunk_count = le32_to_cpu(ci_req->ChunkCount);
6982 total_size_written = 0;
6983
6984 /* verify the SRV_COPYCHUNK_COPY packet */
6985 if (chunk_count > ksmbd_server_side_copy_max_chunk_count() ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09006986 le32_to_cpu(req->InputCount) <
6987 offsetof(struct copychunk_ioctl_req, Chunks) +
6988 chunk_count * sizeof(struct srv_copychunk)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09006989 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
6990 return -EINVAL;
6991 }
6992
6993 for (i = 0; i < chunk_count; i++) {
6994 if (le32_to_cpu(chunks[i].Length) == 0 ||
Namjae Jeon64b39f42021-03-30 14:25:35 +09006995 le32_to_cpu(chunks[i].Length) > ksmbd_server_side_copy_max_chunk_size())
Namjae Jeone2f34482021-03-16 10:49:09 +09006996 break;
6997 total_size_written += le32_to_cpu(chunks[i].Length);
6998 }
Namjae Jeon64b39f42021-03-30 14:25:35 +09006999
7000 if (i < chunk_count ||
7001 total_size_written > ksmbd_server_side_copy_max_total_size()) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007002 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
7003 return -EINVAL;
7004 }
7005
7006 src_fp = ksmbd_lookup_foreign_fd(work,
Namjae Jeon070fb212021-05-26 17:57:12 +09007007 le64_to_cpu(ci_req->ResumeKey[0]));
Namjae Jeone2f34482021-03-16 10:49:09 +09007008 dst_fp = ksmbd_lookup_fd_slow(work,
Namjae Jeon070fb212021-05-26 17:57:12 +09007009 le64_to_cpu(req->VolatileFileId),
7010 le64_to_cpu(req->PersistentFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09007011 ret = -EINVAL;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007012 if (!src_fp ||
7013 src_fp->persistent_id != le64_to_cpu(ci_req->ResumeKey[1])) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007014 rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND;
7015 goto out;
7016 }
Namjae Jeon64b39f42021-03-30 14:25:35 +09007017
Namjae Jeone2f34482021-03-16 10:49:09 +09007018 if (!dst_fp) {
7019 rsp->hdr.Status = STATUS_FILE_CLOSED;
7020 goto out;
7021 }
7022
7023 /*
7024 * FILE_READ_DATA should only be included in
7025 * the FSCTL_COPYCHUNK case
7026 */
Namjae Jeon070fb212021-05-26 17:57:12 +09007027 if (cnt_code == FSCTL_COPYCHUNK &&
7028 !(dst_fp->daccess & (FILE_READ_DATA_LE | FILE_GENERIC_READ_LE))) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007029 rsp->hdr.Status = STATUS_ACCESS_DENIED;
7030 goto out;
7031 }
7032
7033 ret = ksmbd_vfs_copy_file_ranges(work, src_fp, dst_fp,
Namjae Jeon070fb212021-05-26 17:57:12 +09007034 chunks, chunk_count,
7035 &chunk_count_written,
7036 &chunk_size_written,
7037 &total_size_written);
Namjae Jeone2f34482021-03-16 10:49:09 +09007038 if (ret < 0) {
7039 if (ret == -EACCES)
7040 rsp->hdr.Status = STATUS_ACCESS_DENIED;
7041 if (ret == -EAGAIN)
7042 rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
7043 else if (ret == -EBADF)
7044 rsp->hdr.Status = STATUS_INVALID_HANDLE;
7045 else if (ret == -EFBIG || ret == -ENOSPC)
7046 rsp->hdr.Status = STATUS_DISK_FULL;
7047 else if (ret == -EINVAL)
7048 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
7049 else if (ret == -EISDIR)
7050 rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
7051 else if (ret == -E2BIG)
7052 rsp->hdr.Status = STATUS_INVALID_VIEW_SIZE;
7053 else
7054 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
7055 }
7056
7057 ci_rsp->ChunksWritten = cpu_to_le32(chunk_count_written);
7058 ci_rsp->ChunkBytesWritten = cpu_to_le32(chunk_size_written);
7059 ci_rsp->TotalBytesWritten = cpu_to_le32(total_size_written);
7060out:
7061 ksmbd_fd_put(work, src_fp);
7062 ksmbd_fd_put(work, dst_fp);
7063 return ret;
7064}
7065
7066static __be32 idev_ipv4_address(struct in_device *idev)
7067{
7068 __be32 addr = 0;
7069
7070 struct in_ifaddr *ifa;
7071
7072 rcu_read_lock();
7073 in_dev_for_each_ifa_rcu(ifa, idev) {
7074 if (ifa->ifa_flags & IFA_F_SECONDARY)
7075 continue;
7076
7077 addr = ifa->ifa_address;
7078 break;
7079 }
7080 rcu_read_unlock();
7081 return addr;
7082}
7083
7084static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn,
Namjae Jeon070fb212021-05-26 17:57:12 +09007085 struct smb2_ioctl_req *req,
7086 struct smb2_ioctl_rsp *rsp)
Namjae Jeone2f34482021-03-16 10:49:09 +09007087{
7088 struct network_interface_info_ioctl_rsp *nii_rsp = NULL;
7089 int nbytes = 0;
7090 struct net_device *netdev;
7091 struct sockaddr_storage_rsp *sockaddr_storage;
7092 unsigned int flags;
7093 unsigned long long speed;
Namjae Jeonf1abdb72021-07-27 13:25:13 +09007094 struct sockaddr_in6 *csin6 = (struct sockaddr_in6 *)&conn->peer_addr;
Namjae Jeone2f34482021-03-16 10:49:09 +09007095
7096 rtnl_lock();
7097 for_each_netdev(&init_net, netdev) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007098 if (netdev->type == ARPHRD_LOOPBACK)
7099 continue;
7100
7101 flags = dev_get_flags(netdev);
7102 if (!(flags & IFF_RUNNING))
7103 continue;
7104
7105 nii_rsp = (struct network_interface_info_ioctl_rsp *)
7106 &rsp->Buffer[nbytes];
7107 nii_rsp->IfIndex = cpu_to_le32(netdev->ifindex);
7108
Hyunchul Lee03d8d4f2021-07-13 16:09:34 +09007109 nii_rsp->Capability = 0;
Hyunchul Lee03d8d4f2021-07-13 16:09:34 +09007110 if (ksmbd_rdma_capable_netdev(netdev))
7111 nii_rsp->Capability |= cpu_to_le32(RDMA_CAPABLE);
Namjae Jeone2f34482021-03-16 10:49:09 +09007112
7113 nii_rsp->Next = cpu_to_le32(152);
7114 nii_rsp->Reserved = 0;
7115
7116 if (netdev->ethtool_ops->get_link_ksettings) {
7117 struct ethtool_link_ksettings cmd;
7118
7119 netdev->ethtool_ops->get_link_ksettings(netdev, &cmd);
7120 speed = cmd.base.speed;
7121 } else {
Per Forlind4758662021-08-30 13:23:04 +09007122 ksmbd_debug(SMB, "%s %s\n", netdev->name,
7123 "speed is unknown, defaulting to 1Gb/sec");
Namjae Jeone2f34482021-03-16 10:49:09 +09007124 speed = SPEED_1000;
7125 }
7126
7127 speed *= 1000000;
7128 nii_rsp->LinkSpeed = cpu_to_le64(speed);
7129
7130 sockaddr_storage = (struct sockaddr_storage_rsp *)
7131 nii_rsp->SockAddr_Storage;
7132 memset(sockaddr_storage, 0, 128);
7133
Namjae Jeonf1abdb72021-07-27 13:25:13 +09007134 if (conn->peer_addr.ss_family == PF_INET ||
7135 ipv6_addr_v4mapped(&csin6->sin6_addr)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007136 struct in_device *idev;
7137
7138 sockaddr_storage->Family = cpu_to_le16(INTERNETWORK);
7139 sockaddr_storage->addr4.Port = 0;
7140
7141 idev = __in_dev_get_rtnl(netdev);
7142 if (!idev)
7143 continue;
7144 sockaddr_storage->addr4.IPv4address =
7145 idev_ipv4_address(idev);
7146 } else {
7147 struct inet6_dev *idev6;
7148 struct inet6_ifaddr *ifa;
7149 __u8 *ipv6_addr = sockaddr_storage->addr6.IPv6address;
7150
7151 sockaddr_storage->Family = cpu_to_le16(INTERNETWORKV6);
7152 sockaddr_storage->addr6.Port = 0;
7153 sockaddr_storage->addr6.FlowInfo = 0;
7154
7155 idev6 = __in6_dev_get(netdev);
7156 if (!idev6)
7157 continue;
7158
7159 list_for_each_entry(ifa, &idev6->addr_list, if_list) {
7160 if (ifa->flags & (IFA_F_TENTATIVE |
7161 IFA_F_DEPRECATED))
7162 continue;
7163 memcpy(ipv6_addr, ifa->addr.s6_addr, 16);
7164 break;
7165 }
7166 sockaddr_storage->addr6.ScopeId = 0;
7167 }
7168
7169 nbytes += sizeof(struct network_interface_info_ioctl_rsp);
7170 }
7171 rtnl_unlock();
7172
7173 /* zero if this is last one */
7174 if (nii_rsp)
7175 nii_rsp->Next = 0;
7176
7177 if (!nbytes) {
7178 rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL;
7179 return -EINVAL;
7180 }
7181
7182 rsp->PersistentFileId = cpu_to_le64(SMB2_NO_FID);
7183 rsp->VolatileFileId = cpu_to_le64(SMB2_NO_FID);
7184 return nbytes;
7185}
7186
Namjae Jeone2f34482021-03-16 10:49:09 +09007187static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn,
Namjae Jeon070fb212021-05-26 17:57:12 +09007188 struct validate_negotiate_info_req *neg_req,
7189 struct validate_negotiate_info_rsp *neg_rsp)
Namjae Jeone2f34482021-03-16 10:49:09 +09007190{
7191 int ret = 0;
7192 int dialect;
7193
7194 dialect = ksmbd_lookup_dialect_by_id(neg_req->Dialects,
Namjae Jeon070fb212021-05-26 17:57:12 +09007195 neg_req->DialectCount);
Namjae Jeone2f34482021-03-16 10:49:09 +09007196 if (dialect == BAD_PROT_ID || dialect != conn->dialect) {
7197 ret = -EINVAL;
7198 goto err_out;
7199 }
7200
7201 if (strncmp(neg_req->Guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE)) {
7202 ret = -EINVAL;
7203 goto err_out;
7204 }
7205
7206 if (le16_to_cpu(neg_req->SecurityMode) != conn->cli_sec_mode) {
7207 ret = -EINVAL;
7208 goto err_out;
7209 }
7210
7211 if (le32_to_cpu(neg_req->Capabilities) != conn->cli_cap) {
7212 ret = -EINVAL;
7213 goto err_out;
7214 }
7215
7216 neg_rsp->Capabilities = cpu_to_le32(conn->vals->capabilities);
7217 memset(neg_rsp->Guid, 0, SMB2_CLIENT_GUID_SIZE);
7218 neg_rsp->SecurityMode = cpu_to_le16(conn->srv_sec_mode);
7219 neg_rsp->Dialect = cpu_to_le16(conn->dialect);
7220err_out:
7221 return ret;
7222}
7223
Namjae Jeon64b39f42021-03-30 14:25:35 +09007224static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id,
Namjae Jeon070fb212021-05-26 17:57:12 +09007225 struct file_allocated_range_buffer *qar_req,
7226 struct file_allocated_range_buffer *qar_rsp,
7227 int in_count, int *out_count)
Namjae Jeone2f34482021-03-16 10:49:09 +09007228{
7229 struct ksmbd_file *fp;
7230 loff_t start, length;
7231 int ret = 0;
7232
7233 *out_count = 0;
7234 if (in_count == 0)
7235 return -EINVAL;
7236
7237 fp = ksmbd_lookup_fd_fast(work, id);
7238 if (!fp)
7239 return -ENOENT;
7240
7241 start = le64_to_cpu(qar_req->file_offset);
7242 length = le64_to_cpu(qar_req->length);
7243
7244 ret = ksmbd_vfs_fqar_lseek(fp, start, length,
Namjae Jeon070fb212021-05-26 17:57:12 +09007245 qar_rsp, in_count, out_count);
Namjae Jeone2f34482021-03-16 10:49:09 +09007246 if (ret && ret != -E2BIG)
7247 *out_count = 0;
7248
7249 ksmbd_fd_put(work, fp);
7250 return ret;
7251}
7252
Namjae Jeon64b39f42021-03-30 14:25:35 +09007253static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id,
Namjae Jeon070fb212021-05-26 17:57:12 +09007254 int out_buf_len, struct smb2_ioctl_req *req,
7255 struct smb2_ioctl_rsp *rsp)
Namjae Jeone2f34482021-03-16 10:49:09 +09007256{
7257 struct ksmbd_rpc_command *rpc_resp;
7258 char *data_buf = (char *)&req->Buffer[0];
7259 int nbytes = 0;
7260
Namjae Jeon64b39f42021-03-30 14:25:35 +09007261 rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf,
Namjae Jeon070fb212021-05-26 17:57:12 +09007262 le32_to_cpu(req->InputCount));
Namjae Jeone2f34482021-03-16 10:49:09 +09007263 if (rpc_resp) {
7264 if (rpc_resp->flags == KSMBD_RPC_SOME_NOT_MAPPED) {
7265 /*
7266 * set STATUS_SOME_NOT_MAPPED response
7267 * for unknown domain sid.
7268 */
7269 rsp->hdr.Status = STATUS_SOME_NOT_MAPPED;
7270 } else if (rpc_resp->flags == KSMBD_RPC_ENOTIMPLEMENTED) {
7271 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
7272 goto out;
7273 } else if (rpc_resp->flags != KSMBD_RPC_OK) {
7274 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
7275 goto out;
7276 }
7277
7278 nbytes = rpc_resp->payload_sz;
7279 if (rpc_resp->payload_sz > out_buf_len) {
7280 rsp->hdr.Status = STATUS_BUFFER_OVERFLOW;
7281 nbytes = out_buf_len;
7282 }
7283
7284 if (!rpc_resp->payload_sz) {
7285 rsp->hdr.Status =
7286 STATUS_UNEXPECTED_IO_ERROR;
7287 goto out;
7288 }
7289
7290 memcpy((char *)rsp->Buffer, rpc_resp->payload, nbytes);
7291 }
7292out:
Namjae Jeon79f6b112021-04-02 12:47:14 +09007293 kvfree(rpc_resp);
Namjae Jeone2f34482021-03-16 10:49:09 +09007294 return nbytes;
7295}
7296
Namjae Jeon64b39f42021-03-30 14:25:35 +09007297static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,
Namjae Jeon070fb212021-05-26 17:57:12 +09007298 struct file_sparse *sparse)
Namjae Jeone2f34482021-03-16 10:49:09 +09007299{
7300 struct ksmbd_file *fp;
Hyunchul Lee465d7202021-07-03 12:10:36 +09007301 struct user_namespace *user_ns;
Namjae Jeone2f34482021-03-16 10:49:09 +09007302 int ret = 0;
7303 __le32 old_fattr;
7304
7305 fp = ksmbd_lookup_fd_fast(work, id);
7306 if (!fp)
7307 return -ENOENT;
Hyunchul Lee465d7202021-07-03 12:10:36 +09007308 user_ns = file_mnt_user_ns(fp->filp);
Namjae Jeone2f34482021-03-16 10:49:09 +09007309
7310 old_fattr = fp->f_ci->m_fattr;
7311 if (sparse->SetSparse)
7312 fp->f_ci->m_fattr |= ATTR_SPARSE_FILE_LE;
7313 else
7314 fp->f_ci->m_fattr &= ~ATTR_SPARSE_FILE_LE;
7315
7316 if (fp->f_ci->m_fattr != old_fattr &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09007317 test_share_config_flag(work->tcon->share_conf,
7318 KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007319 struct xattr_dos_attrib da;
7320
Hyunchul Lee465d7202021-07-03 12:10:36 +09007321 ret = ksmbd_vfs_get_dos_attrib_xattr(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09007322 fp->filp->f_path.dentry, &da);
Namjae Jeone2f34482021-03-16 10:49:09 +09007323 if (ret <= 0)
7324 goto out;
7325
7326 da.attr = le32_to_cpu(fp->f_ci->m_fattr);
Hyunchul Lee465d7202021-07-03 12:10:36 +09007327 ret = ksmbd_vfs_set_dos_attrib_xattr(user_ns,
Hyunchul Leeaf349832021-06-30 18:25:53 +09007328 fp->filp->f_path.dentry, &da);
Namjae Jeone2f34482021-03-16 10:49:09 +09007329 if (ret)
7330 fp->f_ci->m_fattr = old_fattr;
7331 }
7332
7333out:
7334 ksmbd_fd_put(work, fp);
7335 return ret;
7336}
7337
7338static int fsctl_request_resume_key(struct ksmbd_work *work,
Namjae Jeon070fb212021-05-26 17:57:12 +09007339 struct smb2_ioctl_req *req,
7340 struct resume_key_ioctl_rsp *key_rsp)
Namjae Jeone2f34482021-03-16 10:49:09 +09007341{
7342 struct ksmbd_file *fp;
7343
7344 fp = ksmbd_lookup_fd_slow(work,
Namjae Jeon070fb212021-05-26 17:57:12 +09007345 le64_to_cpu(req->VolatileFileId),
7346 le64_to_cpu(req->PersistentFileId));
Namjae Jeone2f34482021-03-16 10:49:09 +09007347 if (!fp)
7348 return -ENOENT;
7349
7350 memset(key_rsp, 0, sizeof(*key_rsp));
7351 key_rsp->ResumeKey[0] = req->VolatileFileId;
7352 key_rsp->ResumeKey[1] = req->PersistentFileId;
7353 ksmbd_fd_put(work, fp);
7354
7355 return 0;
7356}
7357
7358/**
7359 * smb2_ioctl() - handler for smb2 ioctl command
7360 * @work: smb work containing ioctl command buffer
7361 *
7362 * Return: 0 on success, otherwise error
7363 */
7364int smb2_ioctl(struct ksmbd_work *work)
7365{
7366 struct smb2_ioctl_req *req;
7367 struct smb2_ioctl_rsp *rsp, *rsp_org;
7368 int cnt_code, nbytes = 0;
7369 int out_buf_len;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007370 u64 id = KSMBD_NO_FID;
Namjae Jeone2f34482021-03-16 10:49:09 +09007371 struct ksmbd_conn *conn = work->conn;
7372 int ret = 0;
7373
Namjae Jeone5066492021-03-30 12:35:23 +09007374 rsp_org = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09007375 if (work->next_smb2_rcv_hdr_off) {
Namjae Jeon8a893312021-06-25 13:43:37 +09007376 req = ksmbd_req_buf_next(work);
7377 rsp = ksmbd_resp_buf_next(work);
Namjae Jeon38673692021-07-08 12:32:27 +09007378 if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
7379 ksmbd_debug(SMB, "Compound request set FID = %llu\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09007380 work->compound_fid);
Namjae Jeone2f34482021-03-16 10:49:09 +09007381 id = work->compound_fid;
7382 }
7383 } else {
Namjae Jeone5066492021-03-30 12:35:23 +09007384 req = work->request_buf;
7385 rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09007386 }
7387
Namjae Jeon38673692021-07-08 12:32:27 +09007388 if (!has_file_id(id))
Namjae Jeone2f34482021-03-16 10:49:09 +09007389 id = le64_to_cpu(req->VolatileFileId);
7390
7391 if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) {
7392 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
7393 goto out;
7394 }
7395
7396 cnt_code = le32_to_cpu(req->CntCode);
7397 out_buf_len = le32_to_cpu(req->MaxOutputResponse);
7398 out_buf_len = min(KSMBD_IPC_MAX_PAYLOAD, out_buf_len);
7399
7400 switch (cnt_code) {
7401 case FSCTL_DFS_GET_REFERRALS:
7402 case FSCTL_DFS_GET_REFERRALS_EX:
7403 /* Not support DFS yet */
7404 rsp->hdr.Status = STATUS_FS_DRIVER_REQUIRED;
7405 goto out;
7406 case FSCTL_CREATE_OR_GET_OBJECT_ID:
7407 {
7408 struct file_object_buf_type1_ioctl_rsp *obj_buf;
7409
7410 nbytes = sizeof(struct file_object_buf_type1_ioctl_rsp);
7411 obj_buf = (struct file_object_buf_type1_ioctl_rsp *)
7412 &rsp->Buffer[0];
7413
7414 /*
7415 * TODO: This is dummy implementation to pass smbtorture
7416 * Need to check correct response later
7417 */
7418 memset(obj_buf->ObjectId, 0x0, 16);
7419 memset(obj_buf->BirthVolumeId, 0x0, 16);
7420 memset(obj_buf->BirthObjectId, 0x0, 16);
7421 memset(obj_buf->DomainId, 0x0, 16);
7422
7423 break;
7424 }
7425 case FSCTL_PIPE_TRANSCEIVE:
7426 nbytes = fsctl_pipe_transceive(work, id, out_buf_len, req, rsp);
7427 break;
7428 case FSCTL_VALIDATE_NEGOTIATE_INFO:
7429 if (conn->dialect < SMB30_PROT_ID) {
7430 ret = -EOPNOTSUPP;
7431 goto out;
7432 }
7433
7434 ret = fsctl_validate_negotiate_info(conn,
7435 (struct validate_negotiate_info_req *)&req->Buffer[0],
7436 (struct validate_negotiate_info_rsp *)&rsp->Buffer[0]);
7437 if (ret < 0)
7438 goto out;
7439
7440 nbytes = sizeof(struct validate_negotiate_info_rsp);
7441 rsp->PersistentFileId = cpu_to_le64(SMB2_NO_FID);
7442 rsp->VolatileFileId = cpu_to_le64(SMB2_NO_FID);
7443 break;
7444 case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
7445 nbytes = fsctl_query_iface_info_ioctl(conn, req, rsp);
7446 if (nbytes < 0)
7447 goto out;
7448 break;
7449 case FSCTL_REQUEST_RESUME_KEY:
7450 if (out_buf_len < sizeof(struct resume_key_ioctl_rsp)) {
7451 ret = -EINVAL;
7452 goto out;
7453 }
7454
7455 ret = fsctl_request_resume_key(work, req,
Namjae Jeon070fb212021-05-26 17:57:12 +09007456 (struct resume_key_ioctl_rsp *)&rsp->Buffer[0]);
Namjae Jeone2f34482021-03-16 10:49:09 +09007457 if (ret < 0)
7458 goto out;
7459 rsp->PersistentFileId = req->PersistentFileId;
7460 rsp->VolatileFileId = req->VolatileFileId;
7461 nbytes = sizeof(struct resume_key_ioctl_rsp);
7462 break;
7463 case FSCTL_COPYCHUNK:
7464 case FSCTL_COPYCHUNK_WRITE:
Namjae Jeon64b39f42021-03-30 14:25:35 +09007465 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007466 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09007467 "User does not have write permission\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09007468 ret = -EACCES;
7469 goto out;
7470 }
7471
7472 if (out_buf_len < sizeof(struct copychunk_ioctl_rsp)) {
7473 ret = -EINVAL;
7474 goto out;
7475 }
7476
7477 nbytes = sizeof(struct copychunk_ioctl_rsp);
7478 fsctl_copychunk(work, req, rsp);
7479 break;
7480 case FSCTL_SET_SPARSE:
7481 ret = fsctl_set_sparse(work, id,
Namjae Jeon070fb212021-05-26 17:57:12 +09007482 (struct file_sparse *)&req->Buffer[0]);
Namjae Jeone2f34482021-03-16 10:49:09 +09007483 if (ret < 0)
7484 goto out;
7485 break;
7486 case FSCTL_SET_ZERO_DATA:
7487 {
7488 struct file_zero_data_information *zero_data;
7489 struct ksmbd_file *fp;
7490 loff_t off, len;
7491
Namjae Jeon64b39f42021-03-30 14:25:35 +09007492 if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007493 ksmbd_debug(SMB,
Namjae Jeon070fb212021-05-26 17:57:12 +09007494 "User does not have write permission\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09007495 ret = -EACCES;
7496 goto out;
7497 }
7498
7499 zero_data =
7500 (struct file_zero_data_information *)&req->Buffer[0];
7501
7502 fp = ksmbd_lookup_fd_fast(work, id);
7503 if (!fp) {
7504 ret = -ENOENT;
7505 goto out;
7506 }
7507
7508 off = le64_to_cpu(zero_data->FileOffset);
7509 len = le64_to_cpu(zero_data->BeyondFinalZero) - off;
7510
7511 ret = ksmbd_vfs_zero_data(work, fp, off, len);
7512 ksmbd_fd_put(work, fp);
7513 if (ret < 0)
7514 goto out;
7515 break;
7516 }
7517 case FSCTL_QUERY_ALLOCATED_RANGES:
7518 ret = fsctl_query_allocated_ranges(work, id,
7519 (struct file_allocated_range_buffer *)&req->Buffer[0],
7520 (struct file_allocated_range_buffer *)&rsp->Buffer[0],
7521 out_buf_len /
7522 sizeof(struct file_allocated_range_buffer), &nbytes);
7523 if (ret == -E2BIG) {
7524 rsp->hdr.Status = STATUS_BUFFER_OVERFLOW;
7525 } else if (ret < 0) {
7526 nbytes = 0;
7527 goto out;
7528 }
7529
7530 nbytes *= sizeof(struct file_allocated_range_buffer);
7531 break;
7532 case FSCTL_GET_REPARSE_POINT:
7533 {
7534 struct reparse_data_buffer *reparse_ptr;
7535 struct ksmbd_file *fp;
7536
7537 reparse_ptr = (struct reparse_data_buffer *)&rsp->Buffer[0];
7538 fp = ksmbd_lookup_fd_fast(work, id);
7539 if (!fp) {
Namjae Jeonbde16942021-06-28 15:23:19 +09007540 pr_err("not found fp!!\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09007541 ret = -ENOENT;
7542 goto out;
7543 }
7544
7545 reparse_ptr->ReparseTag =
Namjae Jeonab0b2632021-06-29 09:20:13 +09007546 smb2_get_reparse_tag_special_file(file_inode(fp->filp)->i_mode);
Namjae Jeone2f34482021-03-16 10:49:09 +09007547 reparse_ptr->ReparseDataLength = 0;
7548 ksmbd_fd_put(work, fp);
7549 nbytes = sizeof(struct reparse_data_buffer);
7550 break;
7551 }
Namjae Jeoneb817362021-05-18 10:37:59 +09007552 case FSCTL_DUPLICATE_EXTENTS_TO_FILE:
7553 {
7554 struct ksmbd_file *fp_in, *fp_out = NULL;
7555 struct duplicate_extents_to_file *dup_ext;
7556 loff_t src_off, dst_off, length, cloned;
7557
7558 dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0];
7559
7560 fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle,
Namjae Jeon070fb212021-05-26 17:57:12 +09007561 dup_ext->PersistentFileHandle);
Namjae Jeoneb817362021-05-18 10:37:59 +09007562 if (!fp_in) {
Namjae Jeonbde16942021-06-28 15:23:19 +09007563 pr_err("not found file handle in duplicate extent to file\n");
Namjae Jeoneb817362021-05-18 10:37:59 +09007564 ret = -ENOENT;
7565 goto out;
7566 }
7567
7568 fp_out = ksmbd_lookup_fd_fast(work, id);
7569 if (!fp_out) {
Namjae Jeonbde16942021-06-28 15:23:19 +09007570 pr_err("not found fp\n");
Namjae Jeoneb817362021-05-18 10:37:59 +09007571 ret = -ENOENT;
7572 goto dup_ext_out;
7573 }
7574
7575 src_off = le64_to_cpu(dup_ext->SourceFileOffset);
7576 dst_off = le64_to_cpu(dup_ext->TargetFileOffset);
7577 length = le64_to_cpu(dup_ext->ByteCount);
7578 cloned = vfs_clone_file_range(fp_in->filp, src_off, fp_out->filp,
Namjae Jeon070fb212021-05-26 17:57:12 +09007579 dst_off, length, 0);
Namjae Jeoneb817362021-05-18 10:37:59 +09007580 if (cloned == -EXDEV || cloned == -EOPNOTSUPP) {
7581 ret = -EOPNOTSUPP;
7582 goto dup_ext_out;
7583 } else if (cloned != length) {
Namjae Jeonf8524772021-06-18 10:28:00 +09007584 cloned = vfs_copy_file_range(fp_in->filp, src_off,
7585 fp_out->filp, dst_off, length, 0);
Namjae Jeoneb817362021-05-18 10:37:59 +09007586 if (cloned != length) {
7587 if (cloned < 0)
7588 ret = cloned;
7589 else
7590 ret = -EINVAL;
7591 }
7592 }
7593
7594dup_ext_out:
7595 ksmbd_fd_put(work, fp_in);
7596 ksmbd_fd_put(work, fp_out);
7597 if (ret < 0)
7598 goto out;
7599 break;
7600 }
Namjae Jeone2f34482021-03-16 10:49:09 +09007601 default:
7602 ksmbd_debug(SMB, "not implemented yet ioctl command 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09007603 cnt_code);
Namjae Jeone2f34482021-03-16 10:49:09 +09007604 ret = -EOPNOTSUPP;
7605 goto out;
7606 }
7607
7608 rsp->CntCode = cpu_to_le32(cnt_code);
7609 rsp->InputCount = cpu_to_le32(0);
7610 rsp->InputOffset = cpu_to_le32(112);
7611 rsp->OutputOffset = cpu_to_le32(112);
7612 rsp->OutputCount = cpu_to_le32(nbytes);
7613 rsp->StructureSize = cpu_to_le16(49);
7614 rsp->Reserved = cpu_to_le16(0);
7615 rsp->Flags = cpu_to_le32(0);
7616 rsp->Reserved2 = cpu_to_le32(0);
7617 inc_rfc1001_len(rsp_org, 48 + nbytes);
7618
7619 return 0;
7620
7621out:
7622 if (ret == -EACCES)
7623 rsp->hdr.Status = STATUS_ACCESS_DENIED;
7624 else if (ret == -ENOENT)
7625 rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND;
7626 else if (ret == -EOPNOTSUPP)
7627 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
7628 else if (ret < 0 || rsp->hdr.Status == 0)
7629 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
7630 smb2_set_err_rsp(work);
7631 return 0;
7632}
7633
7634/**
7635 * smb20_oplock_break_ack() - handler for smb2.0 oplock break command
7636 * @work: smb work containing oplock break command buffer
7637 *
7638 * Return: 0
7639 */
7640static void smb20_oplock_break_ack(struct ksmbd_work *work)
7641{
Namjae Jeone5066492021-03-30 12:35:23 +09007642 struct smb2_oplock_break *req = work->request_buf;
7643 struct smb2_oplock_break *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09007644 struct ksmbd_file *fp;
7645 struct oplock_info *opinfo = NULL;
7646 __le32 err = 0;
7647 int ret = 0;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007648 u64 volatile_id, persistent_id;
Namjae Jeone2f34482021-03-16 10:49:09 +09007649 char req_oplevel = 0, rsp_oplevel = 0;
7650 unsigned int oplock_change_type;
7651
7652 volatile_id = le64_to_cpu(req->VolatileFid);
7653 persistent_id = le64_to_cpu(req->PersistentFid);
7654 req_oplevel = req->OplockLevel;
7655 ksmbd_debug(OPLOCK, "v_id %llu, p_id %llu request oplock level %d\n",
7656 volatile_id, persistent_id, req_oplevel);
7657
7658 fp = ksmbd_lookup_fd_slow(work, volatile_id, persistent_id);
7659 if (!fp) {
7660 rsp->hdr.Status = STATUS_FILE_CLOSED;
7661 smb2_set_err_rsp(work);
7662 return;
7663 }
7664
7665 opinfo = opinfo_get(fp);
7666 if (!opinfo) {
Namjae Jeonbde16942021-06-28 15:23:19 +09007667 pr_err("unexpected null oplock_info\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09007668 rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL;
7669 smb2_set_err_rsp(work);
7670 ksmbd_fd_put(work, fp);
7671 return;
7672 }
7673
7674 if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE) {
7675 rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL;
7676 goto err_out;
7677 }
7678
7679 if (opinfo->op_state == OPLOCK_STATE_NONE) {
7680 ksmbd_debug(SMB, "unexpected oplock state 0x%x\n", opinfo->op_state);
7681 rsp->hdr.Status = STATUS_UNSUCCESSFUL;
7682 goto err_out;
7683 }
7684
Namjae Jeon64b39f42021-03-30 14:25:35 +09007685 if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
7686 opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
7687 (req_oplevel != SMB2_OPLOCK_LEVEL_II &&
7688 req_oplevel != SMB2_OPLOCK_LEVEL_NONE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007689 err = STATUS_INVALID_OPLOCK_PROTOCOL;
7690 oplock_change_type = OPLOCK_WRITE_TO_NONE;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007691 } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
7692 req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007693 err = STATUS_INVALID_OPLOCK_PROTOCOL;
7694 oplock_change_type = OPLOCK_READ_TO_NONE;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007695 } else if (req_oplevel == SMB2_OPLOCK_LEVEL_II ||
7696 req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007697 err = STATUS_INVALID_DEVICE_STATE;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007698 if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
7699 opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
7700 req_oplevel == SMB2_OPLOCK_LEVEL_II) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007701 oplock_change_type = OPLOCK_WRITE_TO_READ;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007702 } else if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
7703 opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
7704 req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007705 oplock_change_type = OPLOCK_WRITE_TO_NONE;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007706 } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
7707 req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007708 oplock_change_type = OPLOCK_READ_TO_NONE;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007709 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09007710 oplock_change_type = 0;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007711 }
7712 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09007713 oplock_change_type = 0;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007714 }
Namjae Jeone2f34482021-03-16 10:49:09 +09007715
7716 switch (oplock_change_type) {
7717 case OPLOCK_WRITE_TO_READ:
7718 ret = opinfo_write_to_read(opinfo);
7719 rsp_oplevel = SMB2_OPLOCK_LEVEL_II;
7720 break;
7721 case OPLOCK_WRITE_TO_NONE:
7722 ret = opinfo_write_to_none(opinfo);
7723 rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
7724 break;
7725 case OPLOCK_READ_TO_NONE:
7726 ret = opinfo_read_to_none(opinfo);
7727 rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
7728 break;
7729 default:
Namjae Jeonbde16942021-06-28 15:23:19 +09007730 pr_err("unknown oplock change 0x%x -> 0x%x\n",
7731 opinfo->level, rsp_oplevel);
Namjae Jeone2f34482021-03-16 10:49:09 +09007732 }
7733
7734 if (ret < 0) {
7735 rsp->hdr.Status = err;
7736 goto err_out;
7737 }
7738
7739 opinfo_put(opinfo);
7740 ksmbd_fd_put(work, fp);
7741 opinfo->op_state = OPLOCK_STATE_NONE;
7742 wake_up_interruptible_all(&opinfo->oplock_q);
7743
7744 rsp->StructureSize = cpu_to_le16(24);
7745 rsp->OplockLevel = rsp_oplevel;
7746 rsp->Reserved = 0;
7747 rsp->Reserved2 = 0;
7748 rsp->VolatileFid = cpu_to_le64(volatile_id);
7749 rsp->PersistentFid = cpu_to_le64(persistent_id);
7750 inc_rfc1001_len(rsp, 24);
7751 return;
7752
7753err_out:
7754 opinfo->op_state = OPLOCK_STATE_NONE;
7755 wake_up_interruptible_all(&opinfo->oplock_q);
7756
7757 opinfo_put(opinfo);
7758 ksmbd_fd_put(work, fp);
7759 smb2_set_err_rsp(work);
7760}
7761
7762static int check_lease_state(struct lease *lease, __le32 req_state)
7763{
7764 if ((lease->new_state ==
Namjae Jeon64b39f42021-03-30 14:25:35 +09007765 (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE)) &&
7766 !(req_state & SMB2_LEASE_WRITE_CACHING_LE)) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007767 lease->new_state = req_state;
7768 return 0;
7769 }
7770
7771 if (lease->new_state == req_state)
7772 return 0;
7773
7774 return 1;
7775}
7776
7777/**
7778 * smb21_lease_break_ack() - handler for smb2.1 lease break command
7779 * @work: smb work containing lease break command buffer
7780 *
7781 * Return: 0
7782 */
7783static void smb21_lease_break_ack(struct ksmbd_work *work)
7784{
7785 struct ksmbd_conn *conn = work->conn;
Namjae Jeone5066492021-03-30 12:35:23 +09007786 struct smb2_lease_ack *req = work->request_buf;
7787 struct smb2_lease_ack *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09007788 struct oplock_info *opinfo;
7789 __le32 err = 0;
7790 int ret = 0;
7791 unsigned int lease_change_type;
7792 __le32 lease_state;
7793 struct lease *lease;
7794
7795 ksmbd_debug(OPLOCK, "smb21 lease break, lease state(0x%x)\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09007796 le32_to_cpu(req->LeaseState));
Namjae Jeone2f34482021-03-16 10:49:09 +09007797 opinfo = lookup_lease_in_table(conn, req->LeaseKey);
7798 if (!opinfo) {
7799 ksmbd_debug(OPLOCK, "file not opened\n");
7800 smb2_set_err_rsp(work);
7801 rsp->hdr.Status = STATUS_UNSUCCESSFUL;
7802 return;
7803 }
7804 lease = opinfo->o_lease;
7805
7806 if (opinfo->op_state == OPLOCK_STATE_NONE) {
Namjae Jeonbde16942021-06-28 15:23:19 +09007807 pr_err("unexpected lease break state 0x%x\n",
7808 opinfo->op_state);
Namjae Jeone2f34482021-03-16 10:49:09 +09007809 rsp->hdr.Status = STATUS_UNSUCCESSFUL;
7810 goto err_out;
7811 }
7812
7813 if (check_lease_state(lease, req->LeaseState)) {
7814 rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
7815 ksmbd_debug(OPLOCK,
Namjae Jeon070fb212021-05-26 17:57:12 +09007816 "req lease state: 0x%x, expected state: 0x%x\n",
7817 req->LeaseState, lease->new_state);
Namjae Jeone2f34482021-03-16 10:49:09 +09007818 goto err_out;
7819 }
7820
7821 if (!atomic_read(&opinfo->breaking_cnt)) {
7822 rsp->hdr.Status = STATUS_UNSUCCESSFUL;
7823 goto err_out;
7824 }
7825
7826 /* check for bad lease state */
Namjae Jeon070fb212021-05-26 17:57:12 +09007827 if (req->LeaseState &
7828 (~(SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE))) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007829 err = STATUS_INVALID_OPLOCK_PROTOCOL;
7830 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
7831 lease_change_type = OPLOCK_WRITE_TO_NONE;
7832 else
7833 lease_change_type = OPLOCK_READ_TO_NONE;
7834 ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09007835 le32_to_cpu(lease->state),
7836 le32_to_cpu(req->LeaseState));
Namjae Jeon64b39f42021-03-30 14:25:35 +09007837 } else if (lease->state == SMB2_LEASE_READ_CACHING_LE &&
7838 req->LeaseState != SMB2_LEASE_NONE_LE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09007839 err = STATUS_INVALID_OPLOCK_PROTOCOL;
7840 lease_change_type = OPLOCK_READ_TO_NONE;
7841 ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09007842 le32_to_cpu(lease->state),
7843 le32_to_cpu(req->LeaseState));
Namjae Jeone2f34482021-03-16 10:49:09 +09007844 } else {
7845 /* valid lease state changes */
7846 err = STATUS_INVALID_DEVICE_STATE;
7847 if (req->LeaseState == SMB2_LEASE_NONE_LE) {
7848 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
7849 lease_change_type = OPLOCK_WRITE_TO_NONE;
7850 else
7851 lease_change_type = OPLOCK_READ_TO_NONE;
7852 } else if (req->LeaseState & SMB2_LEASE_READ_CACHING_LE) {
7853 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
7854 lease_change_type = OPLOCK_WRITE_TO_READ;
7855 else
7856 lease_change_type = OPLOCK_READ_HANDLE_TO_READ;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007857 } else {
Namjae Jeone2f34482021-03-16 10:49:09 +09007858 lease_change_type = 0;
Namjae Jeon64b39f42021-03-30 14:25:35 +09007859 }
Namjae Jeone2f34482021-03-16 10:49:09 +09007860 }
7861
7862 switch (lease_change_type) {
7863 case OPLOCK_WRITE_TO_READ:
7864 ret = opinfo_write_to_read(opinfo);
7865 break;
7866 case OPLOCK_READ_HANDLE_TO_READ:
7867 ret = opinfo_read_handle_to_read(opinfo);
7868 break;
7869 case OPLOCK_WRITE_TO_NONE:
7870 ret = opinfo_write_to_none(opinfo);
7871 break;
7872 case OPLOCK_READ_TO_NONE:
7873 ret = opinfo_read_to_none(opinfo);
7874 break;
7875 default:
7876 ksmbd_debug(OPLOCK, "unknown lease change 0x%x -> 0x%x\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09007877 le32_to_cpu(lease->state),
7878 le32_to_cpu(req->LeaseState));
Namjae Jeone2f34482021-03-16 10:49:09 +09007879 }
7880
7881 lease_state = lease->state;
7882 opinfo->op_state = OPLOCK_STATE_NONE;
7883 wake_up_interruptible_all(&opinfo->oplock_q);
7884 atomic_dec(&opinfo->breaking_cnt);
7885 wake_up_interruptible_all(&opinfo->oplock_brk);
7886 opinfo_put(opinfo);
7887
7888 if (ret < 0) {
7889 rsp->hdr.Status = err;
7890 goto err_out;
7891 }
7892
7893 rsp->StructureSize = cpu_to_le16(36);
7894 rsp->Reserved = 0;
7895 rsp->Flags = 0;
7896 memcpy(rsp->LeaseKey, req->LeaseKey, 16);
7897 rsp->LeaseState = lease_state;
7898 rsp->LeaseDuration = 0;
7899 inc_rfc1001_len(rsp, 36);
7900 return;
7901
7902err_out:
7903 opinfo->op_state = OPLOCK_STATE_NONE;
7904 wake_up_interruptible_all(&opinfo->oplock_q);
7905 atomic_dec(&opinfo->breaking_cnt);
7906 wake_up_interruptible_all(&opinfo->oplock_brk);
7907
7908 opinfo_put(opinfo);
7909 smb2_set_err_rsp(work);
7910}
7911
7912/**
7913 * smb2_oplock_break() - dispatcher for smb2.0 and 2.1 oplock/lease break
7914 * @work: smb work containing oplock/lease break command buffer
7915 *
7916 * Return: 0
7917 */
7918int smb2_oplock_break(struct ksmbd_work *work)
7919{
Namjae Jeone5066492021-03-30 12:35:23 +09007920 struct smb2_oplock_break *req = work->request_buf;
7921 struct smb2_oplock_break *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09007922
7923 switch (le16_to_cpu(req->StructureSize)) {
7924 case OP_BREAK_STRUCT_SIZE_20:
7925 smb20_oplock_break_ack(work);
7926 break;
7927 case OP_BREAK_STRUCT_SIZE_21:
7928 smb21_lease_break_ack(work);
7929 break;
7930 default:
7931 ksmbd_debug(OPLOCK, "invalid break cmd %d\n",
Namjae Jeon070fb212021-05-26 17:57:12 +09007932 le16_to_cpu(req->StructureSize));
Namjae Jeone2f34482021-03-16 10:49:09 +09007933 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
7934 smb2_set_err_rsp(work);
7935 }
7936
7937 return 0;
7938}
7939
7940/**
7941 * smb2_notify() - handler for smb2 notify request
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +09007942 * @work: smb work containing notify command buffer
Namjae Jeone2f34482021-03-16 10:49:09 +09007943 *
7944 * Return: 0
7945 */
7946int smb2_notify(struct ksmbd_work *work)
7947{
7948 struct smb2_notify_req *req;
7949 struct smb2_notify_rsp *rsp;
7950
7951 WORK_BUFFERS(work, req, rsp);
7952
7953 if (work->next_smb2_rcv_hdr_off && req->hdr.NextCommand) {
7954 rsp->hdr.Status = STATUS_INTERNAL_ERROR;
7955 smb2_set_err_rsp(work);
7956 return 0;
7957 }
7958
7959 smb2_set_err_rsp(work);
7960 rsp->hdr.Status = STATUS_NOT_IMPLEMENTED;
7961 return 0;
7962}
7963
7964/**
7965 * smb2_is_sign_req() - handler for checking packet signing status
Hyunchul Lee95fa1ce2021-03-21 17:05:56 +09007966 * @work: smb work containing notify command buffer
7967 * @command: SMB2 command id
Namjae Jeone2f34482021-03-16 10:49:09 +09007968 *
7969 * Return: true if packed is signed, false otherwise
7970 */
7971bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)
7972{
Namjae Jeone5066492021-03-30 12:35:23 +09007973 struct smb2_hdr *rcv_hdr2 = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09007974
7975 if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09007976 command != SMB2_NEGOTIATE_HE &&
7977 command != SMB2_SESSION_SETUP_HE &&
7978 command != SMB2_OPLOCK_BREAK_HE)
Namjae Jeone2f34482021-03-16 10:49:09 +09007979 return true;
7980
kernel test robot56160152021-05-12 09:24:37 +09007981 return false;
Namjae Jeone2f34482021-03-16 10:49:09 +09007982}
7983
7984/**
7985 * smb2_check_sign_req() - handler for req packet sign processing
7986 * @work: smb work containing notify command buffer
7987 *
7988 * Return: 1 on success, 0 otherwise
7989 */
7990int smb2_check_sign_req(struct ksmbd_work *work)
7991{
7992 struct smb2_hdr *hdr, *hdr_org;
7993 char signature_req[SMB2_SIGNATURE_SIZE];
7994 char signature[SMB2_HMACSHA256_SIZE];
7995 struct kvec iov[1];
7996 size_t len;
7997
Namjae Jeone5066492021-03-30 12:35:23 +09007998 hdr_org = hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09007999 if (work->next_smb2_rcv_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +09008000 hdr = ksmbd_req_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09008001
8002 if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off)
8003 len = be32_to_cpu(hdr_org->smb2_buf_length);
8004 else if (hdr->NextCommand)
8005 len = le32_to_cpu(hdr->NextCommand);
8006 else
8007 len = be32_to_cpu(hdr_org->smb2_buf_length) -
8008 work->next_smb2_rcv_hdr_off;
8009
8010 memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE);
8011 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
8012
8013 iov[0].iov_base = (char *)&hdr->ProtocolId;
8014 iov[0].iov_len = len;
8015
8016 if (ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, 1,
Namjae Jeon64b39f42021-03-30 14:25:35 +09008017 signature))
Namjae Jeone2f34482021-03-16 10:49:09 +09008018 return 0;
8019
8020 if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09008021 pr_err("bad smb2 signature\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09008022 return 0;
8023 }
8024
8025 return 1;
8026}
8027
8028/**
8029 * smb2_set_sign_rsp() - handler for rsp packet sign processing
8030 * @work: smb work containing notify command buffer
8031 *
8032 */
8033void smb2_set_sign_rsp(struct ksmbd_work *work)
8034{
8035 struct smb2_hdr *hdr, *hdr_org;
8036 struct smb2_hdr *req_hdr;
8037 char signature[SMB2_HMACSHA256_SIZE];
8038 struct kvec iov[2];
8039 size_t len;
8040 int n_vec = 1;
8041
Namjae Jeone5066492021-03-30 12:35:23 +09008042 hdr_org = hdr = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09008043 if (work->next_smb2_rsp_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +09008044 hdr = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09008045
Namjae Jeon8a893312021-06-25 13:43:37 +09008046 req_hdr = ksmbd_req_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09008047
8048 if (!work->next_smb2_rsp_hdr_off) {
8049 len = get_rfc1002_len(hdr_org);
8050 if (req_hdr->NextCommand)
8051 len = ALIGN(len, 8);
8052 } else {
8053 len = get_rfc1002_len(hdr_org) - work->next_smb2_rsp_hdr_off;
8054 len = ALIGN(len, 8);
8055 }
8056
8057 if (req_hdr->NextCommand)
8058 hdr->NextCommand = cpu_to_le32(len);
8059
8060 hdr->Flags |= SMB2_FLAGS_SIGNED;
8061 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
8062
8063 iov[0].iov_base = (char *)&hdr->ProtocolId;
8064 iov[0].iov_len = len;
8065
Namjae Jeone5066492021-03-30 12:35:23 +09008066 if (work->aux_payload_sz) {
8067 iov[0].iov_len -= work->aux_payload_sz;
Namjae Jeone2f34482021-03-16 10:49:09 +09008068
Namjae Jeone5066492021-03-30 12:35:23 +09008069 iov[1].iov_base = work->aux_payload_buf;
8070 iov[1].iov_len = work->aux_payload_sz;
Namjae Jeone2f34482021-03-16 10:49:09 +09008071 n_vec++;
8072 }
8073
8074 if (!ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec,
Namjae Jeon64b39f42021-03-30 14:25:35 +09008075 signature))
Namjae Jeone2f34482021-03-16 10:49:09 +09008076 memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);
8077}
8078
8079/**
8080 * smb3_check_sign_req() - handler for req packet sign processing
8081 * @work: smb work containing notify command buffer
8082 *
8083 * Return: 1 on success, 0 otherwise
8084 */
8085int smb3_check_sign_req(struct ksmbd_work *work)
8086{
Namjae Jeonf5a544e2021-06-18 10:04:19 +09008087 struct ksmbd_conn *conn = work->conn;
Namjae Jeone2f34482021-03-16 10:49:09 +09008088 char *signing_key;
8089 struct smb2_hdr *hdr, *hdr_org;
8090 struct channel *chann;
8091 char signature_req[SMB2_SIGNATURE_SIZE];
8092 char signature[SMB2_CMACAES_SIZE];
8093 struct kvec iov[1];
8094 size_t len;
8095
Namjae Jeone5066492021-03-30 12:35:23 +09008096 hdr_org = hdr = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09008097 if (work->next_smb2_rcv_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +09008098 hdr = ksmbd_req_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09008099
8100 if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off)
8101 len = be32_to_cpu(hdr_org->smb2_buf_length);
8102 else if (hdr->NextCommand)
8103 len = le32_to_cpu(hdr->NextCommand);
8104 else
8105 len = be32_to_cpu(hdr_org->smb2_buf_length) -
8106 work->next_smb2_rcv_hdr_off;
8107
8108 if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
8109 signing_key = work->sess->smb3signingkey;
Namjae Jeone2f34482021-03-16 10:49:09 +09008110 } else {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09008111 chann = lookup_chann_list(work->sess, conn);
Namjae Jeone2f34482021-03-16 10:49:09 +09008112 if (!chann)
8113 return 0;
8114 signing_key = chann->smb3signingkey;
Namjae Jeone2f34482021-03-16 10:49:09 +09008115 }
8116
8117 if (!signing_key) {
Namjae Jeonbde16942021-06-28 15:23:19 +09008118 pr_err("SMB3 signing key is not generated\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09008119 return 0;
8120 }
8121
8122 memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE);
8123 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
8124 iov[0].iov_base = (char *)&hdr->ProtocolId;
8125 iov[0].iov_len = len;
8126
8127 if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature))
8128 return 0;
8129
8130 if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09008131 pr_err("bad smb2 signature\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09008132 return 0;
8133 }
8134
8135 return 1;
8136}
8137
8138/**
8139 * smb3_set_sign_rsp() - handler for rsp packet sign processing
8140 * @work: smb work containing notify command buffer
8141 *
8142 */
8143void smb3_set_sign_rsp(struct ksmbd_work *work)
8144{
Namjae Jeonf5a544e2021-06-18 10:04:19 +09008145 struct ksmbd_conn *conn = work->conn;
Namjae Jeone2f34482021-03-16 10:49:09 +09008146 struct smb2_hdr *req_hdr;
8147 struct smb2_hdr *hdr, *hdr_org;
8148 struct channel *chann;
8149 char signature[SMB2_CMACAES_SIZE];
8150 struct kvec iov[2];
8151 int n_vec = 1;
8152 size_t len;
8153 char *signing_key;
8154
Namjae Jeone5066492021-03-30 12:35:23 +09008155 hdr_org = hdr = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09008156 if (work->next_smb2_rsp_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +09008157 hdr = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09008158
Namjae Jeon8a893312021-06-25 13:43:37 +09008159 req_hdr = ksmbd_req_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09008160
8161 if (!work->next_smb2_rsp_hdr_off) {
8162 len = get_rfc1002_len(hdr_org);
8163 if (req_hdr->NextCommand)
8164 len = ALIGN(len, 8);
8165 } else {
8166 len = get_rfc1002_len(hdr_org) - work->next_smb2_rsp_hdr_off;
8167 len = ALIGN(len, 8);
8168 }
8169
Namjae Jeon08bdbc62021-07-27 09:30:29 +09008170 if (conn->binding == false &&
8171 le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
Namjae Jeone2f34482021-03-16 10:49:09 +09008172 signing_key = work->sess->smb3signingkey;
Namjae Jeone2f34482021-03-16 10:49:09 +09008173 } else {
Namjae Jeonf5a544e2021-06-18 10:04:19 +09008174 chann = lookup_chann_list(work->sess, work->conn);
Namjae Jeone2f34482021-03-16 10:49:09 +09008175 if (!chann)
8176 return;
8177 signing_key = chann->smb3signingkey;
Namjae Jeone2f34482021-03-16 10:49:09 +09008178 }
8179
8180 if (!signing_key)
8181 return;
8182
8183 if (req_hdr->NextCommand)
8184 hdr->NextCommand = cpu_to_le32(len);
8185
8186 hdr->Flags |= SMB2_FLAGS_SIGNED;
8187 memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
8188 iov[0].iov_base = (char *)&hdr->ProtocolId;
8189 iov[0].iov_len = len;
Namjae Jeone5066492021-03-30 12:35:23 +09008190 if (work->aux_payload_sz) {
8191 iov[0].iov_len -= work->aux_payload_sz;
8192 iov[1].iov_base = work->aux_payload_buf;
8193 iov[1].iov_len = work->aux_payload_sz;
Namjae Jeone2f34482021-03-16 10:49:09 +09008194 n_vec++;
8195 }
8196
8197 if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, signature))
8198 memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);
8199}
8200
8201/**
8202 * smb3_preauth_hash_rsp() - handler for computing preauth hash on response
8203 * @work: smb work containing response buffer
8204 *
8205 */
8206void smb3_preauth_hash_rsp(struct ksmbd_work *work)
8207{
8208 struct ksmbd_conn *conn = work->conn;
8209 struct ksmbd_session *sess = work->sess;
8210 struct smb2_hdr *req, *rsp;
8211
8212 if (conn->dialect != SMB311_PROT_ID)
8213 return;
8214
8215 WORK_BUFFERS(work, req, rsp);
8216
8217 if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE)
8218 ksmbd_gen_preauth_integrity_hash(conn, (char *)rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09008219 conn->preauth_info->Preauth_HashValue);
Namjae Jeone2f34482021-03-16 10:49:09 +09008220
Namjae Jeonf5a544e2021-06-18 10:04:19 +09008221 if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) {
Namjae Jeone2f34482021-03-16 10:49:09 +09008222 __u8 *hash_value;
8223
Namjae Jeonf5a544e2021-06-18 10:04:19 +09008224 if (conn->binding) {
8225 struct preauth_session *preauth_sess;
8226
8227 preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
8228 if (!preauth_sess)
8229 return;
8230 hash_value = preauth_sess->Preauth_HashValue;
8231 } else {
8232 hash_value = sess->Preauth_HashValue;
8233 if (!hash_value)
8234 return;
8235 }
Namjae Jeone2f34482021-03-16 10:49:09 +09008236 ksmbd_gen_preauth_integrity_hash(conn, (char *)rsp,
Namjae Jeon070fb212021-05-26 17:57:12 +09008237 hash_value);
Namjae Jeone2f34482021-03-16 10:49:09 +09008238 }
8239}
8240
Namjae Jeon64b39f42021-03-30 14:25:35 +09008241static void fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, char *old_buf,
Namjae Jeon070fb212021-05-26 17:57:12 +09008242 __le16 cipher_type)
Namjae Jeone2f34482021-03-16 10:49:09 +09008243{
8244 struct smb2_hdr *hdr = (struct smb2_hdr *)old_buf;
8245 unsigned int orig_len = get_rfc1002_len(old_buf);
8246
8247 memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
8248 tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
8249 tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
8250 tr_hdr->Flags = cpu_to_le16(0x01);
Namjae Jeon5a0ca772021-05-06 11:43:37 +09008251 if (cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
8252 cipher_type == SMB2_ENCRYPTION_AES256_GCM)
8253 get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
Namjae Jeone2f34482021-03-16 10:49:09 +09008254 else
Namjae Jeon5a0ca772021-05-06 11:43:37 +09008255 get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
Namjae Jeone2f34482021-03-16 10:49:09 +09008256 memcpy(&tr_hdr->SessionId, &hdr->SessionId, 8);
8257 inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4);
8258 inc_rfc1001_len(tr_hdr, orig_len);
8259}
8260
8261int smb3_encrypt_resp(struct ksmbd_work *work)
8262{
Namjae Jeone5066492021-03-30 12:35:23 +09008263 char *buf = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09008264 struct smb2_transform_hdr *tr_hdr;
8265 struct kvec iov[3];
8266 int rc = -ENOMEM;
Namjae Jeone5066492021-03-30 12:35:23 +09008267 int buf_size = 0, rq_nvec = 2 + (work->aux_payload_sz ? 1 : 0);
Namjae Jeone2f34482021-03-16 10:49:09 +09008268
8269 if (ARRAY_SIZE(iov) < rq_nvec)
8270 return -ENOMEM;
8271
Namjae Jeon20ea7fd2021-03-30 12:40:47 +09008272 tr_hdr = kzalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL);
Namjae Jeone2f34482021-03-16 10:49:09 +09008273 if (!tr_hdr)
8274 return rc;
8275
8276 /* fill transform header */
8277 fill_transform_hdr(tr_hdr, buf, work->conn->cipher_type);
8278
8279 iov[0].iov_base = tr_hdr;
8280 iov[0].iov_len = sizeof(struct smb2_transform_hdr);
8281 buf_size += iov[0].iov_len - 4;
8282
8283 iov[1].iov_base = buf + 4;
8284 iov[1].iov_len = get_rfc1002_len(buf);
Namjae Jeone5066492021-03-30 12:35:23 +09008285 if (work->aux_payload_sz) {
8286 iov[1].iov_len = work->resp_hdr_sz - 4;
Namjae Jeone2f34482021-03-16 10:49:09 +09008287
Namjae Jeone5066492021-03-30 12:35:23 +09008288 iov[2].iov_base = work->aux_payload_buf;
8289 iov[2].iov_len = work->aux_payload_sz;
Namjae Jeone2f34482021-03-16 10:49:09 +09008290 buf_size += iov[2].iov_len;
8291 }
8292 buf_size += iov[1].iov_len;
8293 work->resp_hdr_sz = iov[1].iov_len;
8294
8295 rc = ksmbd_crypt_message(work->conn, iov, rq_nvec, 1);
8296 if (rc)
8297 return rc;
8298
8299 memmove(buf, iov[1].iov_base, iov[1].iov_len);
8300 tr_hdr->smb2_buf_length = cpu_to_be32(buf_size);
8301 work->tr_buf = tr_hdr;
8302
8303 return rc;
8304}
8305
Namjae Jeonf4228b62021-08-12 10:16:40 +09008306bool smb3_is_transform_hdr(void *buf)
Namjae Jeone2f34482021-03-16 10:49:09 +09008307{
8308 struct smb2_transform_hdr *trhdr = buf;
8309
8310 return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
8311}
8312
8313int smb3_decrypt_req(struct ksmbd_work *work)
8314{
8315 struct ksmbd_conn *conn = work->conn;
8316 struct ksmbd_session *sess;
Namjae Jeone5066492021-03-30 12:35:23 +09008317 char *buf = work->request_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09008318 struct smb2_hdr *hdr;
8319 unsigned int pdu_length = get_rfc1002_len(buf);
8320 struct kvec iov[2];
8321 unsigned int buf_data_size = pdu_length + 4 -
8322 sizeof(struct smb2_transform_hdr);
8323 struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
8324 unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
8325 int rc = 0;
8326
Namjae Jeonf5a544e2021-06-18 10:04:19 +09008327 sess = ksmbd_session_lookup_all(conn, le64_to_cpu(tr_hdr->SessionId));
Namjae Jeone2f34482021-03-16 10:49:09 +09008328 if (!sess) {
Namjae Jeonbde16942021-06-28 15:23:19 +09008329 pr_err("invalid session id(%llx) in transform header\n",
8330 le64_to_cpu(tr_hdr->SessionId));
Namjae Jeone2f34482021-03-16 10:49:09 +09008331 return -ECONNABORTED;
8332 }
8333
Namjae Jeon070fb212021-05-26 17:57:12 +09008334 if (pdu_length + 4 <
8335 sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_hdr)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09008336 pr_err("Transform message is too small (%u)\n",
8337 pdu_length);
Namjae Jeone2f34482021-03-16 10:49:09 +09008338 return -ECONNABORTED;
8339 }
8340
8341 if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) {
Namjae Jeonbde16942021-06-28 15:23:19 +09008342 pr_err("Transform message is broken\n");
Namjae Jeone2f34482021-03-16 10:49:09 +09008343 return -ECONNABORTED;
8344 }
8345
8346 iov[0].iov_base = buf;
8347 iov[0].iov_len = sizeof(struct smb2_transform_hdr);
8348 iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
8349 iov[1].iov_len = buf_data_size;
8350 rc = ksmbd_crypt_message(conn, iov, 2, 0);
8351 if (rc)
8352 return rc;
8353
8354 memmove(buf + 4, iov[1].iov_base, buf_data_size);
8355 hdr = (struct smb2_hdr *)buf;
8356 hdr->smb2_buf_length = cpu_to_be32(buf_data_size);
8357
8358 return rc;
8359}
8360
8361bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
8362{
8363 struct ksmbd_conn *conn = work->conn;
Namjae Jeone5066492021-03-30 12:35:23 +09008364 struct smb2_hdr *rsp = work->response_buf;
Namjae Jeone2f34482021-03-16 10:49:09 +09008365
8366 if (conn->dialect < SMB30_PROT_ID)
8367 return false;
8368
8369 if (work->next_smb2_rcv_hdr_off)
Namjae Jeon8a893312021-06-25 13:43:37 +09008370 rsp = ksmbd_resp_buf_next(work);
Namjae Jeone2f34482021-03-16 10:49:09 +09008371
8372 if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE &&
Namjae Jeon64b39f42021-03-30 14:25:35 +09008373 rsp->Status == STATUS_SUCCESS)
Namjae Jeone2f34482021-03-16 10:49:09 +09008374 return true;
8375 return false;
8376}