• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/smbd/
1/*
2   Unix SMB/CIFS implementation.
3   Core SMB2 server
4
5   Copyright (C) Stefan Metzmacher 2009
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22#include "smbd/globals.h"
23#include "../libcli/smb/smb_common.h"
24
25static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
26			struct tevent_context *ev,
27			struct smbd_smb2_request *smb2req,
28			uint8_t in_oplock_level,
29			uint32_t in_impersonation_level,
30			uint32_t in_desired_access,
31			uint32_t in_file_attributes,
32			uint32_t in_share_access,
33			uint32_t in_create_disposition,
34			uint32_t in_create_options,
35			const char *in_name,
36			struct smb2_create_blobs in_context_blobs);
37static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
38			TALLOC_CTX *mem_ctx,
39			uint8_t *out_oplock_level,
40			uint32_t *out_create_action,
41			NTTIME *out_creation_time,
42			NTTIME *out_last_access_time,
43			NTTIME *out_last_write_time,
44			NTTIME *out_change_time,
45			uint64_t *out_allocation_size,
46			uint64_t *out_end_of_file,
47			uint32_t *out_file_attributes,
48			uint64_t *out_file_id_volatile,
49			struct smb2_create_blobs *out_context_blobs);
50
51static void smbd_smb2_request_create_done(struct tevent_req *subreq);
52NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *req)
53{
54	const uint8_t *inbody;
55	int i = req->current_idx;
56	size_t expected_body_size = 0x39;
57	size_t body_size;
58	uint8_t in_oplock_level;
59	uint32_t in_impersonation_level;
60	uint32_t in_desired_access;
61	uint32_t in_file_attributes;
62	uint32_t in_share_access;
63	uint32_t in_create_disposition;
64	uint32_t in_create_options;
65	uint16_t in_name_offset;
66	uint16_t in_name_length;
67	DATA_BLOB in_name_buffer;
68	char *in_name_string;
69	size_t in_name_string_size;
70	uint32_t name_offset = 0;
71	uint32_t name_available_length = 0;
72	uint32_t in_context_offset;
73	uint32_t in_context_length;
74	DATA_BLOB in_context_buffer;
75	struct smb2_create_blobs in_context_blobs;
76	uint32_t context_offset = 0;
77	uint32_t context_available_length = 0;
78	uint32_t dyn_offset;
79	NTSTATUS status;
80	bool ok;
81	struct tevent_req *subreq;
82
83	if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
84		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
85	}
86
87	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
88
89	body_size = SVAL(inbody, 0x00);
90	if (body_size != expected_body_size) {
91		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
92	}
93
94	in_oplock_level		= CVAL(inbody, 0x03);
95	in_impersonation_level	= IVAL(inbody, 0x04);
96	in_desired_access	= IVAL(inbody, 0x18);
97	in_file_attributes	= IVAL(inbody, 0x1C);
98	in_share_access		= IVAL(inbody, 0x20);
99	in_create_disposition	= IVAL(inbody, 0x24);
100	in_create_options	= IVAL(inbody, 0x28);
101	in_name_offset		= SVAL(inbody, 0x2C);
102	in_name_length		= SVAL(inbody, 0x2E);
103	in_context_offset	= IVAL(inbody, 0x30);
104	in_context_length	= IVAL(inbody, 0x34);
105
106	/*
107	 * First check if the dynamic name and context buffers
108	 * are correctly specified.
109	 *
110	 * Note: That we don't check if the name and context buffers
111	 *       overlap
112	 */
113
114	dyn_offset = SMB2_HDR_BODY + (body_size & 0xFFFFFFFE);
115
116	if (in_name_offset == 0 && in_name_length == 0) {
117		/* This is ok */
118		name_offset = 0;
119	} else if (in_name_offset < dyn_offset) {
120		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
121	} else {
122		name_offset = in_name_offset - dyn_offset;
123	}
124
125	if (name_offset > req->in.vector[i+2].iov_len) {
126		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
127	}
128
129	name_available_length = req->in.vector[i+2].iov_len - name_offset;
130
131	if (in_name_length > name_available_length) {
132		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
133	}
134
135	in_name_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base +
136			      name_offset;
137	in_name_buffer.length = in_name_length;
138
139	if (in_context_offset == 0 && in_context_length == 0) {
140		/* This is ok */
141		context_offset = 0;
142	} else if (in_context_offset < dyn_offset) {
143		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
144	} else {
145		context_offset = in_context_offset - dyn_offset;
146	}
147
148	if (context_offset > req->in.vector[i+2].iov_len) {
149		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
150	}
151
152	context_available_length = req->in.vector[i+2].iov_len - context_offset;
153
154	if (in_context_length > context_available_length) {
155		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
156	}
157
158	in_context_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base +
159				  context_offset;
160	in_context_buffer.length = in_context_length;
161
162	/*
163	 * Now interpret the name and context buffers
164	 */
165
166	ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
167				   in_name_buffer.data,
168				   in_name_buffer.length,
169				   &in_name_string,
170				   &in_name_string_size, false);
171	if (!ok) {
172		return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
173	}
174
175	ZERO_STRUCT(in_context_blobs);
176	status = smb2_create_blob_parse(req, in_context_buffer, &in_context_blobs);
177	if (!NT_STATUS_IS_OK(status)) {
178		return smbd_smb2_request_error(req, status);
179	}
180
181	subreq = smbd_smb2_create_send(req,
182				       req->sconn->smb2.event_ctx,
183				       req,
184				       in_oplock_level,
185				       in_impersonation_level,
186				       in_desired_access,
187				       in_file_attributes,
188				       in_share_access,
189				       in_create_disposition,
190				       in_create_options,
191				       in_name_string,
192				       in_context_blobs);
193	if (subreq == NULL) {
194		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
195	}
196	tevent_req_set_callback(subreq, smbd_smb2_request_create_done, req);
197
198	return smbd_smb2_request_pending_queue(req, subreq);
199}
200
201static void smbd_smb2_request_create_done(struct tevent_req *subreq)
202{
203	struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
204					struct smbd_smb2_request);
205	int i = req->current_idx;
206	uint8_t *outhdr;
207	DATA_BLOB outbody;
208	DATA_BLOB outdyn;
209	uint8_t out_oplock_level = 0;
210	uint32_t out_create_action = 0;
211	NTTIME out_creation_time = 0;
212	NTTIME out_last_access_time = 0;
213	NTTIME out_last_write_time = 0;
214	NTTIME out_change_time = 0;
215	uint64_t out_allocation_size = 0;
216	uint64_t out_end_of_file = 0;
217	uint32_t out_file_attributes = 0;
218	uint64_t out_file_id_volatile = 0;
219	struct smb2_create_blobs out_context_blobs;
220	DATA_BLOB out_context_buffer;
221	uint16_t out_context_buffer_offset = 0;
222	NTSTATUS status;
223	NTSTATUS error; /* transport error */
224
225	status = smbd_smb2_create_recv(subreq,
226				       req,
227				       &out_oplock_level,
228				       &out_create_action,
229				       &out_creation_time,
230				       &out_last_access_time,
231				       &out_last_write_time,
232				       &out_change_time,
233				       &out_allocation_size,
234				       &out_end_of_file,
235				       &out_file_attributes,
236				       &out_file_id_volatile,
237				       &out_context_blobs);
238	TALLOC_FREE(subreq);
239	if (!NT_STATUS_IS_OK(status)) {
240		error = smbd_smb2_request_error(req, status);
241		if (!NT_STATUS_IS_OK(error)) {
242			smbd_server_connection_terminate(req->sconn,
243							 nt_errstr(error));
244			return;
245		}
246		return;
247	}
248
249	status = smb2_create_blob_push(req, &out_context_buffer, out_context_blobs);
250	if (!NT_STATUS_IS_OK(status)) {
251		error = smbd_smb2_request_error(req, status);
252		if (!NT_STATUS_IS_OK(error)) {
253			smbd_server_connection_terminate(req->sconn,
254							 nt_errstr(error));
255			return;
256		}
257		return;
258	}
259
260	if (out_context_buffer.length > 0) {
261		out_context_buffer_offset = SMB2_HDR_BODY + 0x58;
262	}
263
264	outhdr = (uint8_t *)req->out.vector[i].iov_base;
265
266	outbody = data_blob_talloc(req->out.vector, NULL, 0x58);
267	if (outbody.data == NULL) {
268		error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
269		if (!NT_STATUS_IS_OK(error)) {
270			smbd_server_connection_terminate(req->sconn,
271							 nt_errstr(error));
272			return;
273		}
274		return;
275	}
276
277	SSVAL(outbody.data, 0x00, 0x58 + 1);	/* struct size */
278	SCVAL(outbody.data, 0x02,
279	      out_oplock_level);		/* oplock level */
280	SCVAL(outbody.data, 0x03, 0);		/* reserved */
281	SIVAL(outbody.data, 0x04,
282	      out_create_action);		/* create action */
283	SBVAL(outbody.data, 0x08,
284	      out_creation_time);		/* creation time */
285	SBVAL(outbody.data, 0x10,
286	      out_last_access_time);		/* last access time */
287	SBVAL(outbody.data, 0x18,
288	      out_last_write_time);		/* last write time */
289	SBVAL(outbody.data, 0x20,
290	      out_change_time);			/* change time */
291	SBVAL(outbody.data, 0x28,
292	      out_allocation_size);		/* allocation size */
293	SBVAL(outbody.data, 0x30,
294	      out_end_of_file);			/* end of file */
295	SIVAL(outbody.data, 0x38,
296	      out_file_attributes);		/* file attributes */
297	SIVAL(outbody.data, 0x3C, 0);		/* reserved */
298	SBVAL(outbody.data, 0x40, 0);		/* file id (persistent) */
299	SBVAL(outbody.data, 0x48,
300	      out_file_id_volatile);		/* file id (volatile) */
301	SIVAL(outbody.data, 0x50,
302	      out_context_buffer_offset);	/* create contexts offset */
303	SIVAL(outbody.data, 0x54,
304	      out_context_buffer.length);	/* create contexts length */
305
306	outdyn = out_context_buffer;
307
308	error = smbd_smb2_request_done(req, outbody, &outdyn);
309	if (!NT_STATUS_IS_OK(error)) {
310		smbd_server_connection_terminate(req->sconn,
311						 nt_errstr(error));
312		return;
313	}
314}
315
316struct smbd_smb2_create_state {
317	struct smbd_smb2_request *smb2req;
318	uint8_t out_oplock_level;
319	uint32_t out_create_action;
320	NTTIME out_creation_time;
321	NTTIME out_last_access_time;
322	NTTIME out_last_write_time;
323	NTTIME out_change_time;
324	uint64_t out_allocation_size;
325	uint64_t out_end_of_file;
326	uint32_t out_file_attributes;
327	uint64_t out_file_id_volatile;
328	struct smb2_create_blobs out_context_blobs;
329};
330
331static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
332			struct tevent_context *ev,
333			struct smbd_smb2_request *smb2req,
334			uint8_t in_oplock_level,
335			uint32_t in_impersonation_level,
336			uint32_t in_desired_access,
337			uint32_t in_file_attributes,
338			uint32_t in_share_access,
339			uint32_t in_create_disposition,
340			uint32_t in_create_options,
341			const char *in_name,
342			struct smb2_create_blobs in_context_blobs)
343{
344	struct tevent_req *req;
345	struct smbd_smb2_create_state *state;
346	NTSTATUS status;
347	struct smb_request *smbreq;
348	files_struct *result;
349	int info;
350	struct timespec write_time_ts;
351	struct smb2_create_blobs out_context_blobs;
352
353	ZERO_STRUCT(out_context_blobs);
354
355	req = tevent_req_create(mem_ctx, &state,
356				struct smbd_smb2_create_state);
357	if (req == NULL) {
358		return NULL;
359	}
360	state->smb2req = smb2req;
361
362	DEBUG(10,("smbd_smb2_create: name[%s]\n",
363		  in_name));
364
365	smbreq = smbd_smb2_fake_smb_request(smb2req);
366	if (tevent_req_nomem(smbreq, req)) {
367		return tevent_req_post(req, ev);
368	}
369
370	if (IS_IPC(smbreq->conn)) {
371		const char *pipe_name = in_name;
372
373		if (!lp_nt_pipe_support()) {
374			tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
375			return tevent_req_post(req, ev);
376		}
377
378		/* Strip \\ off the name. */
379		if (pipe_name[0] == '\\') {
380			pipe_name++;
381		}
382
383		status = open_np_file(smbreq, pipe_name, &result);
384		if (!NT_STATUS_IS_OK(status)) {
385			tevent_req_nterror(req, status);
386			return tevent_req_post(req, ev);
387		}
388		info = FILE_WAS_OPENED;
389	} else if (CAN_PRINT(smbreq->conn)) {
390		status = file_new(smbreq, smbreq->conn, &result);
391		if(!NT_STATUS_IS_OK(status)) {
392			tevent_req_nterror(req, status);
393			return tevent_req_post(req, ev);
394		}
395
396		status = print_fsp_open(smbreq,
397					smbreq->conn,
398					in_name,
399					smbreq->vuid,
400					result);
401		if (!NT_STATUS_IS_OK(status)) {
402			file_free(smbreq, result);
403			tevent_req_nterror(req, status);
404			return tevent_req_post(req, ev);
405		}
406		info = FILE_WAS_CREATED;
407	} else {
408		char *fname;
409		struct smb_filename *smb_fname = NULL;
410		struct smb2_create_blob *exta = NULL;
411		struct ea_list *ea_list = NULL;
412		struct smb2_create_blob *mxac = NULL;
413		NTTIME max_access_time = 0;
414		struct smb2_create_blob *secd = NULL;
415		struct security_descriptor *sec_desc = NULL;
416		struct smb2_create_blob *dhnq = NULL;
417		struct smb2_create_blob *dhnc = NULL;
418		struct smb2_create_blob *alsi = NULL;
419		uint64_t allocation_size = 0;
420		struct smb2_create_blob *twrp = NULL;
421		struct smb2_create_blob *qfid = NULL;
422
423		exta = smb2_create_blob_find(&in_context_blobs,
424					     SMB2_CREATE_TAG_EXTA);
425		mxac = smb2_create_blob_find(&in_context_blobs,
426					     SMB2_CREATE_TAG_MXAC);
427		secd = smb2_create_blob_find(&in_context_blobs,
428					     SMB2_CREATE_TAG_SECD);
429		dhnq = smb2_create_blob_find(&in_context_blobs,
430					     SMB2_CREATE_TAG_DHNQ);
431		dhnc = smb2_create_blob_find(&in_context_blobs,
432					     SMB2_CREATE_TAG_DHNC);
433		alsi = smb2_create_blob_find(&in_context_blobs,
434					     SMB2_CREATE_TAG_ALSI);
435		twrp = smb2_create_blob_find(&in_context_blobs,
436					     SMB2_CREATE_TAG_TWRP);
437		qfid = smb2_create_blob_find(&in_context_blobs,
438					     SMB2_CREATE_TAG_QFID);
439
440		fname = talloc_strdup(state, in_name);
441		if (tevent_req_nomem(fname, req)) {
442			return tevent_req_post(req, ev);
443		}
444
445		if (exta) {
446			if (dhnc) {
447				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
448				return tevent_req_post(req, ev);
449			}
450
451			ea_list = read_nttrans_ea_list(mem_ctx,
452				(const char *)exta->data.data, exta->data.length);
453			if (!ea_list) {
454				DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
455				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
456				return tevent_req_post(req, ev);
457			}
458		}
459
460		if (mxac) {
461			if (dhnc) {
462				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
463				return tevent_req_post(req, ev);
464			}
465
466			if (mxac->data.length == 0) {
467				max_access_time = 0;
468			} else if (mxac->data.length == 8) {
469				max_access_time = BVAL(mxac->data.data, 0);
470			} else {
471				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
472				return tevent_req_post(req, ev);
473			}
474		}
475
476		if (secd) {
477			enum ndr_err_code ndr_err;
478
479			if (dhnc) {
480				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
481				return tevent_req_post(req, ev);
482			}
483
484			sec_desc = talloc_zero(state, struct security_descriptor);
485			if (tevent_req_nomem(sec_desc, req)) {
486				return tevent_req_post(req, ev);
487			}
488
489			ndr_err = ndr_pull_struct_blob(&secd->data,
490				sec_desc, NULL, sec_desc,
491				(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
492			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
493				DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
494					 ndr_errstr(ndr_err)));
495				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
496				return tevent_req_post(req, ev);
497			}
498		}
499
500		if (dhnq) {
501			if (dhnc) {
502				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
503				return tevent_req_post(req, ev);
504			}
505
506			if (dhnq->data.length != 16) {
507				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
508				return tevent_req_post(req, ev);
509			}
510			/*
511			 * we don't support durable handles yet
512			 * and have to ignore this
513			 */
514		}
515
516		if (dhnc) {
517			if (dhnc->data.length != 16) {
518				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
519				return tevent_req_post(req, ev);
520			}
521			/* we don't support durable handles yet */
522			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
523			return tevent_req_post(req, ev);
524		}
525
526		if (alsi) {
527			if (dhnc) {
528				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
529				return tevent_req_post(req, ev);
530			}
531
532			if (alsi->data.length != 8) {
533				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
534				return tevent_req_post(req, ev);
535			}
536			allocation_size = BVAL(alsi->data.data, 0);
537		}
538
539		if (twrp) {
540			NTTIME nttime;
541			time_t t;
542			struct tm *tm;
543
544			if (dhnc) {
545				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
546				return tevent_req_post(req, ev);
547			}
548
549			if (twrp->data.length != 8) {
550				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
551				return tevent_req_post(req, ev);
552			}
553
554			nttime = BVAL(twrp->data.data, 0);
555			t = nt_time_to_unix(nttime);
556			tm = gmtime(&t);
557
558			TALLOC_FREE(fname);
559			fname = talloc_asprintf(state,
560					"@GMT-%04u.%02u.%02u-%02u.%02u.%02u\\%s",
561					tm->tm_year + 1900,
562					tm->tm_mon + 1,
563					tm->tm_mday,
564					tm->tm_hour,
565					tm->tm_min,
566					tm->tm_sec,
567					in_name);
568			if (tevent_req_nomem(fname, req)) {
569				return tevent_req_post(req, ev);
570			}
571		}
572
573		if (qfid) {
574			if (qfid->data.length != 0) {
575				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
576				return tevent_req_post(req, ev);
577			}
578		}
579
580		/* these are ignored for SMB2 */
581		in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
582		in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
583
584		/* convert '\\' into '/' */
585		status = check_path_syntax(fname);
586		if (!NT_STATUS_IS_OK(status)) {
587			tevent_req_nterror(req, status);
588			return tevent_req_post(req, ev);
589		}
590
591		status = filename_convert(req,
592					  smbreq->conn,
593					  smbreq->flags2 & FLAGS2_DFS_PATHNAMES,
594					  fname,
595					  0,
596					  NULL,
597					  &smb_fname);
598		if (!NT_STATUS_IS_OK(status)) {
599			tevent_req_nterror(req, status);
600			return tevent_req_post(req, ev);
601		}
602
603		status = SMB_VFS_CREATE_FILE(smbreq->conn,
604					     smbreq,
605					     0, /* root_dir_fid */
606					     smb_fname,
607					     in_desired_access,
608					     in_share_access,
609					     in_create_disposition,
610					     in_create_options,
611					     in_file_attributes,
612					     0, /* oplock_request */
613					     allocation_size,
614					     sec_desc,
615					     ea_list,
616					     &result,
617					     &info);
618		if (!NT_STATUS_IS_OK(status)) {
619			tevent_req_nterror(req, status);
620			return tevent_req_post(req, ev);
621		}
622
623		if (mxac) {
624			NTTIME last_write_time;
625
626			unix_timespec_to_nt_time(&last_write_time,
627						 result->fsp_name->st.st_ex_mtime);
628			if (last_write_time != max_access_time) {
629				uint8_t p[8];
630				uint32_t max_access_granted;
631				DATA_BLOB blob = data_blob_const(p, sizeof(p));
632
633				status = smbd_check_open_rights(smbreq->conn,
634							result->fsp_name,
635							SEC_FLAG_MAXIMUM_ALLOWED,
636							&max_access_granted);
637
638				SIVAL(p, 0, NT_STATUS_V(status));
639				SIVAL(p, 4, max_access_granted);
640
641				status = smb2_create_blob_add(state,
642							&out_context_blobs,
643							SMB2_CREATE_TAG_MXAC,
644							blob);
645				if (!NT_STATUS_IS_OK(status)) {
646					tevent_req_nterror(req, status);
647					return tevent_req_post(req, ev);
648				}
649			}
650		}
651
652		if (qfid) {
653			uint8_t p[32];
654			uint64_t file_index = get_FileIndex(result->conn,
655							&result->fsp_name->st);
656			DATA_BLOB blob = data_blob_const(p, sizeof(p));
657
658			ZERO_STRUCT(p);
659
660			/* From conversations with Microsoft engineers at
661			   the MS plugfest. The first 8 bytes are the "volume index"
662			   == inode, the second 8 bytes are the "volume id",
663			   == dev. This will be updated in the SMB2 doc. */
664			SBVAL(p, 0, file_index);
665			SIVAL(p, 8, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
666
667			status = smb2_create_blob_add(state, &out_context_blobs,
668						      SMB2_CREATE_TAG_QFID,
669						      blob);
670			if (!NT_STATUS_IS_OK(status)) {
671				tevent_req_nterror(req, status);
672				return tevent_req_post(req, ev);
673			}
674		}
675	}
676
677	smb2req->compat_chain_fsp = smbreq->chain_fsp;
678
679	state->out_oplock_level	= 0;
680	if ((in_create_disposition == FILE_SUPERSEDE)
681	    && (info == FILE_WAS_OVERWRITTEN)) {
682		state->out_create_action = FILE_WAS_SUPERSEDED;
683	} else {
684		state->out_create_action = info;
685	}
686	state->out_file_attributes = dos_mode(result->conn,
687					   result->fsp_name);
688	/* Deal with other possible opens having a modified
689	   write time. JRA. */
690	ZERO_STRUCT(write_time_ts);
691	get_file_infos(result->file_id, NULL, &write_time_ts);
692	if (!null_timespec(write_time_ts)) {
693		update_stat_ex_mtime(&result->fsp_name->st, write_time_ts);
694	}
695
696	unix_timespec_to_nt_time(&state->out_creation_time,
697			get_create_timespec(smbreq->conn, result,
698					result->fsp_name));
699	unix_timespec_to_nt_time(&state->out_last_access_time,
700			result->fsp_name->st.st_ex_atime);
701	unix_timespec_to_nt_time(&state->out_last_write_time,
702			result->fsp_name->st.st_ex_mtime);
703	unix_timespec_to_nt_time(&state->out_change_time,
704			get_change_timespec(smbreq->conn, result,
705					result->fsp_name));
706	state->out_allocation_size =
707			result->fsp_name->st.st_ex_blksize *
708			result->fsp_name->st.st_ex_blocks;
709	state->out_end_of_file = result->fsp_name->st.st_ex_size;
710	if (state->out_file_attributes == 0) {
711		state->out_file_attributes = FILE_ATTRIBUTE_NORMAL;
712	}
713	state->out_file_id_volatile = result->fnum;
714	state->out_context_blobs = out_context_blobs;
715
716	tevent_req_done(req);
717	return tevent_req_post(req, ev);
718}
719
720static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
721			TALLOC_CTX *mem_ctx,
722			uint8_t *out_oplock_level,
723			uint32_t *out_create_action,
724			NTTIME *out_creation_time,
725			NTTIME *out_last_access_time,
726			NTTIME *out_last_write_time,
727			NTTIME *out_change_time,
728			uint64_t *out_allocation_size,
729			uint64_t *out_end_of_file,
730			uint32_t *out_file_attributes,
731			uint64_t *out_file_id_volatile,
732			struct smb2_create_blobs *out_context_blobs)
733{
734	NTSTATUS status;
735	struct smbd_smb2_create_state *state = tevent_req_data(req,
736					       struct smbd_smb2_create_state);
737
738	if (tevent_req_is_nterror(req, &status)) {
739		tevent_req_received(req);
740		return status;
741	}
742
743	*out_oplock_level	= state->out_oplock_level;
744	*out_create_action	= state->out_create_action;
745	*out_creation_time	= state->out_creation_time;
746	*out_last_access_time	= state->out_last_access_time;
747	*out_last_write_time	= state->out_last_write_time;
748	*out_change_time	= state->out_change_time;
749	*out_allocation_size	= state->out_allocation_size;
750	*out_end_of_file	= state->out_end_of_file;
751	*out_file_attributes	= state->out_file_attributes;
752	*out_file_id_volatile	= state->out_file_id_volatile;
753	*out_context_blobs	= state->out_context_blobs;
754
755	talloc_steal(mem_ctx, state->out_context_blobs.blobs);
756
757	tevent_req_received(req);
758	return NT_STATUS_OK;
759}
760