Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB transaction2 handling
4 : Copyright (C) Jeremy Allison 1994-2007
5 : Copyright (C) Stefan (metze) Metzmacher 2003
6 : Copyright (C) Volker Lendecke 2005-2007
7 : Copyright (C) Steve French 2005
8 : Copyright (C) James Peach 2006-2007
9 :
10 : Extensively modified by Andrew Tridgell, 1995
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include "includes.h"
27 : #include "ntioctl.h"
28 : #include "system/filesys.h"
29 : #include "lib/util/time_basic.h"
30 : #include "version.h"
31 : #include "smbd/smbd.h"
32 : #include "smbd/globals.h"
33 : #include "../libcli/auth/libcli_auth.h"
34 : #include "../librpc/gen_ndr/xattr.h"
35 : #include "../librpc/gen_ndr/ndr_security.h"
36 : #include "libcli/security/security.h"
37 : #include "trans2.h"
38 : #include "auth.h"
39 : #include "smbprofile.h"
40 : #include "rpc_server/srv_pipe_hnd.h"
41 : #include "printing.h"
42 : #include "lib/util_ea.h"
43 : #include "lib/readdir_attr.h"
44 : #include "messages.h"
45 : #include "libcli/smb/smb2_posix.h"
46 : #include "lib/util/string_wrappers.h"
47 : #include "source3/lib/substitute.h"
48 : #include "source3/lib/adouble.h"
49 : #include "source3/smbd/dir.h"
50 :
51 : #define DIR_ENTRY_SAFETY_MARGIN 4096
52 :
53 : /****************************************************************************
54 : Send the required number of replies back.
55 : We assume all fields other than the data fields are
56 : set correctly for the type of call.
57 : HACK ! Always assumes smb_setup field is zero.
58 : ****************************************************************************/
59 :
60 30496 : static void send_trans2_replies(connection_struct *conn,
61 : struct smb_request *req,
62 : NTSTATUS status,
63 : const char *params,
64 : int paramsize,
65 : const char *pdata,
66 : int datasize,
67 : int max_data_bytes)
68 : {
69 : /* As we are using a protocol > LANMAN1 then the max_send
70 : variable must have been set in the sessetupX call.
71 : This takes precedence over the max_xmit field in the
72 : global struct. These different max_xmit variables should
73 : be merged as this is now too confusing */
74 :
75 30496 : int data_to_send = datasize;
76 30496 : int params_to_send = paramsize;
77 1172 : int useable_space;
78 30496 : const char *pp = params;
79 30496 : const char *pd = pdata;
80 1172 : int params_sent_thistime, data_sent_thistime, total_sent_thistime;
81 30496 : int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
82 30496 : int data_alignment_offset = 0;
83 30496 : bool overflow = False;
84 30496 : struct smbXsrv_connection *xconn = req->xconn;
85 30496 : int max_send = xconn->smb1.sessions.max_send;
86 :
87 : /* Modify the data_to_send and datasize and set the error if
88 : we're trying to send more than max_data_bytes. We still send
89 : the part of the packet(s) that fit. Strange, but needed
90 : for OS/2. */
91 :
92 30496 : if (max_data_bytes > 0 && datasize > max_data_bytes) {
93 0 : DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
94 : max_data_bytes, datasize ));
95 0 : datasize = data_to_send = max_data_bytes;
96 0 : overflow = True;
97 : }
98 :
99 : /* If there genuinely are no parameters or data to send just send the empty packet */
100 :
101 30496 : if(params_to_send == 0 && data_to_send == 0) {
102 0 : reply_smb1_outbuf(req, 10, 0);
103 0 : if (NT_STATUS_V(status)) {
104 0 : uint8_t eclass;
105 0 : uint32_t ecode;
106 0 : ntstatus_to_dos(status, &eclass, &ecode);
107 0 : error_packet_set((char *)req->outbuf,
108 : eclass, ecode, status,
109 : __LINE__,__FILE__);
110 : }
111 0 : show_msg((char *)req->outbuf);
112 0 : if (!smb1_srv_send(xconn,
113 0 : (char *)req->outbuf,
114 : true,
115 0 : req->seqnum + 1,
116 0 : IS_CONN_ENCRYPTED(conn))) {
117 0 : exit_server_cleanly("send_trans2_replies: smb1_srv_send failed.");
118 : }
119 0 : TALLOC_FREE(req->outbuf);
120 0 : return;
121 : }
122 :
123 : /* When sending params and data ensure that both are nicely aligned */
124 : /* Only do this alignment when there is also data to send - else
125 : can cause NT redirector problems. */
126 :
127 30496 : if (((params_to_send % 4) != 0) && (data_to_send != 0))
128 20697 : data_alignment_offset = 4 - (params_to_send % 4);
129 :
130 : /* Space is bufsize minus Netbios over TCP header minus SMB header */
131 : /* The alignment_offset is to align the param bytes on an even byte
132 : boundary. NT 4.0 Beta needs this to work correctly. */
133 :
134 30496 : useable_space = max_send - (smb_size
135 : + 2 * 10 /* wct */
136 29324 : + alignment_offset
137 30496 : + data_alignment_offset);
138 :
139 30496 : if (useable_space < 0) {
140 0 : DEBUG(0, ("send_trans2_replies failed sanity useable_space "
141 : "= %d!!!\n", useable_space));
142 0 : exit_server_cleanly("send_trans2_replies: Not enough space");
143 : }
144 :
145 61020 : while (params_to_send || data_to_send) {
146 : /* Calculate whether we will totally or partially fill this packet */
147 :
148 30524 : total_sent_thistime = params_to_send + data_to_send;
149 :
150 : /* We can never send more than useable_space */
151 : /*
152 : * Note that 'useable_space' does not include the alignment offsets,
153 : * but we must include the alignment offsets in the calculation of
154 : * the length of the data we send over the wire, as the alignment offsets
155 : * are sent here. Fix from Marc_Jacobsen@hp.com.
156 : */
157 :
158 30524 : total_sent_thistime = MIN(total_sent_thistime, useable_space);
159 :
160 30524 : reply_smb1_outbuf(req, 10, total_sent_thistime + alignment_offset
161 30524 : + data_alignment_offset);
162 :
163 : /* Set total params and data to be sent */
164 30524 : SSVAL(req->outbuf,smb_tprcnt,paramsize);
165 30524 : SSVAL(req->outbuf,smb_tdrcnt,datasize);
166 :
167 : /* Calculate how many parameters and data we can fit into
168 : * this packet. Parameters get precedence
169 : */
170 :
171 30524 : params_sent_thistime = MIN(params_to_send,useable_space);
172 30524 : data_sent_thistime = useable_space - params_sent_thistime;
173 30524 : data_sent_thistime = MIN(data_sent_thistime,data_to_send);
174 :
175 30524 : SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
176 :
177 : /* smb_proff is the offset from the start of the SMB header to the
178 : parameter bytes, however the first 4 bytes of outbuf are
179 : the Netbios over TCP header. Thus use smb_base() to subtract
180 : them from the calculation */
181 :
182 30524 : SSVAL(req->outbuf,smb_proff,
183 : ((smb_buf(req->outbuf)+alignment_offset)
184 : - smb_base(req->outbuf)));
185 :
186 30524 : if(params_sent_thistime == 0)
187 3149 : SSVAL(req->outbuf,smb_prdisp,0);
188 : else
189 : /* Absolute displacement of param bytes sent in this packet */
190 27375 : SSVAL(req->outbuf,smb_prdisp,pp - params);
191 :
192 30524 : SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
193 30524 : if(data_sent_thistime == 0) {
194 5050 : SSVAL(req->outbuf,smb_droff,0);
195 5050 : SSVAL(req->outbuf,smb_drdisp, 0);
196 : } else {
197 : /* The offset of the data bytes is the offset of the
198 : parameter bytes plus the number of parameters being sent this time */
199 25474 : SSVAL(req->outbuf, smb_droff,
200 : ((smb_buf(req->outbuf)+alignment_offset)
201 : - smb_base(req->outbuf))
202 : + params_sent_thistime + data_alignment_offset);
203 25474 : SSVAL(req->outbuf,smb_drdisp, pd - pdata);
204 : }
205 :
206 : /* Initialize the padding for alignment */
207 :
208 30524 : if (alignment_offset != 0) {
209 30524 : memset(smb_buf(req->outbuf), 0, alignment_offset);
210 : }
211 :
212 : /* Copy the param bytes into the packet */
213 :
214 30524 : if(params_sent_thistime) {
215 27375 : memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
216 : params_sent_thistime);
217 : }
218 :
219 : /* Copy in the data bytes */
220 30524 : if(data_sent_thistime) {
221 25474 : if (data_alignment_offset != 0) {
222 20717 : memset((smb_buf(req->outbuf)+alignment_offset+
223 : params_sent_thistime), 0,
224 : data_alignment_offset);
225 : }
226 26646 : memcpy(smb_buf(req->outbuf)+alignment_offset
227 25474 : +params_sent_thistime+data_alignment_offset,
228 : pd,data_sent_thistime);
229 : }
230 :
231 30524 : DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
232 : params_sent_thistime, data_sent_thistime, useable_space));
233 30524 : DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
234 : params_to_send, data_to_send, paramsize, datasize));
235 :
236 30524 : if (overflow) {
237 0 : error_packet_set((char *)req->outbuf,
238 : ERRDOS,ERRbufferoverflow,
239 0 : STATUS_BUFFER_OVERFLOW,
240 : __LINE__,__FILE__);
241 30524 : } else if (NT_STATUS_V(status)) {
242 47 : uint8_t eclass;
243 47 : uint32_t ecode;
244 235 : ntstatus_to_dos(status, &eclass, &ecode);
245 235 : error_packet_set((char *)req->outbuf,
246 : eclass, ecode, status,
247 : __LINE__,__FILE__);
248 : }
249 :
250 : /* Send the packet */
251 30524 : show_msg((char *)req->outbuf);
252 30524 : if (!smb1_srv_send(xconn,
253 30524 : (char *)req->outbuf,
254 : true,
255 30524 : req->seqnum + 1,
256 30524 : IS_CONN_ENCRYPTED(conn))) {
257 0 : exit_server_cleanly("send_trans2_replies: smb1_srv_send failed.");
258 : }
259 :
260 30524 : TALLOC_FREE(req->outbuf);
261 :
262 30524 : pp += params_sent_thistime;
263 30524 : pd += data_sent_thistime;
264 :
265 30524 : params_to_send -= params_sent_thistime;
266 30524 : data_to_send -= data_sent_thistime;
267 :
268 : /* Sanity check */
269 30524 : if(params_to_send < 0 || data_to_send < 0) {
270 0 : DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
271 : params_to_send, data_to_send));
272 0 : return;
273 : }
274 : }
275 :
276 29324 : return;
277 : }
278 :
279 : /****************************************************************************
280 : Deal with SMB_SET_POSIX_LOCK.
281 : ****************************************************************************/
282 :
283 : static void smb_set_posix_lock_done(struct tevent_req *subreq);
284 :
285 36 : static NTSTATUS smb_set_posix_lock(connection_struct *conn,
286 : struct smb_request *req,
287 : const char *pdata,
288 : int total_data,
289 : files_struct *fsp)
290 : {
291 36 : struct tevent_req *subreq = NULL;
292 36 : struct smbd_lock_element *lck = NULL;
293 0 : uint64_t count;
294 0 : uint64_t offset;
295 0 : uint64_t smblctx;
296 36 : bool blocking_lock = False;
297 0 : enum brl_type lock_type;
298 :
299 36 : NTSTATUS status = NT_STATUS_OK;
300 :
301 36 : if (!CAN_WRITE(conn)) {
302 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
303 : }
304 :
305 36 : if (fsp == NULL ||
306 36 : fsp->fsp_flags.is_pathref ||
307 36 : fsp_get_io_fd(fsp) == -1)
308 : {
309 0 : return NT_STATUS_INVALID_HANDLE;
310 : }
311 :
312 36 : if (total_data != POSIX_LOCK_DATA_SIZE) {
313 0 : return NT_STATUS_INVALID_PARAMETER;
314 : }
315 :
316 36 : switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
317 4 : case POSIX_LOCK_TYPE_READ:
318 4 : lock_type = READ_LOCK;
319 4 : break;
320 24 : case POSIX_LOCK_TYPE_WRITE:
321 : /* Return the right POSIX-mappable error code for files opened read-only. */
322 24 : if (!fsp->fsp_flags.can_write) {
323 0 : return NT_STATUS_INVALID_HANDLE;
324 : }
325 24 : lock_type = WRITE_LOCK;
326 24 : break;
327 8 : case POSIX_LOCK_TYPE_UNLOCK:
328 8 : lock_type = UNLOCK_LOCK;
329 8 : break;
330 0 : default:
331 0 : return NT_STATUS_INVALID_PARAMETER;
332 : }
333 :
334 36 : switch (SVAL(pdata, POSIX_LOCK_FLAGS_OFFSET)) {
335 28 : case POSIX_LOCK_FLAG_NOWAIT:
336 28 : blocking_lock = false;
337 28 : break;
338 8 : case POSIX_LOCK_FLAG_WAIT:
339 8 : blocking_lock = true;
340 8 : break;
341 0 : default:
342 0 : return NT_STATUS_INVALID_PARAMETER;
343 : }
344 :
345 36 : if (!lp_blocking_locks(SNUM(conn))) {
346 0 : blocking_lock = False;
347 : }
348 :
349 36 : smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
350 36 : offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
351 36 : ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
352 36 : count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
353 36 : ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
354 :
355 36 : DBG_DEBUG("file %s, lock_type = %u, smblctx = %"PRIu64", "
356 : "count = %"PRIu64", offset = %"PRIu64"\n",
357 : fsp_str_dbg(fsp),
358 : (unsigned int)lock_type,
359 : smblctx,
360 : count,
361 : offset);
362 :
363 36 : if (lock_type == UNLOCK_LOCK) {
364 8 : struct smbd_lock_element l = {
365 8 : .req_guid = smbd_request_guid(req, 0),
366 : .smblctx = smblctx,
367 : .brltype = UNLOCK_LOCK,
368 : .lock_flav = POSIX_LOCK,
369 : .offset = offset,
370 : .count = count,
371 : };
372 8 : status = smbd_do_unlocking(req, fsp, 1, &l);
373 8 : return status;
374 : }
375 :
376 28 : lck = talloc(req, struct smbd_lock_element);
377 28 : if (lck == NULL) {
378 0 : return NT_STATUS_NO_MEMORY;
379 : }
380 :
381 28 : *lck = (struct smbd_lock_element) {
382 28 : .req_guid = smbd_request_guid(req, 0),
383 : .smblctx = smblctx,
384 : .brltype = lock_type,
385 : .lock_flav = POSIX_LOCK,
386 : .count = count,
387 : .offset = offset,
388 : };
389 :
390 28 : subreq = smbd_smb1_do_locks_send(
391 : fsp,
392 28 : req->sconn->ev_ctx,
393 : &req,
394 : fsp,
395 : blocking_lock ? UINT32_MAX : 0,
396 : true, /* large_offset */
397 : 1,
398 : lck);
399 28 : if (subreq == NULL) {
400 0 : TALLOC_FREE(lck);
401 0 : return NT_STATUS_NO_MEMORY;
402 : }
403 28 : tevent_req_set_callback(subreq, smb_set_posix_lock_done, req);
404 28 : return NT_STATUS_EVENT_PENDING;
405 : }
406 :
407 28 : static void smb_set_posix_lock_done(struct tevent_req *subreq)
408 : {
409 28 : struct smb_request *req = NULL;
410 0 : NTSTATUS status;
411 0 : bool ok;
412 :
413 28 : ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
414 28 : SMB_ASSERT(ok);
415 :
416 28 : status = smbd_smb1_do_locks_recv(subreq);
417 28 : TALLOC_FREE(subreq);
418 :
419 28 : if (NT_STATUS_IS_OK(status)) {
420 24 : char params[2] = {0};
421 : /* Fake up max_data_bytes here - we know it fits. */
422 24 : send_trans2_replies(
423 24 : req->conn,
424 : req,
425 24 : NT_STATUS_OK,
426 : params,
427 : 2,
428 : NULL,
429 : 0,
430 : 0xffff);
431 : } else {
432 4 : reply_nterror(req, status);
433 4 : ok = smb1_srv_send(req->xconn,
434 4 : (char *)req->outbuf,
435 : true,
436 4 : req->seqnum + 1,
437 4 : IS_CONN_ENCRYPTED(req->conn));
438 4 : if (!ok) {
439 0 : exit_server_cleanly("smb_set_posix_lock_done: "
440 : "smb1_srv_send failed.");
441 : }
442 : }
443 :
444 28 : TALLOC_FREE(req);
445 28 : return;
446 : }
447 :
448 : /****************************************************************************
449 : Read a list of EA names from an incoming data buffer. Create an ea_list with them.
450 : ****************************************************************************/
451 :
452 164 : static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
453 : {
454 164 : struct ea_list *ea_list_head = NULL;
455 164 : size_t converted_size, offset = 0;
456 :
457 340 : while (offset + 2 < data_size) {
458 176 : struct ea_list *eal = talloc_zero(ctx, struct ea_list);
459 176 : unsigned int namelen = CVAL(pdata,offset);
460 :
461 176 : offset++; /* Go past the namelen byte. */
462 :
463 : /* integer wrap paranioa. */
464 176 : if ((offset + namelen < offset) || (offset + namelen < namelen) ||
465 176 : (offset > data_size) || (namelen > data_size) ||
466 148 : (offset + namelen >= data_size)) {
467 : break;
468 : }
469 : /* Ensure the name is null terminated. */
470 176 : if (pdata[offset + namelen] != '\0') {
471 0 : return NULL;
472 : }
473 176 : if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
474 : &converted_size)) {
475 0 : DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
476 : "failed: %s\n", strerror(errno)));
477 : }
478 176 : if (!eal->ea.name) {
479 0 : return NULL;
480 : }
481 :
482 176 : offset += (namelen + 1); /* Go past the name + terminating zero. */
483 176 : DLIST_ADD_END(ea_list_head, eal);
484 176 : DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
485 : }
486 :
487 136 : return ea_list_head;
488 : }
489 :
490 : /****************************************************************************
491 : Reply to a TRANSACT2_OPEN.
492 : ****************************************************************************/
493 :
494 98 : static void call_trans2open(connection_struct *conn,
495 : struct smb_request *req,
496 : char **pparams, int total_params,
497 : char **ppdata, int total_data,
498 : unsigned int max_data_bytes)
499 : {
500 98 : struct smb_filename *smb_fname = NULL;
501 98 : char *params = *pparams;
502 98 : char *pdata = *ppdata;
503 18 : int deny_mode;
504 18 : int32_t open_attr;
505 18 : bool oplock_request;
506 : #if 0
507 : bool return_additional_info;
508 : int16 open_sattr;
509 : time_t open_time;
510 : #endif
511 18 : int open_ofun;
512 18 : uint32_t open_size;
513 18 : char *pname;
514 98 : char *fname = NULL;
515 98 : off_t size=0;
516 98 : int fattr = 0;
517 98 : SMB_INO_T inode = 0;
518 98 : int smb_action = 0;
519 98 : struct files_struct *dirfsp = NULL;
520 18 : files_struct *fsp;
521 98 : struct ea_list *ea_list = NULL;
522 98 : uint16_t flags = 0;
523 18 : NTSTATUS status;
524 18 : uint32_t access_mask;
525 18 : uint32_t share_mode;
526 18 : uint32_t create_disposition;
527 98 : uint32_t create_options = 0;
528 98 : uint32_t private_flags = 0;
529 98 : NTTIME twrp = 0;
530 98 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
531 98 : TALLOC_CTX *ctx = talloc_tos();
532 :
533 : /*
534 : * Ensure we have enough parameters to perform the operation.
535 : */
536 :
537 98 : if (total_params < 29) {
538 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
539 0 : goto out;
540 : }
541 :
542 98 : flags = SVAL(params, 0);
543 98 : deny_mode = SVAL(params, 2);
544 98 : open_attr = SVAL(params,6);
545 98 : oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
546 98 : if (oplock_request) {
547 0 : oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
548 : }
549 :
550 : #if 0
551 : return_additional_info = BITSETW(params,0);
552 : open_sattr = SVAL(params, 4);
553 : open_time = make_unix_date3(params+8);
554 : #endif
555 98 : open_ofun = SVAL(params,12);
556 98 : open_size = IVAL(params,14);
557 98 : pname = ¶ms[28];
558 :
559 98 : if (IS_IPC(conn)) {
560 0 : reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
561 0 : goto out;
562 : }
563 :
564 98 : if (req->posix_pathnames) {
565 0 : srvstr_get_path_posix(ctx,
566 : params,
567 0 : req->flags2,
568 : &fname,
569 : pname,
570 0 : total_params - 28,
571 : STR_TERMINATE,
572 : &status);
573 : } else {
574 98 : srvstr_get_path(ctx,
575 : params,
576 98 : req->flags2,
577 : &fname,
578 : pname,
579 98 : total_params - 28,
580 : STR_TERMINATE,
581 : &status);
582 : }
583 98 : if (!NT_STATUS_IS_OK(status)) {
584 0 : reply_nterror(req, status);
585 0 : goto out;
586 : }
587 :
588 98 : DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
589 : fname, (unsigned int)deny_mode, (unsigned int)open_attr,
590 : (unsigned int)open_ofun, open_size));
591 :
592 98 : if (ucf_flags & UCF_GMT_PATHNAME) {
593 0 : extract_snapshot_token(fname, &twrp);
594 : }
595 98 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
596 98 : if (!NT_STATUS_IS_OK(status)) {
597 0 : reply_nterror(req, status);
598 0 : goto out;
599 : }
600 98 : status = filename_convert_dirfsp(ctx,
601 : conn,
602 : fname,
603 : ucf_flags,
604 : twrp,
605 : &dirfsp,
606 : &smb_fname);
607 98 : if (!NT_STATUS_IS_OK(status)) {
608 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
609 0 : reply_botherror(req,
610 : NT_STATUS_PATH_NOT_COVERED,
611 : ERRSRV, ERRbadpath);
612 0 : goto out;
613 : }
614 0 : reply_nterror(req, status);
615 0 : goto out;
616 : }
617 :
618 98 : if (open_ofun == 0) {
619 10 : reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
620 10 : goto out;
621 : }
622 :
623 88 : if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
624 : open_ofun,
625 : &access_mask, &share_mode,
626 : &create_disposition,
627 : &create_options,
628 : &private_flags)) {
629 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
630 0 : goto out;
631 : }
632 :
633 : /* Any data in this call is an EA list. */
634 88 : if (total_data && (total_data != 4)) {
635 88 : if (total_data < 10) {
636 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
637 0 : goto out;
638 : }
639 :
640 88 : if (IVAL(pdata,0) > total_data) {
641 0 : DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
642 : IVAL(pdata,0), (unsigned int)total_data));
643 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
644 0 : goto out;
645 : }
646 :
647 88 : ea_list = read_ea_list(talloc_tos(), pdata + 4,
648 88 : total_data - 4);
649 88 : if (!ea_list) {
650 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
651 0 : goto out;
652 : }
653 :
654 88 : if (!lp_ea_support(SNUM(conn))) {
655 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
656 0 : goto out;
657 : }
658 :
659 176 : if (!req->posix_pathnames &&
660 88 : ea_list_has_invalid_name(ea_list)) {
661 0 : int param_len = 30;
662 0 : *pparams = (char *)SMB_REALLOC(*pparams, param_len);
663 0 : if(*pparams == NULL ) {
664 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
665 0 : goto out;
666 : }
667 0 : params = *pparams;
668 0 : memset(params, '\0', param_len);
669 0 : send_trans2_replies(conn, req, STATUS_INVALID_EA_NAME,
670 : params, param_len, NULL, 0, max_data_bytes);
671 0 : goto out;
672 : }
673 : }
674 :
675 88 : status = SMB_VFS_CREATE_FILE(
676 : conn, /* conn */
677 : req, /* req */
678 : dirfsp, /* dirfsp */
679 : smb_fname, /* fname */
680 : access_mask, /* access_mask */
681 : share_mode, /* share_access */
682 : create_disposition, /* create_disposition*/
683 : create_options, /* create_options */
684 : open_attr, /* file_attributes */
685 : oplock_request, /* oplock_request */
686 : NULL, /* lease */
687 : open_size, /* allocation_size */
688 : private_flags,
689 : NULL, /* sd */
690 : ea_list, /* ea_list */
691 : &fsp, /* result */
692 : &smb_action, /* psbuf */
693 : NULL, NULL); /* create context */
694 :
695 88 : if (!NT_STATUS_IS_OK(status)) {
696 33 : if (open_was_deferred(req->xconn, req->mid)) {
697 : /* We have re-scheduled this call. */
698 0 : goto out;
699 : }
700 :
701 33 : if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
702 23 : reply_openerror(req, status);
703 23 : goto out;
704 : }
705 :
706 10 : fsp = fcb_or_dos_open(
707 : req,
708 : smb_fname,
709 : access_mask,
710 : create_options,
711 : private_flags);
712 10 : if (fsp == NULL) {
713 10 : bool ok = defer_smb1_sharing_violation(req);
714 10 : if (ok) {
715 5 : goto out;
716 : }
717 5 : reply_openerror(req, status);
718 5 : goto out;
719 : }
720 :
721 0 : smb_action = FILE_WAS_OPENED;
722 : }
723 :
724 55 : size = get_file_size_stat(&smb_fname->st);
725 55 : fattr = fdos_mode(fsp);
726 55 : inode = smb_fname->st.st_ex_ino;
727 55 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
728 0 : close_file_free(req, &fsp, ERROR_CLOSE);
729 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
730 0 : goto out;
731 : }
732 :
733 : /* Realloc the size of parameters and data we will return */
734 55 : *pparams = (char *)SMB_REALLOC(*pparams, 30);
735 55 : if(*pparams == NULL ) {
736 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
737 0 : goto out;
738 : }
739 55 : params = *pparams;
740 :
741 55 : SSVAL(params,0,fsp->fnum);
742 55 : SSVAL(params,2,fattr);
743 55 : srv_put_dos_date2_ts(params, 4, smb_fname->st.st_ex_mtime);
744 55 : SIVAL(params,8, (uint32_t)size);
745 55 : SSVAL(params,12,deny_mode);
746 55 : SSVAL(params,14,0); /* open_type - file or directory. */
747 55 : SSVAL(params,16,0); /* open_state - only valid for IPC device. */
748 :
749 55 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
750 0 : smb_action |= EXTENDED_OPLOCK_GRANTED;
751 : }
752 :
753 55 : SSVAL(params,18,smb_action);
754 :
755 : /*
756 : * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
757 : */
758 55 : SIVAL(params,20,inode);
759 55 : SSVAL(params,24,0); /* Padding. */
760 55 : if (flags & 8) {
761 0 : uint32_t ea_size = estimate_ea_size(smb_fname->fsp);
762 0 : SIVAL(params, 26, ea_size);
763 : } else {
764 55 : SIVAL(params, 26, 0);
765 : }
766 :
767 : /* Send the required number of replies */
768 55 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 30, *ppdata, 0, max_data_bytes);
769 98 : out:
770 98 : TALLOC_FREE(smb_fname);
771 98 : }
772 :
773 207176 : static NTSTATUS get_lanman2_dir_entry(TALLOC_CTX *ctx,
774 : connection_struct *conn,
775 : struct dptr_struct *dirptr,
776 : uint16_t flags2,
777 : const char *path_mask,
778 : uint32_t dirtype,
779 : int info_level,
780 : bool requires_resume_key,
781 : bool dont_descend,
782 : bool ask_sharemode,
783 : char **ppdata,
784 : char *base_data,
785 : char *end_data,
786 : int space_remaining,
787 : int *last_entry_off,
788 : struct ea_list *name_list)
789 : {
790 207176 : uint8_t align = 4;
791 207176 : const bool do_pad = true;
792 :
793 207176 : if (info_level >= 1 && info_level <= 3) {
794 : /* No alignment on earlier info levels. */
795 114822 : align = 1;
796 : }
797 :
798 207176 : return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
799 : path_mask, dirtype, info_level,
800 : requires_resume_key, dont_descend, ask_sharemode,
801 : true, align, do_pad,
802 : ppdata, base_data, end_data,
803 : space_remaining,
804 : NULL,
805 : last_entry_off, name_list, NULL);
806 : }
807 :
808 : /****************************************************************************
809 : Reply to a TRANS2_FINDFIRST.
810 : ****************************************************************************/
811 :
812 8736 : static void call_trans2findfirst(connection_struct *conn,
813 : struct smb_request *req,
814 : char **pparams, int total_params,
815 : char **ppdata, int total_data,
816 : unsigned int max_data_bytes)
817 : {
818 : /* We must be careful here that we don't return more than the
819 : allowed number of data bytes. If this means returning fewer than
820 : maxentries then so be it. We assume that the redirector has
821 : enough room for the fixed number of parameter bytes it has
822 : requested. */
823 8736 : struct smb_filename *smb_dname = NULL;
824 8736 : char *params = *pparams;
825 8736 : char *pdata = *ppdata;
826 175 : char *data_end;
827 175 : uint32_t dirtype;
828 175 : int maxentries;
829 175 : uint16_t findfirst_flags;
830 175 : bool close_after_first;
831 175 : bool close_if_end;
832 175 : bool requires_resume_key;
833 175 : int info_level;
834 8736 : char *directory = NULL;
835 8736 : char *mask = NULL;
836 175 : char *p;
837 8736 : int last_entry_off=0;
838 8736 : int dptr_num = -1;
839 8736 : int numentries = 0;
840 175 : int i;
841 8736 : bool finished = False;
842 8736 : bool dont_descend = False;
843 8736 : bool out_of_space = False;
844 175 : int space_remaining;
845 8736 : struct ea_list *ea_list = NULL;
846 8736 : NTSTATUS ntstatus = NT_STATUS_OK;
847 175 : bool ask_sharemode;
848 8736 : struct smbXsrv_connection *xconn = req->xconn;
849 8736 : struct smbd_server_connection *sconn = req->sconn;
850 8736 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
851 8736 : bool backup_priv = false;
852 8736 : bool as_root = false;
853 8736 : files_struct *fsp = NULL;
854 8736 : struct files_struct *dirfsp = NULL;
855 175 : const struct loadparm_substitution *lp_sub =
856 8736 : loadparm_s3_global_substitution();
857 :
858 8736 : if (total_params < 13) {
859 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
860 0 : goto out;
861 : }
862 :
863 8736 : dirtype = SVAL(params,0);
864 8736 : maxentries = SVAL(params,2);
865 8736 : findfirst_flags = SVAL(params,4);
866 8736 : close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
867 8736 : close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
868 8736 : requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
869 8742 : backup_priv = ((findfirst_flags & FLAG_TRANS2_FIND_BACKUP_INTENT) &&
870 6 : security_token_has_privilege(get_current_nttok(conn),
871 : SEC_PRIV_BACKUP));
872 :
873 8736 : info_level = SVAL(params,6);
874 :
875 8736 : DBG_NOTICE("dirtype = %"PRIx32", maxentries = %d, "
876 : "close_after_first=%d, close_if_end = %d "
877 : "requires_resume_key = %d backup_priv = %d level = 0x%x, "
878 : "max_data_bytes = %d\n",
879 : dirtype,
880 : maxentries,
881 : close_after_first,
882 : close_if_end,
883 : requires_resume_key,
884 : backup_priv,
885 : info_level,
886 : max_data_bytes);
887 :
888 8736 : if (!maxentries) {
889 : /* W2K3 seems to treat zero as 1. */
890 12 : maxentries = 1;
891 : }
892 :
893 8736 : switch (info_level) {
894 8545 : case SMB_FIND_INFO_STANDARD:
895 : case SMB_FIND_EA_SIZE:
896 : case SMB_FIND_EA_LIST:
897 : case SMB_FIND_FILE_DIRECTORY_INFO:
898 : case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
899 : case SMB_FIND_FILE_NAMES_INFO:
900 : case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
901 : case SMB_FIND_ID_FULL_DIRECTORY_INFO:
902 : case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
903 8720 : break;
904 16 : case SMB_FIND_FILE_UNIX:
905 : case SMB_FIND_FILE_UNIX_INFO2:
906 16 : if (!lp_smb1_unix_extensions()) {
907 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
908 0 : goto out;
909 : }
910 16 : if (!req->posix_pathnames) {
911 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
912 0 : goto out;
913 : }
914 16 : break;
915 0 : default:
916 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
917 0 : goto out;
918 : }
919 :
920 8736 : if (req->posix_pathnames) {
921 190 : srvstr_get_path_posix(talloc_tos(),
922 : params,
923 190 : req->flags2,
924 : &directory,
925 190 : params+12,
926 190 : total_params - 12,
927 : STR_TERMINATE,
928 : &ntstatus);
929 : } else {
930 8546 : srvstr_get_path(talloc_tos(),
931 : params,
932 8546 : req->flags2,
933 : &directory,
934 8546 : params+12,
935 8546 : total_params - 12,
936 : STR_TERMINATE,
937 : &ntstatus);
938 : }
939 8736 : if (!NT_STATUS_IS_OK(ntstatus)) {
940 0 : reply_nterror(req, ntstatus);
941 0 : goto out;
942 : }
943 :
944 8736 : if (backup_priv) {
945 0 : become_root();
946 0 : as_root = true;
947 : }
948 8736 : ntstatus = smb1_strip_dfs_path(talloc_tos(), &ucf_flags, &directory);
949 8736 : if (!NT_STATUS_IS_OK(ntstatus)) {
950 0 : reply_nterror(req, ntstatus);
951 0 : goto out;
952 : }
953 :
954 8736 : ntstatus = filename_convert_smb1_search_path(talloc_tos(),
955 : conn,
956 : directory,
957 : ucf_flags,
958 : &dirfsp,
959 : &smb_dname,
960 : &mask);
961 :
962 8736 : if (!NT_STATUS_IS_OK(ntstatus)) {
963 114 : if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
964 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
965 : ERRSRV, ERRbadpath);
966 0 : goto out;
967 : }
968 114 : reply_nterror(req, ntstatus);
969 114 : goto out;
970 : }
971 :
972 8622 : TALLOC_FREE(directory);
973 8622 : directory = smb_dname->base_name;
974 :
975 8622 : DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
976 :
977 8622 : if (info_level == SMB_FIND_EA_LIST) {
978 0 : uint32_t ea_size;
979 :
980 6 : if (total_data < 4) {
981 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
982 0 : goto out;
983 : }
984 :
985 6 : ea_size = IVAL(pdata,0);
986 6 : if (ea_size != total_data) {
987 0 : DBG_NOTICE("Rejecting EA request with incorrect "
988 : "total_data=%d (should be %" PRIu32 ")\n",
989 : total_data,
990 : ea_size);
991 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
992 0 : goto out;
993 : }
994 :
995 6 : if (!lp_ea_support(SNUM(conn))) {
996 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
997 0 : goto out;
998 : }
999 :
1000 : /* Pull out the list of names. */
1001 6 : ea_list = read_ea_name_list(talloc_tos(), pdata + 4, ea_size - 4);
1002 6 : if (!ea_list) {
1003 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1004 0 : goto out;
1005 : }
1006 : }
1007 :
1008 8622 : if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
1009 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1010 0 : goto out;
1011 : }
1012 :
1013 8622 : *ppdata = (char *)SMB_REALLOC(
1014 : *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
1015 8622 : if(*ppdata == NULL ) {
1016 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1017 0 : goto out;
1018 : }
1019 8622 : pdata = *ppdata;
1020 8622 : data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
1021 : /*
1022 : * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
1023 : * error.
1024 : */
1025 8622 : memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data));
1026 : /* Realloc the params space */
1027 8622 : *pparams = (char *)SMB_REALLOC(*pparams, 10);
1028 8622 : if (*pparams == NULL) {
1029 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1030 0 : goto out;
1031 : }
1032 8622 : params = *pparams;
1033 :
1034 : /*
1035 : * Open an fsp on this directory for the dptr.
1036 : */
1037 8622 : ntstatus = SMB_VFS_CREATE_FILE(
1038 : conn, /* conn */
1039 : req, /* req */
1040 : dirfsp, /* dirfsp */
1041 : smb_dname, /* dname */
1042 : FILE_LIST_DIRECTORY, /* access_mask */
1043 : FILE_SHARE_READ|
1044 : FILE_SHARE_WRITE, /* share_access */
1045 : FILE_OPEN, /* create_disposition*/
1046 : FILE_DIRECTORY_FILE, /* create_options */
1047 : FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
1048 : NO_OPLOCK, /* oplock_request */
1049 : NULL, /* lease */
1050 : 0, /* allocation_size */
1051 : 0, /* private_flags */
1052 : NULL, /* sd */
1053 : NULL, /* ea_list */
1054 : &fsp, /* result */
1055 : NULL, /* pinfo */
1056 : NULL, /* in_context */
1057 : NULL);/* out_context */
1058 :
1059 8622 : if (!NT_STATUS_IS_OK(ntstatus)) {
1060 119 : DBG_ERR("failed to open directory %s\n",
1061 : smb_fname_str_dbg(smb_dname));
1062 119 : reply_nterror(req, ntstatus);
1063 119 : goto out;
1064 : }
1065 :
1066 : /* Save the wildcard match and attribs we are using on this directory -
1067 : needed as lanman2 assumes these are being saved between calls */
1068 :
1069 8503 : ntstatus = dptr_create(conn,
1070 : req,
1071 : fsp, /* fsp */
1072 : False,
1073 : mask,
1074 : dirtype,
1075 8503 : &fsp->dptr);
1076 :
1077 8503 : if (!NT_STATUS_IS_OK(ntstatus)) {
1078 : /*
1079 : * Use NULL here for the first parameter (req)
1080 : * as this is not a client visible handle so
1081 : * can't be part of an SMB1 chain.
1082 : */
1083 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1084 0 : reply_nterror(req, ntstatus);
1085 0 : goto out;
1086 : }
1087 :
1088 8503 : if (backup_priv) {
1089 : /* Remember this in case we have
1090 : to do a findnext. */
1091 0 : dptr_set_priv(fsp->dptr);
1092 : }
1093 :
1094 8503 : dptr_num = dptr_dnum(fsp->dptr);
1095 8503 : DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
1096 :
1097 : /* We don't need to check for VOL here as this is returned by
1098 : a different TRANS2 call. */
1099 :
1100 8503 : DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1101 : directory,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn))));
1102 8503 : if (in_list(directory,
1103 8503 : lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
1104 8503 : dptr_case_sensitive(fsp->dptr))) {
1105 0 : dont_descend = True;
1106 : }
1107 :
1108 8503 : p = pdata;
1109 8503 : space_remaining = max_data_bytes;
1110 8503 : out_of_space = False;
1111 :
1112 8503 : ask_sharemode = fsp_search_ask_sharemode(fsp);
1113 :
1114 58075 : for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
1115 :
1116 49398 : ntstatus = get_lanman2_dir_entry(talloc_tos(),
1117 : conn,
1118 49398 : fsp->dptr,
1119 49398 : req->flags2,
1120 : mask,
1121 : dirtype,
1122 : info_level,
1123 : requires_resume_key,
1124 : dont_descend,
1125 : ask_sharemode,
1126 : &p,
1127 : pdata,
1128 : data_end,
1129 : space_remaining,
1130 : &last_entry_off,
1131 : ea_list);
1132 49398 : if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_ILLEGAL_CHARACTER)) {
1133 : /*
1134 : * Bad character conversion on name. Ignore
1135 : * this entry.
1136 : */
1137 12 : continue;
1138 : }
1139 49386 : if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
1140 0 : out_of_space = true;
1141 : } else {
1142 49386 : finished = !NT_STATUS_IS_OK(ntstatus);
1143 : }
1144 :
1145 49386 : if (!finished && !out_of_space) {
1146 41510 : numentries++;
1147 : }
1148 :
1149 : /* Ensure space_remaining never goes -ve. */
1150 49386 : if (PTR_DIFF(p,pdata) > max_data_bytes) {
1151 0 : space_remaining = 0;
1152 0 : out_of_space = true;
1153 : } else {
1154 49386 : space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
1155 : }
1156 : }
1157 :
1158 : /* Check if we can close the dirptr */
1159 8503 : if(close_after_first || (finished && close_if_end)) {
1160 8369 : DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
1161 8369 : dptr_num = -1;
1162 8369 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1163 : }
1164 :
1165 : /*
1166 : * If there are no matching entries we must return ERRDOS/ERRbadfile -
1167 : * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
1168 : * the protocol level is less than NT1. Tested with smbclient. JRA.
1169 : * This should fix the OS/2 client bug #2335.
1170 : */
1171 :
1172 8503 : if(numentries == 0) {
1173 541 : dptr_num = -1;
1174 : /*
1175 : * We may have already closed the file in the
1176 : * close_after_first or finished case above.
1177 : */
1178 541 : if (fsp != NULL) {
1179 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1180 : }
1181 541 : if (xconn->protocol < PROTOCOL_NT1) {
1182 0 : reply_force_doserror(req, ERRDOS, ERRnofiles);
1183 0 : goto out;
1184 : } else {
1185 541 : reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
1186 : ERRDOS, ERRbadfile);
1187 541 : goto out;
1188 : }
1189 : }
1190 :
1191 : /* At this point pdata points to numentries directory entries. */
1192 :
1193 : /* Set up the return parameter block */
1194 7962 : SSVAL(params,0,dptr_num);
1195 7962 : SSVAL(params,2,numentries);
1196 7962 : SSVAL(params,4,finished);
1197 7962 : SSVAL(params,6,0); /* Never an EA error */
1198 7962 : SSVAL(params,8,last_entry_off);
1199 :
1200 7962 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
1201 : max_data_bytes);
1202 :
1203 7962 : if ((! *directory) && dptr_path(sconn, dptr_num)) {
1204 0 : directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num));
1205 0 : if (!directory) {
1206 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1207 : }
1208 : }
1209 :
1210 7962 : DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
1211 : smb_fn_name(req->cmd),
1212 : mask, directory, dirtype, numentries ) );
1213 :
1214 : /*
1215 : * Force a name mangle here to ensure that the
1216 : * mask as an 8.3 name is top of the mangled cache.
1217 : * The reasons for this are subtle. Don't remove
1218 : * this code unless you know what you are doing
1219 : * (see PR#13758). JRA.
1220 : */
1221 :
1222 7962 : if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
1223 153 : char mangled_name[13];
1224 7824 : name_to_8_3(mask, mangled_name, True, conn->params);
1225 : }
1226 138 : out:
1227 :
1228 8736 : if (as_root) {
1229 0 : unbecome_root();
1230 : }
1231 :
1232 8736 : TALLOC_FREE(smb_dname);
1233 8736 : return;
1234 : }
1235 :
1236 368918 : static bool smbd_dptr_name_equal(struct dptr_struct *dptr,
1237 : const char *name1,
1238 : const char *name2)
1239 : {
1240 0 : bool equal;
1241 :
1242 368918 : if (dptr_case_sensitive(dptr)) {
1243 0 : equal = (strcmp(name1, name2) == 0);
1244 : } else {
1245 368918 : equal = strequal(name1, name2);
1246 : }
1247 :
1248 368918 : return equal;
1249 : }
1250 :
1251 : /****************************************************************************
1252 : Reply to a TRANS2_FINDNEXT.
1253 : ****************************************************************************/
1254 :
1255 1724 : static void call_trans2findnext(connection_struct *conn,
1256 : struct smb_request *req,
1257 : char **pparams, int total_params,
1258 : char **ppdata, int total_data,
1259 : unsigned int max_data_bytes)
1260 : {
1261 : /* We must be careful here that we don't return more than the
1262 : allowed number of data bytes. If this means returning fewer than
1263 : maxentries then so be it. We assume that the redirector has
1264 : enough room for the fixed number of parameter bytes it has
1265 : requested. */
1266 1724 : char *params = *pparams;
1267 1724 : char *pdata = *ppdata;
1268 0 : char *data_end;
1269 0 : int dptr_num;
1270 0 : int maxentries;
1271 0 : uint16_t info_level;
1272 0 : uint32_t resume_key;
1273 0 : uint16_t findnext_flags;
1274 0 : bool close_after_request;
1275 0 : bool close_if_end;
1276 0 : bool requires_resume_key;
1277 0 : bool continue_bit;
1278 1724 : char *resume_name = NULL;
1279 1724 : const char *mask = NULL;
1280 1724 : const char *directory = NULL;
1281 1724 : char *p = NULL;
1282 0 : uint16_t dirtype;
1283 1724 : int numentries = 0;
1284 1724 : int i, last_entry_off=0;
1285 1724 : bool finished = False;
1286 1724 : bool dont_descend = False;
1287 1724 : bool out_of_space = False;
1288 0 : int space_remaining;
1289 1724 : struct ea_list *ea_list = NULL;
1290 1724 : NTSTATUS ntstatus = NT_STATUS_OK;
1291 0 : bool ask_sharemode;
1292 1724 : TALLOC_CTX *ctx = talloc_tos();
1293 1724 : struct smbd_server_connection *sconn = req->sconn;
1294 1724 : bool backup_priv = false;
1295 1724 : bool as_root = false;
1296 1724 : files_struct *fsp = NULL;
1297 0 : const struct loadparm_substitution *lp_sub =
1298 1724 : loadparm_s3_global_substitution();
1299 :
1300 1724 : if (total_params < 13) {
1301 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1302 0 : return;
1303 : }
1304 :
1305 1724 : dptr_num = SVAL(params,0);
1306 1724 : maxentries = SVAL(params,2);
1307 1724 : info_level = SVAL(params,4);
1308 1724 : resume_key = IVAL(params,6);
1309 1724 : findnext_flags = SVAL(params,10);
1310 1724 : close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
1311 1724 : close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
1312 1724 : requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
1313 1724 : continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
1314 :
1315 1724 : if (!continue_bit) {
1316 : /* We only need resume_name if continue_bit is zero. */
1317 1424 : if (req->posix_pathnames) {
1318 0 : srvstr_get_path_posix(ctx,
1319 : params,
1320 0 : req->flags2,
1321 : &resume_name,
1322 0 : params+12,
1323 0 : total_params - 12,
1324 : STR_TERMINATE,
1325 : &ntstatus);
1326 : } else {
1327 1424 : srvstr_get_path(ctx,
1328 : params,
1329 1424 : req->flags2,
1330 : &resume_name,
1331 1424 : params+12,
1332 1424 : total_params - 12,
1333 : STR_TERMINATE,
1334 : &ntstatus);
1335 : }
1336 1424 : if (!NT_STATUS_IS_OK(ntstatus)) {
1337 : /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
1338 : complain (it thinks we're asking for the directory above the shared
1339 : path or an invalid name). Catch this as the resume name is only compared, never used in
1340 : a file access. JRA. */
1341 0 : srvstr_pull_talloc(ctx, params, req->flags2,
1342 : &resume_name, params+12,
1343 : total_params - 12,
1344 : STR_TERMINATE);
1345 :
1346 0 : if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
1347 0 : reply_nterror(req, ntstatus);
1348 0 : return;
1349 : }
1350 : }
1351 : }
1352 :
1353 1724 : DBG_NOTICE("dirhandle = %d, max_data_bytes = %u, maxentries = %d, "
1354 : "close_after_request=%d, close_if_end = %d "
1355 : "requires_resume_key = %d resume_key = %d "
1356 : "resume name = %s continue=%d level = %d\n",
1357 : dptr_num,
1358 : max_data_bytes,
1359 : maxentries,
1360 : close_after_request,
1361 : close_if_end,
1362 : requires_resume_key,
1363 : resume_key,
1364 : resume_name ? resume_name : "(NULL)",
1365 : continue_bit,
1366 : info_level);
1367 :
1368 1724 : if (!maxentries) {
1369 : /* W2K3 seems to treat zero as 1. */
1370 0 : maxentries = 1;
1371 : }
1372 :
1373 1724 : switch (info_level) {
1374 1724 : case SMB_FIND_INFO_STANDARD:
1375 : case SMB_FIND_EA_SIZE:
1376 : case SMB_FIND_EA_LIST:
1377 : case SMB_FIND_FILE_DIRECTORY_INFO:
1378 : case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1379 : case SMB_FIND_FILE_NAMES_INFO:
1380 : case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1381 : case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1382 : case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1383 1724 : break;
1384 0 : case SMB_FIND_FILE_UNIX:
1385 : case SMB_FIND_FILE_UNIX_INFO2:
1386 0 : if (!lp_smb1_unix_extensions()) {
1387 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1388 0 : return;
1389 : }
1390 0 : if (!req->posix_pathnames) {
1391 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1392 0 : return;
1393 : }
1394 0 : break;
1395 0 : default:
1396 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1397 0 : return;
1398 : }
1399 :
1400 1724 : if (info_level == SMB_FIND_EA_LIST) {
1401 0 : uint32_t ea_size;
1402 :
1403 6 : if (total_data < 4) {
1404 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1405 0 : return;
1406 : }
1407 :
1408 6 : ea_size = IVAL(pdata,0);
1409 6 : if (ea_size != total_data) {
1410 0 : DBG_NOTICE("Rejecting EA request with incorrect "
1411 : "total_data=%d (should be %" PRIu32 ")\n",
1412 : total_data,
1413 : ea_size);
1414 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1415 0 : return;
1416 : }
1417 :
1418 6 : if (!lp_ea_support(SNUM(conn))) {
1419 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1420 0 : return;
1421 : }
1422 :
1423 : /* Pull out the list of names. */
1424 6 : ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
1425 6 : if (!ea_list) {
1426 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1427 0 : return;
1428 : }
1429 : }
1430 :
1431 1724 : if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
1432 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1433 0 : return;
1434 : }
1435 :
1436 1724 : *ppdata = (char *)SMB_REALLOC(
1437 : *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
1438 1724 : if(*ppdata == NULL) {
1439 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1440 0 : return;
1441 : }
1442 :
1443 1724 : pdata = *ppdata;
1444 1724 : data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
1445 :
1446 : /*
1447 : * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
1448 : * error.
1449 : */
1450 1724 : memset(pdata + total_data, 0, (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data);
1451 : /* Realloc the params space */
1452 1724 : *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
1453 1724 : if(*pparams == NULL ) {
1454 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1455 0 : return;
1456 : }
1457 :
1458 1724 : params = *pparams;
1459 :
1460 : /* Check that the dptr is valid */
1461 1724 : fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
1462 1724 : if (fsp == NULL) {
1463 0 : reply_nterror(req, STATUS_NO_MORE_FILES);
1464 0 : return;
1465 : }
1466 :
1467 1724 : directory = dptr_path(sconn, dptr_num);
1468 :
1469 : /* Get the wildcard mask from the dptr */
1470 1724 : if((mask = dptr_wcard(sconn, dptr_num))== NULL) {
1471 0 : DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
1472 0 : reply_nterror(req, STATUS_NO_MORE_FILES);
1473 0 : return;
1474 : }
1475 :
1476 : /* Get the attr mask from the dptr */
1477 1724 : dirtype = dptr_attr(sconn, dptr_num);
1478 :
1479 1724 : backup_priv = dptr_get_priv(fsp->dptr);
1480 :
1481 1724 : DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX) "
1482 : "backup_priv = %d\n",
1483 : dptr_num, mask, dirtype,
1484 : (long)fsp->dptr,
1485 : (int)backup_priv));
1486 :
1487 : /* We don't need to check for VOL here as this is returned by
1488 : a different TRANS2 call. */
1489 :
1490 1724 : DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1491 : directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
1492 1724 : if (in_list(directory,lp_dont_descend(ctx, lp_sub, SNUM(conn)),
1493 1724 : dptr_case_sensitive(fsp->dptr)))
1494 0 : dont_descend = True;
1495 :
1496 1724 : p = pdata;
1497 1724 : space_remaining = max_data_bytes;
1498 1724 : out_of_space = False;
1499 :
1500 1724 : if (backup_priv) {
1501 0 : become_root();
1502 0 : as_root = true;
1503 : }
1504 :
1505 : /*
1506 : * Seek to the correct position. We no longer use the resume key but
1507 : * depend on the last file name instead.
1508 : */
1509 :
1510 1724 : if(!continue_bit && resume_name && *resume_name) {
1511 1424 : bool posix_open = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN);
1512 1424 : char *last_name_sent = NULL;
1513 0 : bool sequential;
1514 :
1515 : /*
1516 : * Remember, name_to_8_3 is called by
1517 : * get_lanman2_dir_entry(), so the resume name
1518 : * could be mangled. Ensure we check the unmangled name.
1519 : */
1520 :
1521 2848 : if (!posix_open &&
1522 1424 : mangle_is_mangled(resume_name, conn->params)) {
1523 0 : char *new_resume_name = NULL;
1524 0 : mangle_lookup_name_from_8_3(ctx,
1525 : resume_name,
1526 : &new_resume_name,
1527 0 : conn->params);
1528 0 : if (new_resume_name) {
1529 0 : resume_name = new_resume_name;
1530 : }
1531 : }
1532 :
1533 : /*
1534 : * Fix for NT redirector problem triggered by resume key indexes
1535 : * changing between directory scans. We now return a resume key of 0
1536 : * and instead look for the filename to continue from (also given
1537 : * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
1538 : * findfirst/findnext (as is usual) then the directory pointer
1539 : * should already be at the correct place.
1540 : */
1541 :
1542 1424 : last_name_sent = smbd_dirptr_get_last_name_sent(fsp->dptr);
1543 1424 : sequential = smbd_dptr_name_equal(fsp->dptr,
1544 : resume_name,
1545 : last_name_sent);
1546 1424 : if (!sequential) {
1547 1050 : char *name = NULL;
1548 1050 : bool found = false;
1549 :
1550 1050 : dptr_RewindDir(fsp->dptr);
1551 :
1552 369588 : while ((name = dptr_ReadDirName(talloc_tos(),
1553 737076 : fsp->dptr)) != NULL) {
1554 367494 : found = smbd_dptr_name_equal(fsp->dptr,
1555 : resume_name,
1556 : name);
1557 367494 : TALLOC_FREE(name);
1558 367494 : if (found) {
1559 6 : break;
1560 : }
1561 : }
1562 :
1563 1050 : if (!found) {
1564 : /*
1565 : * We got a name that used to exist
1566 : * but does not anymore. Just start
1567 : * from the beginning. Shown by the
1568 : * "raw.search.os2 delete" smbtorture
1569 : * test.
1570 : */
1571 1044 : dptr_RewindDir(fsp->dptr);
1572 : }
1573 : }
1574 : } /* end if resume_name && !continue_bit */
1575 :
1576 1724 : ask_sharemode = fsp_search_ask_sharemode(fsp);
1577 :
1578 159502 : for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
1579 :
1580 157778 : ntstatus = get_lanman2_dir_entry(ctx,
1581 : conn,
1582 157778 : fsp->dptr,
1583 157778 : req->flags2,
1584 : mask,
1585 : dirtype,
1586 : info_level,
1587 : requires_resume_key,
1588 : dont_descend,
1589 : ask_sharemode,
1590 : &p,
1591 : pdata,
1592 : data_end,
1593 : space_remaining,
1594 : &last_entry_off,
1595 : ea_list);
1596 157778 : if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_ILLEGAL_CHARACTER)) {
1597 : /*
1598 : * Bad character conversion on name. Ignore
1599 : * this entry.
1600 : */
1601 0 : continue;
1602 : }
1603 157778 : if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
1604 0 : out_of_space = true;
1605 : } else {
1606 157778 : finished = !NT_STATUS_IS_OK(ntstatus);
1607 : }
1608 :
1609 157778 : if (!finished && !out_of_space) {
1610 157506 : numentries++;
1611 : }
1612 :
1613 157778 : space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
1614 : }
1615 :
1616 1724 : DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
1617 : smb_fn_name(req->cmd),
1618 : mask, directory, dirtype, numentries ) );
1619 :
1620 : /* Check if we can close the fsp->dptr */
1621 1724 : if(close_after_request || (finished && close_if_end)) {
1622 110 : DBG_INFO("closing dptr_num = %d\n", dptr_num);
1623 110 : dptr_num = -1;
1624 110 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1625 : }
1626 :
1627 1724 : if (as_root) {
1628 0 : unbecome_root();
1629 : }
1630 :
1631 : /* Set up the return parameter block */
1632 1724 : SSVAL(params,0,numentries);
1633 1724 : SSVAL(params,2,finished);
1634 1724 : SSVAL(params,4,0); /* Never an EA error */
1635 1724 : SSVAL(params,6,last_entry_off);
1636 :
1637 1724 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 8, pdata, PTR_DIFF(p,pdata),
1638 : max_data_bytes);
1639 :
1640 1724 : return;
1641 : }
1642 :
1643 : /****************************************************************************
1644 : Reply to a TRANS2_QFSINFO (query filesystem info).
1645 : ****************************************************************************/
1646 :
1647 1375 : static void call_trans2qfsinfo(connection_struct *conn,
1648 : struct smb_request *req,
1649 : char **pparams, int total_params,
1650 : char **ppdata, int total_data,
1651 : unsigned int max_data_bytes)
1652 : {
1653 1375 : char *params = *pparams;
1654 0 : uint16_t info_level;
1655 1375 : int data_len = 0;
1656 0 : size_t fixed_portion;
1657 0 : NTSTATUS status;
1658 :
1659 1375 : if (total_params < 2) {
1660 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1661 0 : return;
1662 : }
1663 :
1664 1375 : info_level = SVAL(params,0);
1665 :
1666 1375 : if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
1667 0 : if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
1668 0 : DEBUG(0,("call_trans2qfsinfo: encryption required "
1669 : "and info level 0x%x sent.\n",
1670 : (unsigned int)info_level));
1671 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1672 0 : return;
1673 : }
1674 : }
1675 :
1676 1375 : DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
1677 :
1678 1375 : status = smbd_do_qfsinfo(req->xconn, conn, req,
1679 : info_level,
1680 1375 : req->flags2,
1681 : max_data_bytes,
1682 : &fixed_portion,
1683 : NULL,
1684 : NULL,
1685 : ppdata, &data_len);
1686 1375 : if (!NT_STATUS_IS_OK(status)) {
1687 0 : reply_nterror(req, status);
1688 0 : return;
1689 : }
1690 :
1691 1375 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
1692 : max_data_bytes);
1693 :
1694 1375 : DEBUG( 4, ( "%s info_level = %d\n",
1695 : smb_fn_name(req->cmd), info_level) );
1696 :
1697 1375 : return;
1698 : }
1699 :
1700 : /****************************************************************************
1701 : Reply to a TRANS2_SETFSINFO (set filesystem info).
1702 : ****************************************************************************/
1703 :
1704 1366 : static void call_trans2setfsinfo(connection_struct *conn,
1705 : struct smb_request *req,
1706 : char **pparams, int total_params,
1707 : char **ppdata, int total_data,
1708 : unsigned int max_data_bytes)
1709 : {
1710 0 : const struct loadparm_substitution *lp_sub =
1711 1366 : loadparm_s3_global_substitution();
1712 1366 : struct smbXsrv_connection *xconn = req->xconn;
1713 1366 : char *pdata = *ppdata;
1714 1366 : char *params = *pparams;
1715 0 : uint16_t info_level;
1716 :
1717 1366 : DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
1718 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1719 :
1720 : /* */
1721 1366 : if (total_params < 4) {
1722 0 : DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
1723 : total_params));
1724 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1725 0 : return;
1726 : }
1727 :
1728 1366 : info_level = SVAL(params,2);
1729 :
1730 1366 : if (IS_IPC(conn)) {
1731 480 : if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
1732 0 : info_level != SMB_SET_CIFS_UNIX_INFO) {
1733 0 : DEBUG(0,("call_trans2setfsinfo: not an allowed "
1734 : "info level (0x%x) on IPC$.\n",
1735 : (unsigned int)info_level));
1736 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1737 0 : return;
1738 : }
1739 : }
1740 :
1741 1366 : if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
1742 0 : if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
1743 0 : DEBUG(0,("call_trans2setfsinfo: encryption required "
1744 : "and info level 0x%x sent.\n",
1745 : (unsigned int)info_level));
1746 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1747 0 : return;
1748 : }
1749 : }
1750 :
1751 1366 : switch(info_level) {
1752 478 : case SMB_SET_CIFS_UNIX_INFO:
1753 478 : if (!lp_smb1_unix_extensions()) {
1754 0 : DEBUG(2,("call_trans2setfsinfo: "
1755 : "SMB_SET_CIFS_UNIX_INFO is invalid with "
1756 : "unix extensions off\n"));
1757 0 : reply_nterror(req,
1758 : NT_STATUS_INVALID_LEVEL);
1759 0 : return;
1760 : }
1761 :
1762 : /* There should be 12 bytes of capabilities set. */
1763 478 : if (total_data < 12) {
1764 0 : reply_nterror(
1765 : req,
1766 : NT_STATUS_INVALID_PARAMETER);
1767 0 : return;
1768 : }
1769 478 : xconn->smb1.unix_info.client_major = SVAL(pdata,0);
1770 478 : xconn->smb1.unix_info.client_minor = SVAL(pdata,2);
1771 478 : xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
1772 478 : xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
1773 :
1774 : /* Just print these values for now. */
1775 478 : DBG_DEBUG("set unix_info info. "
1776 : "major = %"PRIu16", minor = %"PRIu16
1777 : "cap_low = 0x%"PRIx32", "
1778 : "cap_high = 0x%"PRIx32"\n",
1779 : xconn->smb1.unix_info.client_major,
1780 : xconn->smb1.unix_info.client_minor,
1781 : xconn->smb1.unix_info.client_cap_low,
1782 : xconn->smb1.unix_info.client_cap_high);
1783 :
1784 : /*
1785 : * Here is where we must switch to posix
1786 : * pathname processing...
1787 : */
1788 478 : if (xconn->smb1.unix_info.client_cap_low &
1789 : CIFS_UNIX_POSIX_PATHNAMES_CAP)
1790 : {
1791 478 : lp_set_posix_pathnames();
1792 478 : mangle_change_to_posix();
1793 : }
1794 :
1795 478 : if ((xconn->smb1.unix_info.client_cap_low &
1796 478 : CIFS_UNIX_FCNTL_LOCKS_CAP) &&
1797 478 : !(xconn->smb1.unix_info.client_cap_low &
1798 : CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP))
1799 : {
1800 : /* Client that knows how to do posix locks,
1801 : * but not posix open/mkdir operations. Set a
1802 : * default type for read/write checks. */
1803 :
1804 0 : lp_set_posix_default_cifsx_readwrite_locktype(
1805 : POSIX_LOCK);
1806 :
1807 : }
1808 478 : break;
1809 :
1810 888 : case SMB_REQUEST_TRANSPORT_ENCRYPTION:
1811 : {
1812 0 : NTSTATUS status;
1813 888 : size_t param_len = 0;
1814 888 : size_t data_len = total_data;
1815 :
1816 888 : if (!lp_smb1_unix_extensions()) {
1817 0 : reply_nterror(
1818 : req,
1819 : NT_STATUS_INVALID_LEVEL);
1820 0 : return;
1821 : }
1822 :
1823 888 : if (lp_server_smb_encrypt(SNUM(conn)) ==
1824 : SMB_ENCRYPTION_OFF) {
1825 0 : reply_nterror(
1826 : req,
1827 : NT_STATUS_NOT_SUPPORTED);
1828 0 : return;
1829 : }
1830 :
1831 888 : if (xconn->smb1.echo_handler.trusted_fde) {
1832 0 : DEBUG( 2,("call_trans2setfsinfo: "
1833 : "request transport encryption disabled"
1834 : "with 'fork echo handler = yes'\n"));
1835 0 : reply_nterror(
1836 : req,
1837 : NT_STATUS_NOT_SUPPORTED);
1838 0 : return;
1839 : }
1840 :
1841 888 : DEBUG( 4,("call_trans2setfsinfo: "
1842 : "request transport encryption.\n"));
1843 :
1844 888 : status = srv_request_encryption_setup(conn,
1845 : (unsigned char **)ppdata,
1846 : &data_len,
1847 : (unsigned char **)pparams,
1848 : ¶m_len);
1849 :
1850 888 : if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
1851 444 : !NT_STATUS_IS_OK(status)) {
1852 0 : reply_nterror(req, status);
1853 0 : return;
1854 : }
1855 :
1856 888 : send_trans2_replies(conn, req,
1857 888 : NT_STATUS_OK,
1858 : *pparams,
1859 : param_len,
1860 : *ppdata,
1861 : data_len,
1862 : max_data_bytes);
1863 :
1864 888 : if (NT_STATUS_IS_OK(status)) {
1865 : /* Server-side transport
1866 : * encryption is now *on*. */
1867 444 : status = srv_encryption_start(conn);
1868 444 : if (!NT_STATUS_IS_OK(status)) {
1869 0 : char *reason = talloc_asprintf(talloc_tos(),
1870 : "Failure in setting "
1871 : "up encrypted transport: %s",
1872 : nt_errstr(status));
1873 0 : exit_server_cleanly(reason);
1874 : }
1875 : }
1876 888 : return;
1877 : }
1878 :
1879 0 : case SMB_FS_QUOTA_INFORMATION:
1880 : {
1881 0 : NTSTATUS status;
1882 0 : DATA_BLOB qdata = {
1883 : .data = (uint8_t *)pdata,
1884 : .length = total_data
1885 : };
1886 0 : files_struct *fsp = NULL;
1887 0 : fsp = file_fsp(req, SVAL(params,0));
1888 :
1889 0 : status = smb_set_fsquota(conn,
1890 : req,
1891 : fsp,
1892 : &qdata);
1893 0 : if (!NT_STATUS_IS_OK(status)) {
1894 0 : reply_nterror(req, status);
1895 0 : return;
1896 : }
1897 0 : break;
1898 : }
1899 0 : default:
1900 0 : DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
1901 : info_level));
1902 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1903 0 : return;
1904 0 : break;
1905 : }
1906 :
1907 : /*
1908 : * sending this reply works fine,
1909 : * but I'm not sure it's the same
1910 : * like windows do...
1911 : * --metze
1912 : */
1913 478 : reply_smb1_outbuf(req, 10, 0);
1914 : }
1915 :
1916 : /****************************************************************************
1917 : Reply to a TRANSACT2_QFILEINFO on a PIPE !
1918 : ****************************************************************************/
1919 :
1920 0 : static void call_trans2qpipeinfo(connection_struct *conn,
1921 : struct smb_request *req,
1922 : files_struct *fsp,
1923 : uint16_t info_level,
1924 : unsigned int tran_call,
1925 : char **pparams, int total_params,
1926 : char **ppdata, int total_data,
1927 : unsigned int max_data_bytes)
1928 : {
1929 0 : char *params = *pparams;
1930 0 : char *pdata = *ppdata;
1931 0 : unsigned int data_size = 0;
1932 0 : unsigned int param_size = 2;
1933 :
1934 0 : if (!fsp_is_np(fsp)) {
1935 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1936 0 : return;
1937 : }
1938 :
1939 0 : *pparams = (char *)SMB_REALLOC(*pparams,2);
1940 0 : if (*pparams == NULL) {
1941 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1942 0 : return;
1943 : }
1944 0 : params = *pparams;
1945 0 : SSVAL(params,0,0);
1946 0 : if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
1947 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1948 0 : return;
1949 : }
1950 0 : data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
1951 0 : *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
1952 0 : if (*ppdata == NULL ) {
1953 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1954 0 : return;
1955 : }
1956 0 : pdata = *ppdata;
1957 :
1958 0 : switch (info_level) {
1959 0 : case SMB_FILE_STANDARD_INFORMATION:
1960 0 : memset(pdata,0,24);
1961 0 : SOFF_T(pdata,0,4096LL);
1962 0 : SIVAL(pdata,16,1);
1963 0 : SIVAL(pdata,20,1);
1964 0 : data_size = 24;
1965 0 : break;
1966 :
1967 0 : default:
1968 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1969 0 : return;
1970 : }
1971 :
1972 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
1973 : max_data_bytes);
1974 : }
1975 :
1976 12299 : static void handle_trans2qfilepathinfo_result(
1977 : connection_struct *conn,
1978 : struct smb_request *req,
1979 : uint16_t info_level,
1980 : NTSTATUS status,
1981 : char *pdata,
1982 : int data_return_size,
1983 : size_t fixed_portion,
1984 : unsigned int max_data_bytes)
1985 : {
1986 12299 : char params[2] = { 0, 0, };
1987 12299 : int param_size = 2;
1988 :
1989 : /*
1990 : * draft-leach-cifs-v1-spec-02.txt
1991 : * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
1992 : * says:
1993 : *
1994 : * The requested information is placed in the Data portion of the
1995 : * transaction response. For the information levels greater than 0x100,
1996 : * the transaction response has 1 parameter word which should be
1997 : * ignored by the client.
1998 : *
1999 : * However Windows only follows this rule for the IS_NAME_VALID call.
2000 : */
2001 12299 : switch (info_level) {
2002 8 : case SMB_INFO_IS_NAME_VALID:
2003 8 : param_size = 0;
2004 8 : break;
2005 : }
2006 :
2007 12299 : if (!NT_STATUS_IS_OK(status)) {
2008 60 : if (open_was_deferred(req->xconn, req->mid)) {
2009 : /* We have re-scheduled this call. */
2010 60 : return;
2011 : }
2012 56 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2013 0 : bool ok = defer_smb1_sharing_violation(req);
2014 0 : if (ok) {
2015 0 : return;
2016 : }
2017 : }
2018 56 : reply_nterror(req, status);
2019 56 : return;
2020 : }
2021 :
2022 12239 : if (fixed_portion > max_data_bytes) {
2023 0 : reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
2024 0 : return;
2025 : }
2026 :
2027 12239 : send_trans2_replies(
2028 : conn,
2029 : req,
2030 12239 : NT_STATUS_OK,
2031 : params,
2032 : param_size,
2033 : pdata,
2034 : data_return_size,
2035 : max_data_bytes);
2036 : }
2037 :
2038 : /****************************************************************************
2039 : Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
2040 : file name or file id).
2041 : ****************************************************************************/
2042 :
2043 12061 : static void call_trans2qfilepathinfo(connection_struct *conn,
2044 : struct smb_request *req,
2045 : unsigned int tran_call,
2046 : uint16_t info_level,
2047 : struct smb_filename *smb_fname,
2048 : struct files_struct *fsp,
2049 : bool delete_pending,
2050 : struct timespec write_time_ts,
2051 : char **pparams, int total_params,
2052 : char **ppdata, int total_data,
2053 : unsigned int max_data_bytes)
2054 : {
2055 12061 : char *params = *pparams;
2056 12061 : char *pdata = *ppdata;
2057 12061 : unsigned int data_size = 0;
2058 12061 : struct ea_list *ea_list = NULL;
2059 449 : size_t fixed_portion;
2060 12061 : NTSTATUS status = NT_STATUS_OK;
2061 :
2062 12061 : DEBUG(3,("call_trans2qfilepathinfo %s (%s) level=%d call=%d "
2063 : "total_data=%d\n", smb_fname_str_dbg(smb_fname),
2064 : fsp_fnum_dbg(fsp),
2065 : info_level,tran_call,total_data));
2066 :
2067 : /* Pull out any data sent here before we realloc. */
2068 12061 : switch (info_level) {
2069 152 : case SMB_INFO_QUERY_EAS_FROM_LIST:
2070 : {
2071 : /* Pull any EA list from the data portion. */
2072 28 : uint32_t ea_size;
2073 :
2074 152 : if (total_data < 4) {
2075 0 : reply_nterror(
2076 : req, NT_STATUS_INVALID_PARAMETER);
2077 0 : return;
2078 : }
2079 152 : ea_size = IVAL(pdata,0);
2080 :
2081 152 : if (total_data > 0 && ea_size != total_data) {
2082 0 : DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
2083 : total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2084 0 : reply_nterror(
2085 : req, NT_STATUS_INVALID_PARAMETER);
2086 0 : return;
2087 : }
2088 :
2089 152 : if (!lp_ea_support(SNUM(conn))) {
2090 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
2091 0 : return;
2092 : }
2093 :
2094 : /* Pull out the list of names. */
2095 152 : ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
2096 152 : if (!ea_list) {
2097 0 : reply_nterror(
2098 : req, NT_STATUS_INVALID_PARAMETER);
2099 0 : return;
2100 : }
2101 124 : break;
2102 : }
2103 :
2104 11488 : default:
2105 11488 : break;
2106 : }
2107 :
2108 12061 : *pparams = (char *)SMB_REALLOC(*pparams,2);
2109 12061 : if (*pparams == NULL) {
2110 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2111 0 : return;
2112 : }
2113 12061 : params = *pparams;
2114 12061 : SSVAL(params,0,0);
2115 :
2116 12061 : if ((info_level & SMB2_INFO_SPECIAL) == SMB2_INFO_SPECIAL) {
2117 : /*
2118 : * We use levels that start with 0xFF00
2119 : * internally to represent SMB2 specific levels
2120 : */
2121 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2122 0 : return;
2123 : }
2124 :
2125 12061 : status = smbd_do_qfilepathinfo(conn, req, req, info_level,
2126 : fsp, smb_fname,
2127 : delete_pending, write_time_ts,
2128 : ea_list,
2129 12061 : req->flags2, max_data_bytes,
2130 : &fixed_portion,
2131 : ppdata, &data_size);
2132 :
2133 12061 : handle_trans2qfilepathinfo_result(
2134 : conn,
2135 : req,
2136 : info_level,
2137 : status,
2138 : *ppdata,
2139 : data_size,
2140 : fixed_portion,
2141 : max_data_bytes);
2142 : }
2143 :
2144 114 : static NTSTATUS smb_q_unix_basic(
2145 : struct connection_struct *conn,
2146 : struct smb_request *req,
2147 : struct smb_filename *smb_fname,
2148 : struct files_struct *fsp,
2149 : char **ppdata,
2150 : int *ptotal_data)
2151 : {
2152 114 : const int total_data = 100;
2153 :
2154 114 : *ppdata = SMB_REALLOC(*ppdata, total_data);
2155 114 : if (*ppdata == NULL) {
2156 0 : return NT_STATUS_NO_MEMORY;
2157 : }
2158 114 : store_file_unix_basic(conn, *ppdata, fsp, &smb_fname->st);
2159 :
2160 114 : *ptotal_data = total_data;
2161 :
2162 114 : return NT_STATUS_OK;
2163 : }
2164 :
2165 20 : static NTSTATUS smb_q_unix_info2(
2166 : struct connection_struct *conn,
2167 : struct smb_request *req,
2168 : struct smb_filename *smb_fname,
2169 : struct files_struct *fsp,
2170 : char **ppdata,
2171 : int *ptotal_data)
2172 : {
2173 20 : const int total_data = 116;
2174 :
2175 20 : *ppdata = SMB_REALLOC(*ppdata, total_data);
2176 20 : if (*ppdata == NULL) {
2177 0 : return NT_STATUS_NO_MEMORY;
2178 : }
2179 20 : store_file_unix_basic_info2(conn, *ppdata, fsp, &smb_fname->st);
2180 :
2181 20 : *ptotal_data = total_data;
2182 :
2183 20 : return NT_STATUS_OK;
2184 : }
2185 :
2186 : #if defined(HAVE_POSIX_ACLS)
2187 : /****************************************************************************
2188 : Utility function to open a fsp for a POSIX handle operation.
2189 : ****************************************************************************/
2190 :
2191 88 : static NTSTATUS get_posix_fsp(connection_struct *conn,
2192 : struct smb_request *req,
2193 : struct smb_filename *smb_fname,
2194 : uint32_t access_mask,
2195 : files_struct **ret_fsp)
2196 : {
2197 0 : NTSTATUS status;
2198 88 : uint32_t create_disposition = FILE_OPEN;
2199 88 : uint32_t share_access = FILE_SHARE_READ|
2200 : FILE_SHARE_WRITE|
2201 : FILE_SHARE_DELETE;
2202 88 : struct smb2_create_blobs *posx = NULL;
2203 :
2204 : /*
2205 : * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
2206 : * but set reasonable defaults.
2207 : */
2208 88 : uint32_t file_attributes = 0664;
2209 88 : uint32_t oplock = NO_OPLOCK;
2210 88 : uint32_t create_options = FILE_NON_DIRECTORY_FILE;
2211 :
2212 : /* File or directory must exist. */
2213 88 : if (!VALID_STAT(smb_fname->st)) {
2214 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2215 : }
2216 : /* Cannot be a symlink. */
2217 88 : if (S_ISLNK(smb_fname->st.st_ex_mode)) {
2218 16 : return NT_STATUS_ACCESS_DENIED;
2219 : }
2220 : /* Set options correctly for directory open. */
2221 72 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
2222 : /*
2223 : * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
2224 : * directories, but set reasonable defaults.
2225 : */
2226 24 : file_attributes = 0775;
2227 24 : create_options = FILE_DIRECTORY_FILE;
2228 : }
2229 :
2230 72 : status = make_smb2_posix_create_ctx(
2231 : talloc_tos(), &posx, file_attributes);
2232 72 : if (!NT_STATUS_IS_OK(status)) {
2233 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
2234 : nt_errstr(status));
2235 0 : goto done;
2236 : }
2237 :
2238 72 : status = SMB_VFS_CREATE_FILE(
2239 : conn, /* conn */
2240 : req, /* req */
2241 : NULL, /* dirfsp */
2242 : smb_fname, /* fname */
2243 : access_mask, /* access_mask */
2244 : share_access, /* share_access */
2245 : create_disposition,/* create_disposition*/
2246 : create_options, /* create_options */
2247 : file_attributes,/* file_attributes */
2248 : oplock, /* oplock_request */
2249 : NULL, /* lease */
2250 : 0, /* allocation_size */
2251 : 0, /* private_flags */
2252 : NULL, /* sd */
2253 : NULL, /* ea_list */
2254 : ret_fsp, /* result */
2255 : NULL, /* pinfo */
2256 : posx, /* in_context */
2257 : NULL); /* out_context */
2258 :
2259 72 : done:
2260 72 : TALLOC_FREE(posx);
2261 72 : return status;
2262 : }
2263 :
2264 : /****************************************************************************
2265 : Utility function to count the number of entries in a POSIX acl.
2266 : ****************************************************************************/
2267 :
2268 128 : static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
2269 : {
2270 128 : unsigned int ace_count = 0;
2271 128 : int entry_id = SMB_ACL_FIRST_ENTRY;
2272 0 : SMB_ACL_ENTRY_T entry;
2273 :
2274 396 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2275 268 : entry_id = SMB_ACL_NEXT_ENTRY;
2276 268 : ace_count++;
2277 : }
2278 128 : return ace_count;
2279 : }
2280 :
2281 : /****************************************************************************
2282 : Utility function to marshall a POSIX acl into wire format.
2283 : ****************************************************************************/
2284 :
2285 128 : static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
2286 : {
2287 128 : int entry_id = SMB_ACL_FIRST_ENTRY;
2288 0 : SMB_ACL_ENTRY_T entry;
2289 :
2290 396 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2291 0 : SMB_ACL_TAG_T tagtype;
2292 0 : SMB_ACL_PERMSET_T permset;
2293 268 : unsigned char perms = 0;
2294 0 : unsigned int own_grp;
2295 :
2296 268 : entry_id = SMB_ACL_NEXT_ENTRY;
2297 :
2298 268 : if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
2299 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
2300 0 : return False;
2301 : }
2302 :
2303 268 : if (sys_acl_get_permset(entry, &permset) == -1) {
2304 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
2305 0 : return False;
2306 : }
2307 :
2308 268 : perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
2309 268 : perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
2310 268 : perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
2311 :
2312 268 : SCVAL(pdata,1,perms);
2313 :
2314 268 : switch (tagtype) {
2315 52 : case SMB_ACL_USER_OBJ:
2316 52 : SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
2317 52 : own_grp = (unsigned int)pst->st_ex_uid;
2318 52 : SIVAL(pdata,2,own_grp);
2319 52 : SIVAL(pdata,6,0);
2320 52 : break;
2321 40 : case SMB_ACL_USER:
2322 : {
2323 40 : uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2324 40 : if (!puid) {
2325 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2326 0 : return False;
2327 : }
2328 40 : own_grp = (unsigned int)*puid;
2329 40 : SCVAL(pdata,0,SMB_POSIX_ACL_USER);
2330 40 : SIVAL(pdata,2,own_grp);
2331 40 : SIVAL(pdata,6,0);
2332 40 : break;
2333 : }
2334 52 : case SMB_ACL_GROUP_OBJ:
2335 52 : SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
2336 52 : own_grp = (unsigned int)pst->st_ex_gid;
2337 52 : SIVAL(pdata,2,own_grp);
2338 52 : SIVAL(pdata,6,0);
2339 52 : break;
2340 36 : case SMB_ACL_GROUP:
2341 : {
2342 36 : gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
2343 36 : if (!pgid) {
2344 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2345 0 : return False;
2346 : }
2347 36 : own_grp = (unsigned int)*pgid;
2348 36 : SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
2349 36 : SIVAL(pdata,2,own_grp);
2350 36 : SIVAL(pdata,6,0);
2351 36 : break;
2352 : }
2353 36 : case SMB_ACL_MASK:
2354 36 : SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
2355 36 : SIVAL(pdata,2,0xFFFFFFFF);
2356 36 : SIVAL(pdata,6,0xFFFFFFFF);
2357 36 : break;
2358 52 : case SMB_ACL_OTHER:
2359 52 : SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
2360 52 : SIVAL(pdata,2,0xFFFFFFFF);
2361 52 : SIVAL(pdata,6,0xFFFFFFFF);
2362 52 : break;
2363 0 : default:
2364 0 : DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
2365 0 : return False;
2366 : }
2367 268 : pdata += SMB_POSIX_ACL_ENTRY_SIZE;
2368 : }
2369 :
2370 128 : return True;
2371 : }
2372 : #endif
2373 :
2374 80 : static NTSTATUS smb_q_posix_acl(
2375 : struct connection_struct *conn,
2376 : struct smb_request *req,
2377 : struct smb_filename *smb_fname,
2378 : struct files_struct *fsp,
2379 : char **ppdata,
2380 : int *ptotal_data)
2381 : {
2382 : #if !defined(HAVE_POSIX_ACLS)
2383 : return NT_STATUS_INVALID_LEVEL;
2384 : #else
2385 80 : char *pdata = NULL;
2386 80 : SMB_ACL_T file_acl = NULL;
2387 80 : SMB_ACL_T def_acl = NULL;
2388 80 : uint16_t num_file_acls = 0;
2389 80 : uint16_t num_def_acls = 0;
2390 80 : unsigned int size_needed = 0;
2391 0 : NTSTATUS status;
2392 0 : bool ok;
2393 80 : bool close_fsp = false;
2394 :
2395 : /*
2396 : * Ensure we always operate on a file descriptor, not just
2397 : * the filename.
2398 : */
2399 80 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
2400 80 : uint32_t access_mask = SEC_STD_READ_CONTROL|
2401 : FILE_READ_ATTRIBUTES|
2402 : FILE_WRITE_ATTRIBUTES;
2403 :
2404 80 : status = get_posix_fsp(conn,
2405 : req,
2406 : smb_fname,
2407 : access_mask,
2408 : &fsp);
2409 :
2410 80 : if (!NT_STATUS_IS_OK(status)) {
2411 16 : goto out;
2412 : }
2413 64 : close_fsp = true;
2414 : }
2415 :
2416 64 : SMB_ASSERT(fsp != NULL);
2417 :
2418 64 : status = refuse_symlink_fsp(fsp);
2419 64 : if (!NT_STATUS_IS_OK(status)) {
2420 0 : goto out;
2421 : }
2422 :
2423 64 : file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, SMB_ACL_TYPE_ACCESS,
2424 : talloc_tos());
2425 :
2426 64 : if (file_acl == NULL && no_acl_syscall_error(errno)) {
2427 0 : DBG_INFO("ACLs not implemented on "
2428 : "filesystem containing %s\n",
2429 : fsp_str_dbg(fsp));
2430 0 : status = NT_STATUS_NOT_IMPLEMENTED;
2431 0 : goto out;
2432 : }
2433 :
2434 64 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2435 : /*
2436 : * We can only have default POSIX ACLs on
2437 : * directories.
2438 : */
2439 20 : if (!fsp->fsp_flags.is_directory) {
2440 0 : DBG_INFO("Non-directory open %s\n",
2441 : fsp_str_dbg(fsp));
2442 0 : status = NT_STATUS_INVALID_HANDLE;
2443 0 : goto out;
2444 : }
2445 20 : def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
2446 : SMB_ACL_TYPE_DEFAULT,
2447 : talloc_tos());
2448 20 : def_acl = free_empty_sys_acl(conn, def_acl);
2449 : }
2450 :
2451 64 : num_file_acls = count_acl_entries(conn, file_acl);
2452 64 : num_def_acls = count_acl_entries(conn, def_acl);
2453 :
2454 : /* Wrap checks. */
2455 0 : if (num_file_acls + num_def_acls < num_file_acls) {
2456 : status = NT_STATUS_INVALID_PARAMETER;
2457 : goto out;
2458 : }
2459 :
2460 64 : size_needed = num_file_acls + num_def_acls;
2461 :
2462 : /*
2463 : * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
2464 : * than UINT_MAX, so check by division.
2465 : */
2466 64 : if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
2467 0 : status = NT_STATUS_INVALID_PARAMETER;
2468 0 : goto out;
2469 : }
2470 :
2471 64 : size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
2472 64 : if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
2473 0 : status = NT_STATUS_INVALID_PARAMETER;
2474 0 : goto out;
2475 : }
2476 64 : size_needed += SMB_POSIX_ACL_HEADER_SIZE;
2477 :
2478 64 : *ppdata = SMB_REALLOC(*ppdata, size_needed);
2479 64 : if (*ppdata == NULL) {
2480 0 : status = NT_STATUS_NO_MEMORY;
2481 0 : goto out;
2482 : }
2483 64 : pdata = *ppdata;
2484 :
2485 64 : SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
2486 64 : SSVAL(pdata,2,num_file_acls);
2487 64 : SSVAL(pdata,4,num_def_acls);
2488 64 : pdata += SMB_POSIX_ACL_HEADER_SIZE;
2489 :
2490 64 : ok = marshall_posix_acl(conn,
2491 : pdata,
2492 64 : &fsp->fsp_name->st,
2493 : file_acl);
2494 64 : if (!ok) {
2495 0 : status = NT_STATUS_INTERNAL_ERROR;
2496 0 : goto out;
2497 : }
2498 64 : pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
2499 :
2500 64 : ok = marshall_posix_acl(conn,
2501 : pdata,
2502 64 : &fsp->fsp_name->st,
2503 : def_acl);
2504 64 : if (!ok) {
2505 0 : status = NT_STATUS_INTERNAL_ERROR;
2506 0 : goto out;
2507 : }
2508 :
2509 64 : *ptotal_data = size_needed;
2510 64 : status = NT_STATUS_OK;
2511 :
2512 80 : out:
2513 :
2514 80 : if (close_fsp) {
2515 : /*
2516 : * Ensure the stat struct in smb_fname is up to
2517 : * date. Structure copy.
2518 : */
2519 64 : smb_fname->st = fsp->fsp_name->st;
2520 64 : (void)close_file_free(req, &fsp, NORMAL_CLOSE);
2521 : }
2522 :
2523 80 : TALLOC_FREE(file_acl);
2524 80 : TALLOC_FREE(def_acl);
2525 80 : return status;
2526 : #endif
2527 : }
2528 :
2529 24 : static NTSTATUS smb_q_posix_symlink(
2530 : struct connection_struct *conn,
2531 : struct smb_request *req,
2532 : struct smb_filename *smb_fname,
2533 : char **ppdata,
2534 : int *ptotal_data)
2535 : {
2536 0 : char buffer[PATH_MAX+1];
2537 0 : size_t needed, len;
2538 0 : int link_len;
2539 24 : char *pdata = NULL;
2540 24 : struct smb_filename *parent_fname = NULL;
2541 24 : struct smb_filename *base_name = NULL;
2542 0 : NTSTATUS status;
2543 :
2544 24 : DBG_DEBUG("SMB_QUERY_FILE_UNIX_LINK for file %s\n",
2545 : smb_fname_str_dbg(smb_fname));
2546 :
2547 24 : if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
2548 0 : return NT_STATUS_DOS(ERRSRV, ERRbadlink);
2549 : }
2550 :
2551 24 : status = parent_pathref(
2552 : talloc_tos(),
2553 : conn->cwd_fsp,
2554 : smb_fname,
2555 : &parent_fname,
2556 : &base_name);
2557 :
2558 24 : if (!NT_STATUS_IS_OK(status)) {
2559 0 : DBG_DEBUG("parent_pathref failed: %s\n", nt_errstr(status));
2560 0 : return status;
2561 : }
2562 :
2563 24 : link_len = SMB_VFS_READLINKAT(
2564 : conn,
2565 : parent_fname->fsp,
2566 : base_name,
2567 : buffer,
2568 : sizeof(buffer)-1);
2569 24 : TALLOC_FREE(parent_fname);
2570 :
2571 24 : if (link_len == -1) {
2572 0 : status = map_nt_error_from_unix(errno);
2573 0 : DBG_DEBUG("READLINKAT failed: %s\n", nt_errstr(status));
2574 0 : return status;
2575 : }
2576 24 : if (link_len >= sizeof(buffer)) {
2577 0 : return NT_STATUS_INTERNAL_ERROR;
2578 : }
2579 24 : buffer[link_len] = 0;
2580 :
2581 24 : needed = (link_len+1)*2;
2582 :
2583 24 : *ppdata = SMB_REALLOC(*ppdata, needed);
2584 24 : if (*ppdata == NULL) {
2585 0 : return NT_STATUS_NO_MEMORY;
2586 : }
2587 24 : pdata = *ppdata;
2588 :
2589 24 : status = srvstr_push(
2590 : pdata,
2591 : req->flags2,
2592 : pdata,
2593 : buffer,
2594 : needed,
2595 : STR_TERMINATE,
2596 : &len);
2597 24 : if (!NT_STATUS_IS_OK(status)) {
2598 0 : return status;
2599 : }
2600 24 : *ptotal_data = len;
2601 :
2602 24 : return NT_STATUS_OK;
2603 : }
2604 :
2605 10817 : static void call_trans2qpathinfo(
2606 : connection_struct *conn,
2607 : struct smb_request *req,
2608 : char **pparams,
2609 : int total_params,
2610 : char **ppdata,
2611 : int total_data,
2612 : unsigned int max_data_bytes)
2613 : {
2614 10817 : char *params = *pparams;
2615 289 : uint16_t info_level;
2616 10817 : struct smb_filename *smb_fname = NULL;
2617 10817 : bool delete_pending = False;
2618 10817 : struct timespec write_time_ts = { .tv_sec = 0, };
2619 10817 : struct files_struct *dirfsp = NULL;
2620 10817 : files_struct *fsp = NULL;
2621 289 : struct file_id fileid;
2622 289 : uint32_t name_hash;
2623 10817 : char *fname = NULL;
2624 10817 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
2625 10817 : NTTIME twrp = 0;
2626 289 : bool info_level_handled;
2627 10817 : NTSTATUS status = NT_STATUS_OK;
2628 289 : int ret;
2629 :
2630 10817 : if (!params) {
2631 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2632 0 : return;
2633 : }
2634 :
2635 :
2636 : /* qpathinfo */
2637 10817 : if (total_params < 7) {
2638 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2639 0 : return;
2640 : }
2641 :
2642 10817 : info_level = SVAL(params,0);
2643 :
2644 10817 : DBG_NOTICE("TRANSACT2_QPATHINFO: level = %d\n", info_level);
2645 :
2646 10817 : if (INFO_LEVEL_IS_UNIX(info_level)) {
2647 242 : if (!lp_smb1_unix_extensions()) {
2648 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2649 0 : return;
2650 : }
2651 242 : if (!req->posix_pathnames) {
2652 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2653 0 : return;
2654 : }
2655 : }
2656 :
2657 10817 : if (req->posix_pathnames) {
2658 450 : srvstr_get_path_posix(req,
2659 : params,
2660 450 : req->flags2,
2661 : &fname,
2662 450 : ¶ms[6],
2663 450 : total_params - 6,
2664 : STR_TERMINATE,
2665 : &status);
2666 : } else {
2667 10367 : srvstr_get_path(req,
2668 : params,
2669 10367 : req->flags2,
2670 : &fname,
2671 10367 : ¶ms[6],
2672 10367 : total_params - 6,
2673 : STR_TERMINATE,
2674 : &status);
2675 : }
2676 10817 : if (!NT_STATUS_IS_OK(status)) {
2677 0 : reply_nterror(req, status);
2678 0 : return;
2679 : }
2680 :
2681 10817 : if (ucf_flags & UCF_GMT_PATHNAME) {
2682 3632 : extract_snapshot_token(fname, &twrp);
2683 : }
2684 10817 : status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
2685 10817 : if (!NT_STATUS_IS_OK(status)) {
2686 0 : reply_nterror(req, status);
2687 0 : return;
2688 : }
2689 10817 : status = filename_convert_dirfsp(req,
2690 : conn,
2691 : fname,
2692 : ucf_flags,
2693 : twrp,
2694 : &dirfsp,
2695 : &smb_fname);
2696 10817 : if (!NT_STATUS_IS_OK(status)) {
2697 1758 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2698 1208 : reply_botherror(req,
2699 : NT_STATUS_PATH_NOT_COVERED,
2700 : ERRSRV, ERRbadpath);
2701 1208 : return;
2702 : }
2703 550 : reply_nterror(req, status);
2704 550 : return;
2705 : }
2706 :
2707 : /*
2708 : * qpathinfo must operate on an existing file, so we
2709 : * can exit early if filename_convert_dirfsp() returned the
2710 : * "new file" NT_STATUS_OK, !VALID_STAT case.
2711 : */
2712 :
2713 9059 : if (!VALID_STAT(smb_fname->st)) {
2714 110 : reply_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2715 110 : return;
2716 : }
2717 :
2718 8949 : fsp = smb_fname->fsp;
2719 :
2720 : /* If this is a stream, check if there is a delete_pending. */
2721 8949 : if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
2722 3069 : && is_ntfs_stream_smb_fname(smb_fname)) {
2723 0 : struct smb_filename *smb_fname_base;
2724 :
2725 : /* Create an smb_filename with stream_name == NULL. */
2726 60 : smb_fname_base = synthetic_smb_fname(
2727 : talloc_tos(),
2728 60 : smb_fname->base_name,
2729 : NULL,
2730 : NULL,
2731 60 : smb_fname->twrp,
2732 60 : smb_fname->flags);
2733 60 : if (smb_fname_base == NULL) {
2734 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2735 0 : return;
2736 : }
2737 :
2738 60 : ret = vfs_stat(conn, smb_fname_base);
2739 60 : if (ret != 0) {
2740 0 : DBG_NOTICE("vfs_stat of %s failed "
2741 : "(%s)\n",
2742 : smb_fname_str_dbg(smb_fname_base),
2743 : strerror(errno));
2744 0 : TALLOC_FREE(smb_fname_base);
2745 0 : reply_nterror(req,
2746 : map_nt_error_from_unix(errno));
2747 0 : return;
2748 : }
2749 :
2750 60 : status = file_name_hash(conn,
2751 : smb_fname_str_dbg(smb_fname_base),
2752 : &name_hash);
2753 60 : if (!NT_STATUS_IS_OK(status)) {
2754 0 : TALLOC_FREE(smb_fname_base);
2755 0 : reply_nterror(req, status);
2756 0 : return;
2757 : }
2758 :
2759 60 : fileid = vfs_file_id_from_sbuf(conn,
2760 60 : &smb_fname_base->st);
2761 60 : TALLOC_FREE(smb_fname_base);
2762 60 : get_file_infos(fileid, name_hash, &delete_pending, NULL);
2763 60 : if (delete_pending) {
2764 4 : reply_nterror(req, NT_STATUS_DELETE_PENDING);
2765 4 : return;
2766 : }
2767 : }
2768 :
2769 8945 : status = file_name_hash(conn,
2770 : smb_fname_str_dbg(smb_fname),
2771 : &name_hash);
2772 8945 : if (!NT_STATUS_IS_OK(status)) {
2773 0 : reply_nterror(req, status);
2774 0 : return;
2775 : }
2776 :
2777 8945 : if (fsp_getinfo_ask_sharemode(fsp)) {
2778 8945 : fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
2779 8945 : get_file_infos(fileid, name_hash, &delete_pending,
2780 : &write_time_ts);
2781 : }
2782 :
2783 8945 : if (delete_pending) {
2784 119 : reply_nterror(req, NT_STATUS_DELETE_PENDING);
2785 119 : return;
2786 : }
2787 :
2788 8826 : info_level_handled = true; /* Untouched in switch cases below */
2789 :
2790 8826 : switch (info_level) {
2791 :
2792 8328 : default:
2793 8328 : info_level_handled = false;
2794 8328 : break;
2795 :
2796 114 : case SMB_QUERY_FILE_UNIX_BASIC:
2797 114 : status = smb_q_unix_basic(
2798 : conn,
2799 : req,
2800 : smb_fname,
2801 114 : smb_fname->fsp,
2802 : ppdata,
2803 : &total_data);
2804 114 : break;
2805 :
2806 16 : case SMB_QUERY_FILE_UNIX_INFO2:
2807 16 : status = smb_q_unix_info2(
2808 : conn,
2809 : req,
2810 : smb_fname,
2811 16 : smb_fname->fsp,
2812 : ppdata,
2813 : &total_data);
2814 16 : break;
2815 :
2816 80 : case SMB_QUERY_POSIX_ACL:
2817 80 : status = smb_q_posix_acl(
2818 : conn,
2819 : req,
2820 : smb_fname,
2821 80 : smb_fname->fsp,
2822 : ppdata,
2823 : &total_data);
2824 80 : break;
2825 :
2826 24 : case SMB_QUERY_FILE_UNIX_LINK:
2827 24 : status = smb_q_posix_symlink(
2828 : conn,
2829 : req,
2830 : smb_fname,
2831 : ppdata,
2832 : &total_data);
2833 24 : break;
2834 : }
2835 :
2836 8562 : if (info_level_handled) {
2837 234 : handle_trans2qfilepathinfo_result(
2838 : conn,
2839 : req,
2840 : info_level,
2841 : status,
2842 : *ppdata,
2843 : total_data,
2844 : total_data,
2845 : max_data_bytes);
2846 234 : return;
2847 : }
2848 :
2849 8592 : call_trans2qfilepathinfo(
2850 : conn,
2851 : req,
2852 : TRANSACT2_QPATHINFO,
2853 : info_level,
2854 : smb_fname,
2855 : fsp,
2856 : false,
2857 : write_time_ts,
2858 : pparams,
2859 : total_params,
2860 : ppdata,
2861 : total_data,
2862 : max_data_bytes);
2863 : }
2864 :
2865 0 : static NTSTATUS smb_q_posix_lock(
2866 : struct connection_struct *conn,
2867 : struct smb_request *req,
2868 : struct files_struct *fsp,
2869 : char **ppdata,
2870 : int *ptotal_data)
2871 : {
2872 0 : char *pdata = *ppdata;
2873 0 : int total_data = *ptotal_data;
2874 0 : uint64_t count;
2875 0 : uint64_t offset;
2876 0 : uint64_t smblctx;
2877 0 : enum brl_type lock_type;
2878 0 : NTSTATUS status;
2879 :
2880 0 : if (fsp->fsp_flags.is_pathref || (fsp_get_io_fd(fsp) == -1)) {
2881 0 : return NT_STATUS_INVALID_HANDLE;
2882 : }
2883 :
2884 0 : if (total_data != POSIX_LOCK_DATA_SIZE) {
2885 0 : return NT_STATUS_INVALID_PARAMETER;
2886 : }
2887 :
2888 0 : switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
2889 0 : case POSIX_LOCK_TYPE_READ:
2890 0 : lock_type = READ_LOCK;
2891 0 : break;
2892 0 : case POSIX_LOCK_TYPE_WRITE:
2893 0 : lock_type = WRITE_LOCK;
2894 0 : break;
2895 0 : case POSIX_LOCK_TYPE_UNLOCK:
2896 : default:
2897 : /* There's no point in asking for an unlock... */
2898 0 : return NT_STATUS_INVALID_PARAMETER;
2899 : }
2900 :
2901 0 : smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
2902 0 : offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
2903 0 : count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
2904 :
2905 0 : status = query_lock(
2906 : fsp,
2907 : &smblctx,
2908 : &count,
2909 : &offset,
2910 : &lock_type,
2911 : POSIX_LOCK);
2912 :
2913 0 : if (NT_STATUS_IS_OK(status)) {
2914 : /*
2915 : * For success we just return a copy of what we sent
2916 : * with the lock type set to POSIX_LOCK_TYPE_UNLOCK.
2917 : */
2918 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
2919 0 : return NT_STATUS_OK;
2920 : }
2921 :
2922 0 : if (!ERROR_WAS_LOCK_DENIED(status)) {
2923 0 : DBG_DEBUG("query_lock() failed: %s\n", nt_errstr(status));
2924 0 : return status;
2925 : }
2926 :
2927 : /*
2928 : * Here we need to report who has it locked.
2929 : */
2930 :
2931 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
2932 0 : SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
2933 0 : SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
2934 0 : SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
2935 0 : SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
2936 :
2937 0 : return NT_STATUS_OK;
2938 : }
2939 :
2940 3617 : static void call_trans2qfileinfo(
2941 : connection_struct *conn,
2942 : struct smb_request *req,
2943 : char **pparams,
2944 : int total_params,
2945 : char **ppdata,
2946 : int total_data,
2947 : unsigned int max_data_bytes)
2948 : {
2949 3617 : char *params = *pparams;
2950 185 : uint16_t info_level;
2951 3617 : struct smb_filename *smb_fname = NULL;
2952 3617 : bool delete_pending = False;
2953 3617 : struct timespec write_time_ts = { .tv_sec = 0, };
2954 3617 : files_struct *fsp = NULL;
2955 185 : struct file_id fileid;
2956 185 : bool info_level_handled;
2957 3617 : NTSTATUS status = NT_STATUS_OK;
2958 185 : int ret;
2959 :
2960 3617 : if (params == NULL) {
2961 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2962 0 : return;
2963 : }
2964 :
2965 3617 : if (total_params < 4) {
2966 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2967 0 : return;
2968 : }
2969 :
2970 3617 : fsp = file_fsp(req, SVAL(params,0));
2971 3617 : info_level = SVAL(params,2);
2972 :
2973 3617 : if (IS_IPC(conn)) {
2974 0 : call_trans2qpipeinfo(
2975 : conn,
2976 : req,
2977 : fsp,
2978 : info_level,
2979 : TRANSACT2_QFILEINFO,
2980 : pparams,
2981 : total_params,
2982 : ppdata,
2983 : total_data,
2984 : max_data_bytes);
2985 0 : return;
2986 : }
2987 :
2988 3617 : DBG_NOTICE("TRANSACT2_QFILEINFO: level = %d\n", info_level);
2989 :
2990 3617 : if (INFO_LEVEL_IS_UNIX(info_level)) {
2991 4 : if (!lp_smb1_unix_extensions()) {
2992 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2993 0 : return;
2994 : }
2995 4 : if (!req->posix_pathnames) {
2996 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2997 0 : return;
2998 : }
2999 : }
3000 :
3001 : /* Initial check for valid fsp ptr. */
3002 3617 : if (!check_fsp_open(conn, req, fsp)) {
3003 144 : return;
3004 : }
3005 :
3006 3473 : smb_fname = fsp->fsp_name;
3007 :
3008 3473 : if(fsp->fake_file_handle) {
3009 : /*
3010 : * This is actually for the QUOTA_FAKE_FILE --metze
3011 : */
3012 :
3013 : /* We know this name is ok, it's already passed the checks. */
3014 :
3015 3473 : } else if(fsp_get_pathref_fd(fsp) == -1) {
3016 : /*
3017 : * This is actually a QFILEINFO on a directory
3018 : * handle (returned from an NT SMB). NT5.0 seems
3019 : * to do this call. JRA.
3020 : */
3021 0 : ret = vfs_stat(conn, smb_fname);
3022 0 : if (ret != 0) {
3023 0 : DBG_NOTICE("vfs_stat of %s failed (%s)\n",
3024 : smb_fname_str_dbg(smb_fname),
3025 : strerror(errno));
3026 0 : reply_nterror(req,
3027 : map_nt_error_from_unix(errno));
3028 0 : return;
3029 : }
3030 :
3031 0 : if (fsp_getinfo_ask_sharemode(fsp)) {
3032 0 : fileid = vfs_file_id_from_sbuf(
3033 0 : conn, &smb_fname->st);
3034 0 : get_file_infos(fileid, fsp->name_hash,
3035 : &delete_pending,
3036 : &write_time_ts);
3037 : }
3038 : } else {
3039 : /*
3040 : * Original code - this is an open file.
3041 : */
3042 3473 : status = vfs_stat_fsp(fsp);
3043 3473 : if (!NT_STATUS_IS_OK(status)) {
3044 0 : DEBUG(3, ("fstat of %s failed (%s)\n",
3045 : fsp_fnum_dbg(fsp), nt_errstr(status)));
3046 0 : reply_nterror(req, status);
3047 0 : return;
3048 : }
3049 3473 : if (fsp_getinfo_ask_sharemode(fsp)) {
3050 3473 : fileid = vfs_file_id_from_sbuf(
3051 3473 : conn, &smb_fname->st);
3052 3473 : get_file_infos(fileid, fsp->name_hash,
3053 : &delete_pending,
3054 : &write_time_ts);
3055 : }
3056 : }
3057 :
3058 3473 : info_level_handled = true; /* Untouched in switch cases below */
3059 :
3060 3473 : switch (info_level) {
3061 :
3062 3284 : default:
3063 3284 : info_level_handled = false;
3064 3284 : break;
3065 :
3066 0 : case SMB_QUERY_POSIX_LOCK:
3067 0 : status = smb_q_posix_lock(conn, req, fsp, ppdata, &total_data);
3068 0 : break;
3069 :
3070 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3071 0 : status = smb_q_unix_basic(
3072 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3073 0 : break;
3074 :
3075 4 : case SMB_QUERY_FILE_UNIX_INFO2:
3076 4 : status = smb_q_unix_info2(
3077 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3078 4 : break;
3079 :
3080 0 : case SMB_QUERY_POSIX_ACL:
3081 0 : status = smb_q_posix_acl(
3082 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3083 0 : break;
3084 : }
3085 :
3086 3288 : if (info_level_handled) {
3087 4 : handle_trans2qfilepathinfo_result(
3088 : conn,
3089 : req,
3090 : info_level,
3091 : status,
3092 : *ppdata,
3093 : total_data,
3094 : total_data,
3095 : max_data_bytes);
3096 4 : return;
3097 : }
3098 :
3099 3469 : call_trans2qfilepathinfo(
3100 : conn,
3101 : req,
3102 : TRANSACT2_QFILEINFO,
3103 : info_level,
3104 : smb_fname,
3105 : fsp,
3106 : delete_pending,
3107 : write_time_ts,
3108 : pparams,
3109 : total_params,
3110 : ppdata,
3111 : total_data,
3112 : max_data_bytes);
3113 : }
3114 :
3115 5607 : static void handle_trans2setfilepathinfo_result(
3116 : connection_struct *conn,
3117 : struct smb_request *req,
3118 : uint16_t info_level,
3119 : NTSTATUS status,
3120 : char *pdata,
3121 : int data_return_size,
3122 : unsigned int max_data_bytes)
3123 : {
3124 5607 : char params[2] = { 0, 0, };
3125 :
3126 5607 : if (NT_STATUS_IS_OK(status)) {
3127 4680 : send_trans2_replies(
3128 : conn,
3129 : req,
3130 4680 : NT_STATUS_OK,
3131 : params,
3132 : 2,
3133 : pdata,
3134 : data_return_size,
3135 : max_data_bytes);
3136 4680 : return;
3137 : }
3138 :
3139 927 : if (open_was_deferred(req->xconn, req->mid)) {
3140 : /* We have re-scheduled this call. */
3141 6 : return;
3142 : }
3143 :
3144 921 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3145 32 : bool ok = defer_smb1_sharing_violation(req);
3146 32 : if (ok) {
3147 16 : return;
3148 : }
3149 : }
3150 :
3151 905 : if (NT_STATUS_EQUAL(status, NT_STATUS_EVENT_PENDING)) {
3152 : /* We have re-scheduled this call. */
3153 28 : return;
3154 : }
3155 :
3156 877 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3157 0 : reply_botherror(
3158 : req,
3159 : NT_STATUS_PATH_NOT_COVERED,
3160 : ERRSRV,
3161 : ERRbadpath);
3162 0 : return;
3163 : }
3164 :
3165 877 : if (info_level == SMB_POSIX_PATH_OPEN) {
3166 12 : reply_openerror(req, status);
3167 12 : return;
3168 : }
3169 :
3170 865 : if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
3171 : /*
3172 : * Invalid EA name needs to return 2 param bytes,
3173 : * not a zero-length error packet.
3174 : */
3175 :
3176 235 : send_trans2_replies(
3177 : conn,
3178 : req,
3179 : status,
3180 : params,
3181 : 2,
3182 : NULL,
3183 : 0,
3184 : max_data_bytes);
3185 235 : return;
3186 : }
3187 :
3188 630 : reply_nterror(req, status);
3189 : }
3190 :
3191 : /****************************************************************************
3192 : Create a directory with POSIX semantics.
3193 : ****************************************************************************/
3194 :
3195 48 : static NTSTATUS smb_posix_mkdir(connection_struct *conn,
3196 : struct smb_request *req,
3197 : char **ppdata,
3198 : int total_data,
3199 : struct smb_filename *smb_fname,
3200 : int *pdata_return_size)
3201 : {
3202 48 : NTSTATUS status = NT_STATUS_OK;
3203 48 : uint32_t raw_unixmode = 0;
3204 48 : mode_t unixmode = (mode_t)0;
3205 48 : files_struct *fsp = NULL;
3206 48 : uint16_t info_level_return = 0;
3207 0 : int info;
3208 48 : char *pdata = *ppdata;
3209 48 : struct smb2_create_blobs *posx = NULL;
3210 :
3211 48 : if (total_data < 18) {
3212 0 : return NT_STATUS_INVALID_PARAMETER;
3213 : }
3214 :
3215 48 : raw_unixmode = IVAL(pdata,8);
3216 : /* Next 4 bytes are not yet defined. */
3217 :
3218 48 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3219 : PERM_NEW_DIR, &unixmode);
3220 48 : if (!NT_STATUS_IS_OK(status)) {
3221 0 : return status;
3222 : }
3223 :
3224 48 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3225 48 : if (!NT_STATUS_IS_OK(status)) {
3226 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3227 : nt_errstr(status));
3228 0 : return status;
3229 : }
3230 :
3231 48 : DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
3232 : smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
3233 :
3234 48 : status = SMB_VFS_CREATE_FILE(
3235 : conn, /* conn */
3236 : req, /* req */
3237 : NULL, /* dirfsp */
3238 : smb_fname, /* fname */
3239 : FILE_READ_ATTRIBUTES, /* access_mask */
3240 : FILE_SHARE_NONE, /* share_access */
3241 : FILE_CREATE, /* create_disposition*/
3242 : FILE_DIRECTORY_FILE, /* create_options */
3243 : 0, /* file_attributes */
3244 : 0, /* oplock_request */
3245 : NULL, /* lease */
3246 : 0, /* allocation_size */
3247 : 0, /* private_flags */
3248 : NULL, /* sd */
3249 : NULL, /* ea_list */
3250 : &fsp, /* result */
3251 : &info, /* pinfo */
3252 : posx, /* in_context_blobs */
3253 : NULL); /* out_context_blobs */
3254 :
3255 48 : TALLOC_FREE(posx);
3256 :
3257 48 : if (NT_STATUS_IS_OK(status)) {
3258 48 : close_file_free(req, &fsp, NORMAL_CLOSE);
3259 : }
3260 :
3261 48 : info_level_return = SVAL(pdata,16);
3262 :
3263 48 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3264 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3265 48 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3266 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3267 : } else {
3268 48 : *pdata_return_size = 12;
3269 : }
3270 :
3271 : /* Realloc the data size */
3272 48 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3273 48 : if (*ppdata == NULL) {
3274 0 : *pdata_return_size = 0;
3275 0 : return NT_STATUS_NO_MEMORY;
3276 : }
3277 48 : pdata = *ppdata;
3278 :
3279 48 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
3280 48 : SSVAL(pdata,2,0); /* No fnum. */
3281 48 : SIVAL(pdata,4,info); /* Was directory created. */
3282 :
3283 48 : switch (info_level_return) {
3284 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3285 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3286 0 : SSVAL(pdata,10,0); /* Padding. */
3287 0 : store_file_unix_basic(conn, pdata + 12, fsp,
3288 0 : &smb_fname->st);
3289 0 : break;
3290 0 : case SMB_QUERY_FILE_UNIX_INFO2:
3291 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3292 0 : SSVAL(pdata,10,0); /* Padding. */
3293 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
3294 0 : &smb_fname->st);
3295 0 : break;
3296 48 : default:
3297 48 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3298 48 : SSVAL(pdata,10,0); /* Padding. */
3299 48 : break;
3300 : }
3301 :
3302 48 : return status;
3303 : }
3304 :
3305 : /****************************************************************************
3306 : Open/Create a file with POSIX semantics.
3307 : ****************************************************************************/
3308 :
3309 : #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
3310 : #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
3311 :
3312 174 : static NTSTATUS smb_posix_open(connection_struct *conn,
3313 : struct smb_request *req,
3314 : char **ppdata,
3315 : int total_data,
3316 : struct files_struct *dirfsp,
3317 : struct smb_filename *smb_fname,
3318 : int *pdata_return_size)
3319 : {
3320 174 : bool extended_oplock_granted = False;
3321 174 : char *pdata = *ppdata;
3322 174 : uint32_t flags = 0;
3323 174 : uint32_t wire_open_mode = 0;
3324 174 : uint32_t raw_unixmode = 0;
3325 174 : uint32_t attributes = 0;
3326 174 : uint32_t create_disp = 0;
3327 174 : uint32_t access_mask = 0;
3328 174 : uint32_t create_options = FILE_NON_DIRECTORY_FILE;
3329 174 : NTSTATUS status = NT_STATUS_OK;
3330 174 : mode_t unixmode = (mode_t)0;
3331 174 : files_struct *fsp = NULL;
3332 174 : int oplock_request = 0;
3333 174 : int info = 0;
3334 174 : uint16_t info_level_return = 0;
3335 174 : struct smb2_create_blobs *posx = NULL;
3336 :
3337 174 : if (total_data < 18) {
3338 0 : return NT_STATUS_INVALID_PARAMETER;
3339 : }
3340 :
3341 174 : flags = IVAL(pdata,0);
3342 174 : oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
3343 174 : if (oplock_request) {
3344 0 : oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
3345 : }
3346 :
3347 174 : wire_open_mode = IVAL(pdata,4);
3348 :
3349 174 : if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
3350 48 : return smb_posix_mkdir(conn, req,
3351 : ppdata,
3352 : total_data,
3353 : smb_fname,
3354 : pdata_return_size);
3355 : }
3356 :
3357 126 : switch (wire_open_mode & SMB_ACCMODE) {
3358 28 : case SMB_O_RDONLY:
3359 28 : access_mask = SMB_O_RDONLY_MAPPING;
3360 28 : break;
3361 4 : case SMB_O_WRONLY:
3362 4 : access_mask = SMB_O_WRONLY_MAPPING;
3363 4 : break;
3364 94 : case SMB_O_RDWR:
3365 94 : access_mask = (SMB_O_RDONLY_MAPPING|
3366 : SMB_O_WRONLY_MAPPING);
3367 94 : break;
3368 0 : default:
3369 0 : DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
3370 : (unsigned int)wire_open_mode ));
3371 0 : return NT_STATUS_INVALID_PARAMETER;
3372 : }
3373 :
3374 126 : wire_open_mode &= ~SMB_ACCMODE;
3375 :
3376 : /* First take care of O_CREAT|O_EXCL interactions. */
3377 126 : switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
3378 38 : case (SMB_O_CREAT | SMB_O_EXCL):
3379 : /* File exists fail. File not exist create. */
3380 38 : create_disp = FILE_CREATE;
3381 38 : break;
3382 40 : case SMB_O_CREAT:
3383 : /* File exists open. File not exist create. */
3384 40 : create_disp = FILE_OPEN_IF;
3385 40 : break;
3386 48 : case SMB_O_EXCL:
3387 : /* O_EXCL on its own without O_CREAT is undefined.
3388 : We deliberately ignore it as some versions of
3389 : Linux CIFSFS can send a bare O_EXCL on the
3390 : wire which other filesystems in the kernel
3391 : ignore. See bug 9519 for details. */
3392 :
3393 : /* Fallthrough. */
3394 :
3395 : case 0:
3396 : /* File exists open. File not exist fail. */
3397 48 : create_disp = FILE_OPEN;
3398 48 : break;
3399 0 : default:
3400 0 : DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
3401 : (unsigned int)wire_open_mode ));
3402 0 : return NT_STATUS_INVALID_PARAMETER;
3403 : }
3404 :
3405 : /* Next factor in the effects of O_TRUNC. */
3406 126 : wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
3407 :
3408 126 : if (wire_open_mode & SMB_O_TRUNC) {
3409 4 : switch (create_disp) {
3410 0 : case FILE_CREATE:
3411 : /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
3412 : /* Leave create_disp alone as
3413 : (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
3414 : */
3415 : /* File exists fail. File not exist create. */
3416 4 : break;
3417 0 : case FILE_OPEN_IF:
3418 : /* SMB_O_CREAT | SMB_O_TRUNC */
3419 : /* File exists overwrite. File not exist create. */
3420 0 : create_disp = FILE_OVERWRITE_IF;
3421 0 : break;
3422 4 : case FILE_OPEN:
3423 : /* SMB_O_TRUNC */
3424 : /* File exists overwrite. File not exist fail. */
3425 4 : create_disp = FILE_OVERWRITE;
3426 4 : break;
3427 0 : default:
3428 : /* Cannot get here. */
3429 0 : smb_panic("smb_posix_open: logic error");
3430 : return NT_STATUS_INVALID_PARAMETER;
3431 : }
3432 : }
3433 :
3434 126 : raw_unixmode = IVAL(pdata,8);
3435 : /* Next 4 bytes are not yet defined. */
3436 :
3437 126 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3438 126 : (VALID_STAT(smb_fname->st) ?
3439 : PERM_EXISTING_FILE : PERM_NEW_FILE),
3440 : &unixmode);
3441 :
3442 126 : if (!NT_STATUS_IS_OK(status)) {
3443 0 : return status;
3444 : }
3445 :
3446 126 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3447 126 : if (!NT_STATUS_IS_OK(status)) {
3448 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3449 : nt_errstr(status));
3450 0 : return status;
3451 : }
3452 :
3453 126 : if (wire_open_mode & SMB_O_SYNC) {
3454 0 : create_options |= FILE_WRITE_THROUGH;
3455 : }
3456 126 : if (wire_open_mode & SMB_O_APPEND) {
3457 0 : access_mask |= FILE_APPEND_DATA;
3458 : }
3459 126 : if (wire_open_mode & SMB_O_DIRECT) {
3460 : /*
3461 : * BUG: this doesn't work anymore since
3462 : * e0814dc5082dd4ecca8a155e0ce24b073158fd92. But since
3463 : * FILE_FLAG_NO_BUFFERING isn't used at all in the IO codepath,
3464 : * it doesn't really matter.
3465 : */
3466 0 : attributes |= FILE_FLAG_NO_BUFFERING;
3467 : }
3468 :
3469 126 : if ((wire_open_mode & SMB_O_DIRECTORY) ||
3470 126 : VALID_STAT_OF_DIR(smb_fname->st)) {
3471 8 : if (access_mask != SMB_O_RDONLY_MAPPING) {
3472 4 : return NT_STATUS_FILE_IS_A_DIRECTORY;
3473 : }
3474 4 : create_options &= ~FILE_NON_DIRECTORY_FILE;
3475 4 : create_options |= FILE_DIRECTORY_FILE;
3476 : }
3477 :
3478 122 : DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
3479 : smb_fname_str_dbg(smb_fname),
3480 : (unsigned int)wire_open_mode,
3481 : (unsigned int)unixmode ));
3482 :
3483 122 : status = SMB_VFS_CREATE_FILE(
3484 : conn, /* conn */
3485 : req, /* req */
3486 : dirfsp, /* dirfsp */
3487 : smb_fname, /* fname */
3488 : access_mask, /* access_mask */
3489 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3490 : FILE_SHARE_DELETE),
3491 : create_disp, /* create_disposition*/
3492 : create_options, /* create_options */
3493 : attributes, /* file_attributes */
3494 : oplock_request, /* oplock_request */
3495 : NULL, /* lease */
3496 : 0, /* allocation_size */
3497 : 0, /* private_flags */
3498 : NULL, /* sd */
3499 : NULL, /* ea_list */
3500 : &fsp, /* result */
3501 : &info, /* pinfo */
3502 : posx, /* in_context_blobs */
3503 : NULL); /* out_context_blobs */
3504 :
3505 122 : TALLOC_FREE(posx);
3506 :
3507 122 : if (!NT_STATUS_IS_OK(status)) {
3508 8 : return status;
3509 : }
3510 :
3511 114 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3512 0 : extended_oplock_granted = True;
3513 : }
3514 :
3515 114 : if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3516 0 : extended_oplock_granted = True;
3517 : }
3518 :
3519 114 : info_level_return = SVAL(pdata,16);
3520 :
3521 : /* Allocate the correct return size. */
3522 :
3523 114 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3524 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3525 114 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3526 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3527 : } else {
3528 114 : *pdata_return_size = 12;
3529 : }
3530 :
3531 : /* Realloc the data size */
3532 114 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3533 114 : if (*ppdata == NULL) {
3534 0 : close_file_free(req, &fsp, ERROR_CLOSE);
3535 0 : *pdata_return_size = 0;
3536 0 : return NT_STATUS_NO_MEMORY;
3537 : }
3538 114 : pdata = *ppdata;
3539 :
3540 114 : if (extended_oplock_granted) {
3541 0 : if (flags & REQUEST_BATCH_OPLOCK) {
3542 0 : SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
3543 : } else {
3544 0 : SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
3545 : }
3546 114 : } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
3547 0 : SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
3548 : } else {
3549 114 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
3550 : }
3551 :
3552 114 : SSVAL(pdata,2,fsp->fnum);
3553 114 : SIVAL(pdata,4,info); /* Was file created etc. */
3554 :
3555 114 : switch (info_level_return) {
3556 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3557 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3558 0 : SSVAL(pdata,10,0); /* padding. */
3559 0 : store_file_unix_basic(conn, pdata + 12, fsp,
3560 0 : &smb_fname->st);
3561 0 : break;
3562 0 : case SMB_QUERY_FILE_UNIX_INFO2:
3563 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3564 0 : SSVAL(pdata,10,0); /* padding. */
3565 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
3566 0 : &smb_fname->st);
3567 0 : break;
3568 114 : default:
3569 114 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3570 114 : SSVAL(pdata,10,0); /* padding. */
3571 114 : break;
3572 : }
3573 114 : return NT_STATUS_OK;
3574 : }
3575 :
3576 : /****************************************************************************
3577 : Delete a file with POSIX semantics.
3578 : ****************************************************************************/
3579 :
3580 : struct smb_posix_unlink_state {
3581 : struct smb_filename *smb_fname;
3582 : struct files_struct *fsp;
3583 : NTSTATUS status;
3584 : };
3585 :
3586 248 : static void smb_posix_unlink_locked(struct share_mode_lock *lck,
3587 : void *private_data)
3588 : {
3589 248 : struct smb_posix_unlink_state *state = private_data;
3590 248 : char del = 1;
3591 0 : bool other_nonposix_opens;
3592 :
3593 248 : other_nonposix_opens = has_other_nonposix_opens(lck, state->fsp);
3594 248 : if (other_nonposix_opens) {
3595 : /* Fail with sharing violation. */
3596 8 : state->status = NT_STATUS_SHARING_VIOLATION;
3597 8 : return;
3598 : }
3599 :
3600 : /*
3601 : * Set the delete on close.
3602 : */
3603 240 : state->status = smb_set_file_disposition_info(state->fsp->conn,
3604 : &del,
3605 : 1,
3606 240 : state->fsp,
3607 : state->smb_fname);
3608 : }
3609 :
3610 532 : static NTSTATUS smb_posix_unlink(connection_struct *conn,
3611 : struct smb_request *req,
3612 : const char *pdata,
3613 : int total_data,
3614 : struct files_struct *dirfsp,
3615 : struct smb_filename *smb_fname)
3616 : {
3617 532 : struct smb_posix_unlink_state state = {};
3618 532 : NTSTATUS status = NT_STATUS_OK;
3619 532 : files_struct *fsp = NULL;
3620 532 : uint16_t flags = 0;
3621 532 : int info = 0;
3622 532 : int create_options = FILE_OPEN_REPARSE_POINT;
3623 532 : struct smb2_create_blobs *posx = NULL;
3624 :
3625 532 : if (!CAN_WRITE(conn)) {
3626 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3627 : }
3628 :
3629 532 : if (total_data < 2) {
3630 0 : return NT_STATUS_INVALID_PARAMETER;
3631 : }
3632 :
3633 532 : flags = SVAL(pdata,0);
3634 :
3635 532 : if (!VALID_STAT(smb_fname->st)) {
3636 276 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3637 : }
3638 :
3639 256 : if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
3640 40 : !VALID_STAT_OF_DIR(smb_fname->st)) {
3641 0 : return NT_STATUS_NOT_A_DIRECTORY;
3642 : }
3643 :
3644 256 : DEBUG(10,("smb_posix_unlink: %s %s\n",
3645 : (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
3646 : smb_fname_str_dbg(smb_fname)));
3647 :
3648 256 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
3649 44 : create_options |= FILE_DIRECTORY_FILE;
3650 : }
3651 :
3652 256 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
3653 256 : if (!NT_STATUS_IS_OK(status)) {
3654 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3655 : nt_errstr(status));
3656 0 : return status;
3657 : }
3658 :
3659 256 : status = SMB_VFS_CREATE_FILE(
3660 : conn, /* conn */
3661 : req, /* req */
3662 : dirfsp, /* dirfsp */
3663 : smb_fname, /* fname */
3664 : DELETE_ACCESS, /* access_mask */
3665 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3666 : FILE_SHARE_DELETE),
3667 : FILE_OPEN, /* create_disposition*/
3668 : create_options, /* create_options */
3669 : 0, /* file_attributes */
3670 : 0, /* oplock_request */
3671 : NULL, /* lease */
3672 : 0, /* allocation_size */
3673 : 0, /* private_flags */
3674 : NULL, /* sd */
3675 : NULL, /* ea_list */
3676 : &fsp, /* result */
3677 : &info, /* pinfo */
3678 : posx, /* in_context_blobs */
3679 : NULL); /* out_context_blobs */
3680 :
3681 256 : TALLOC_FREE(posx);
3682 :
3683 256 : if (!NT_STATUS_IS_OK(status)) {
3684 8 : return status;
3685 : }
3686 :
3687 : /*
3688 : * Don't lie to client. If we can't really delete due to
3689 : * non-POSIX opens return SHARING_VIOLATION.
3690 : */
3691 :
3692 248 : state = (struct smb_posix_unlink_state) {
3693 : .smb_fname = smb_fname,
3694 : .fsp = fsp,
3695 : };
3696 :
3697 248 : status = share_mode_do_locked_vfs_allowed(fsp->file_id,
3698 : smb_posix_unlink_locked,
3699 : &state);
3700 248 : if (!NT_STATUS_IS_OK(status)) {
3701 0 : DBG_ERR("share_mode_do_locked_vfs_allowed(%s) failed - %s\n",
3702 : fsp_str_dbg(fsp), nt_errstr(status));
3703 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
3704 0 : return NT_STATUS_INVALID_PARAMETER;
3705 : }
3706 :
3707 248 : status = state.status;
3708 248 : if (!NT_STATUS_IS_OK(status)) {
3709 8 : close_file_free(req, &fsp, NORMAL_CLOSE);
3710 8 : return status;
3711 : }
3712 240 : return close_file_free(req, &fsp, NORMAL_CLOSE);
3713 : }
3714 :
3715 : /****************************************************************************
3716 : Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
3717 : ****************************************************************************/
3718 :
3719 128 : static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
3720 : struct smb_request *req,
3721 : const char *pdata,
3722 : int total_data,
3723 : struct smb_filename *new_smb_fname)
3724 : {
3725 128 : char *link_target = NULL;
3726 0 : struct smb_filename target_fname;
3727 128 : TALLOC_CTX *ctx = talloc_tos();
3728 0 : NTSTATUS status;
3729 0 : int ret;
3730 128 : struct smb_filename *parent_fname = NULL;
3731 128 : struct smb_filename *base_name = NULL;
3732 :
3733 128 : if (!CAN_WRITE(conn)) {
3734 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3735 : }
3736 :
3737 : /* Set a symbolic link. */
3738 : /* Don't allow this if follow links is false. */
3739 :
3740 128 : if (total_data == 0) {
3741 0 : return NT_STATUS_INVALID_PARAMETER;
3742 : }
3743 :
3744 128 : if (!lp_follow_symlinks(SNUM(conn))) {
3745 0 : return NT_STATUS_ACCESS_DENIED;
3746 : }
3747 :
3748 128 : srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
3749 : total_data, STR_TERMINATE);
3750 :
3751 128 : if (!link_target) {
3752 0 : return NT_STATUS_INVALID_PARAMETER;
3753 : }
3754 :
3755 128 : target_fname = (struct smb_filename) {
3756 : .base_name = link_target,
3757 : };
3758 :
3759 : /* Removes @GMT tokens if any */
3760 128 : status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
3761 128 : if (!NT_STATUS_IS_OK(status)) {
3762 0 : return status;
3763 : }
3764 :
3765 128 : DBG_DEBUG("SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
3766 : new_smb_fname->base_name, link_target);
3767 :
3768 128 : status = parent_pathref(talloc_tos(),
3769 : conn->cwd_fsp,
3770 : new_smb_fname,
3771 : &parent_fname,
3772 : &base_name);
3773 128 : if (!NT_STATUS_IS_OK(status)) {
3774 0 : return status;
3775 : }
3776 :
3777 128 : ret = SMB_VFS_SYMLINKAT(conn,
3778 : &target_fname,
3779 : parent_fname->fsp,
3780 : base_name);
3781 128 : if (ret != 0) {
3782 8 : TALLOC_FREE(parent_fname);
3783 8 : return map_nt_error_from_unix(errno);
3784 : }
3785 :
3786 120 : TALLOC_FREE(parent_fname);
3787 120 : return NT_STATUS_OK;
3788 : }
3789 :
3790 : /****************************************************************************
3791 : Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
3792 : ****************************************************************************/
3793 :
3794 16 : static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
3795 : struct smb_request *req,
3796 : const char *pdata, int total_data,
3797 : struct smb_filename *smb_fname_new)
3798 : {
3799 16 : char *oldname = NULL;
3800 16 : struct files_struct *src_dirfsp = NULL;
3801 16 : struct smb_filename *smb_fname_old = NULL;
3802 16 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
3803 16 : NTTIME old_twrp = 0;
3804 16 : TALLOC_CTX *ctx = talloc_tos();
3805 16 : NTSTATUS status = NT_STATUS_OK;
3806 :
3807 16 : if (!CAN_WRITE(conn)) {
3808 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3809 : }
3810 :
3811 : /* Set a hard link. */
3812 16 : if (total_data == 0) {
3813 0 : return NT_STATUS_INVALID_PARAMETER;
3814 : }
3815 :
3816 16 : if (req->posix_pathnames) {
3817 16 : srvstr_get_path_posix(ctx,
3818 : pdata,
3819 16 : req->flags2,
3820 : &oldname,
3821 : pdata,
3822 : total_data,
3823 : STR_TERMINATE,
3824 : &status);
3825 : } else {
3826 0 : srvstr_get_path(ctx,
3827 : pdata,
3828 0 : req->flags2,
3829 : &oldname,
3830 : pdata,
3831 : total_data,
3832 : STR_TERMINATE,
3833 : &status);
3834 : }
3835 16 : if (!NT_STATUS_IS_OK(status)) {
3836 0 : return status;
3837 : }
3838 :
3839 16 : DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
3840 : smb_fname_str_dbg(smb_fname_new), oldname));
3841 :
3842 16 : if (ucf_flags & UCF_GMT_PATHNAME) {
3843 0 : extract_snapshot_token(oldname, &old_twrp);
3844 : }
3845 16 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &oldname);
3846 16 : if (!NT_STATUS_IS_OK(status)) {
3847 0 : return status;
3848 : }
3849 16 : status = filename_convert_dirfsp(ctx,
3850 : conn,
3851 : oldname,
3852 : ucf_flags,
3853 : old_twrp,
3854 : &src_dirfsp,
3855 : &smb_fname_old);
3856 16 : if (!NT_STATUS_IS_OK(status)) {
3857 0 : return status;
3858 : }
3859 :
3860 16 : return hardlink_internals(ctx,
3861 : conn,
3862 : req,
3863 : false,
3864 : smb_fname_old,
3865 : smb_fname_new);
3866 : }
3867 :
3868 : /****************************************************************************
3869 : Allow a UNIX info mknod.
3870 : ****************************************************************************/
3871 :
3872 2 : static NTSTATUS smb_unix_mknod(connection_struct *conn,
3873 : const char *pdata,
3874 : int total_data,
3875 : struct files_struct *dirfsp,
3876 : const struct smb_filename *smb_fname)
3877 : {
3878 2 : uint32_t file_type = IVAL(pdata,56);
3879 : #if defined(HAVE_MAKEDEV)
3880 2 : uint32_t dev_major = IVAL(pdata,60);
3881 2 : uint32_t dev_minor = IVAL(pdata,68);
3882 : #endif
3883 2 : SMB_DEV_T dev = (SMB_DEV_T)0;
3884 2 : uint32_t raw_unixmode = IVAL(pdata,84);
3885 0 : NTSTATUS status;
3886 0 : mode_t unixmode;
3887 0 : int ret;
3888 2 : struct smb_filename *parent_fname = NULL;
3889 2 : struct smb_filename *atname = NULL;
3890 :
3891 2 : if (total_data < 100) {
3892 0 : return NT_STATUS_INVALID_PARAMETER;
3893 : }
3894 :
3895 2 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3896 : PERM_NEW_FILE, &unixmode);
3897 2 : if (!NT_STATUS_IS_OK(status)) {
3898 0 : return status;
3899 : }
3900 :
3901 : #if defined(HAVE_MAKEDEV)
3902 2 : dev = makedev(dev_major, dev_minor);
3903 : #endif
3904 :
3905 2 : switch (file_type) {
3906 : /* We can't create other objects here. */
3907 0 : case UNIX_TYPE_FILE:
3908 : case UNIX_TYPE_DIR:
3909 : case UNIX_TYPE_SYMLINK:
3910 0 : return NT_STATUS_ACCESS_DENIED;
3911 : #if defined(S_IFIFO)
3912 1 : case UNIX_TYPE_FIFO:
3913 1 : unixmode |= S_IFIFO;
3914 1 : break;
3915 : #endif
3916 : #if defined(S_IFSOCK)
3917 1 : case UNIX_TYPE_SOCKET:
3918 1 : unixmode |= S_IFSOCK;
3919 1 : break;
3920 : #endif
3921 : #if defined(S_IFCHR)
3922 0 : case UNIX_TYPE_CHARDEV:
3923 : /* This is only allowed for root. */
3924 0 : if (get_current_uid(conn) != sec_initial_uid()) {
3925 0 : return NT_STATUS_ACCESS_DENIED;
3926 : }
3927 0 : unixmode |= S_IFCHR;
3928 0 : break;
3929 : #endif
3930 : #if defined(S_IFBLK)
3931 0 : case UNIX_TYPE_BLKDEV:
3932 0 : if (get_current_uid(conn) != sec_initial_uid()) {
3933 0 : return NT_STATUS_ACCESS_DENIED;
3934 : }
3935 0 : unixmode |= S_IFBLK;
3936 0 : break;
3937 : #endif
3938 0 : default:
3939 0 : return NT_STATUS_INVALID_PARAMETER;
3940 : }
3941 :
3942 2 : DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
3943 : "%.0f mode 0%o for file %s\n", (double)dev,
3944 : (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
3945 :
3946 2 : status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
3947 : talloc_tos(),
3948 : smb_fname,
3949 : &parent_fname,
3950 : &atname);
3951 2 : if (!NT_STATUS_IS_OK(status)) {
3952 0 : return status;
3953 : }
3954 :
3955 : /* Ok - do the mknod. */
3956 2 : ret = SMB_VFS_MKNODAT(conn,
3957 : dirfsp,
3958 : atname,
3959 : unixmode,
3960 : dev);
3961 :
3962 2 : if (ret != 0) {
3963 0 : TALLOC_FREE(parent_fname);
3964 0 : return map_nt_error_from_unix(errno);
3965 : }
3966 :
3967 : /* If any of the other "set" calls fail we
3968 : * don't want to end up with a half-constructed mknod.
3969 : */
3970 :
3971 2 : if (lp_inherit_permissions(SNUM(conn))) {
3972 0 : inherit_access_posix_acl(conn,
3973 : dirfsp,
3974 : smb_fname,
3975 : unixmode);
3976 : }
3977 2 : TALLOC_FREE(parent_fname);
3978 :
3979 2 : return NT_STATUS_OK;
3980 : }
3981 :
3982 : /****************************************************************************
3983 : Deal with SMB_SET_FILE_UNIX_BASIC.
3984 : ****************************************************************************/
3985 :
3986 172 : static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
3987 : struct smb_request *req,
3988 : const char *pdata,
3989 : int total_data,
3990 : struct files_struct *dirfsp,
3991 : files_struct *fsp,
3992 : struct smb_filename *smb_fname)
3993 : {
3994 0 : struct smb_file_time ft;
3995 0 : uint32_t raw_unixmode;
3996 0 : mode_t unixmode;
3997 172 : off_t size = 0;
3998 172 : uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
3999 172 : gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
4000 172 : NTSTATUS status = NT_STATUS_OK;
4001 0 : enum perm_type ptype;
4002 172 : files_struct *all_fsps = NULL;
4003 172 : bool modify_mtime = true;
4004 0 : struct file_id id;
4005 0 : SMB_STRUCT_STAT sbuf;
4006 :
4007 172 : if (!CAN_WRITE(conn)) {
4008 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
4009 : }
4010 :
4011 172 : init_smb_file_time(&ft);
4012 :
4013 172 : if (total_data < 100) {
4014 0 : return NT_STATUS_INVALID_PARAMETER;
4015 : }
4016 :
4017 172 : if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
4018 16 : IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
4019 16 : size=IVAL(pdata,0); /* first 8 Bytes are size */
4020 16 : size |= (((off_t)IVAL(pdata,4)) << 32);
4021 : }
4022 :
4023 172 : ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
4024 172 : ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
4025 172 : set_owner = (uid_t)IVAL(pdata,40);
4026 172 : set_grp = (gid_t)IVAL(pdata,48);
4027 172 : raw_unixmode = IVAL(pdata,84);
4028 :
4029 172 : if (VALID_STAT(smb_fname->st)) {
4030 170 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
4031 4 : ptype = PERM_EXISTING_DIR;
4032 : } else {
4033 166 : ptype = PERM_EXISTING_FILE;
4034 : }
4035 : } else {
4036 2 : ptype = PERM_NEW_FILE;
4037 : }
4038 :
4039 172 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
4040 : ptype, &unixmode);
4041 172 : if (!NT_STATUS_IS_OK(status)) {
4042 0 : return status;
4043 : }
4044 :
4045 172 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
4046 : "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
4047 : smb_fname_str_dbg(smb_fname), (double)size,
4048 : (unsigned int)set_owner, (unsigned int)set_grp,
4049 : (int)raw_unixmode));
4050 :
4051 172 : sbuf = smb_fname->st;
4052 :
4053 172 : if (!VALID_STAT(sbuf)) {
4054 : /*
4055 : * The only valid use of this is to create character and block
4056 : * devices, and named pipes. This is deprecated (IMHO) and
4057 : * a new info level should be used for mknod. JRA.
4058 : */
4059 :
4060 2 : if (dirfsp == NULL) {
4061 0 : return NT_STATUS_INVALID_PARAMETER;
4062 : }
4063 :
4064 2 : return smb_unix_mknod(conn,
4065 : pdata,
4066 : total_data,
4067 : dirfsp,
4068 : smb_fname);
4069 : }
4070 :
4071 : #if 1
4072 : /* Horrible backwards compatibility hack as an old server bug
4073 : * allowed a CIFS client bug to remain unnoticed :-(. JRA.
4074 : * */
4075 :
4076 170 : if (!size) {
4077 170 : size = get_file_size_stat(&sbuf);
4078 : }
4079 : #endif
4080 :
4081 : /*
4082 : * Deal with the UNIX specific mode set.
4083 : */
4084 :
4085 170 : if (raw_unixmode != SMB_MODE_NO_CHANGE) {
4086 0 : int ret;
4087 :
4088 38 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4089 24 : DBG_WARNING("Can't set mode on symlink %s\n",
4090 : smb_fname_str_dbg(smb_fname));
4091 24 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4092 : }
4093 :
4094 14 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4095 : "setting mode 0%o for file %s\n",
4096 : (unsigned int)unixmode,
4097 : smb_fname_str_dbg(smb_fname)));
4098 14 : ret = SMB_VFS_FCHMOD(fsp, unixmode);
4099 14 : if (ret != 0) {
4100 2 : return map_nt_error_from_unix(errno);
4101 : }
4102 : }
4103 :
4104 : /*
4105 : * Deal with the UNIX specific uid set.
4106 : */
4107 :
4108 144 : if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
4109 0 : (sbuf.st_ex_uid != set_owner)) {
4110 0 : int ret;
4111 :
4112 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4113 : "changing owner %u for path %s\n",
4114 : (unsigned int)set_owner,
4115 : smb_fname_str_dbg(smb_fname)));
4116 :
4117 0 : if (fsp &&
4118 0 : !fsp->fsp_flags.is_pathref &&
4119 0 : fsp_get_io_fd(fsp) != -1)
4120 : {
4121 0 : ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
4122 : } else {
4123 : /*
4124 : * UNIX extensions calls must always operate
4125 : * on symlinks.
4126 : */
4127 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname,
4128 : set_owner, (gid_t)-1);
4129 : }
4130 :
4131 0 : if (ret != 0) {
4132 0 : status = map_nt_error_from_unix(errno);
4133 0 : return status;
4134 : }
4135 : }
4136 :
4137 : /*
4138 : * Deal with the UNIX specific gid set.
4139 : */
4140 :
4141 144 : if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
4142 0 : (sbuf.st_ex_gid != set_grp)) {
4143 0 : int ret;
4144 :
4145 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4146 : "changing group %u for file %s\n",
4147 : (unsigned int)set_grp,
4148 : smb_fname_str_dbg(smb_fname)));
4149 0 : if (fsp &&
4150 0 : !fsp->fsp_flags.is_pathref &&
4151 0 : fsp_get_io_fd(fsp) != -1)
4152 : {
4153 0 : ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
4154 : } else {
4155 : /*
4156 : * UNIX extensions calls must always operate
4157 : * on symlinks.
4158 : */
4159 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
4160 : set_grp);
4161 : }
4162 0 : if (ret != 0) {
4163 0 : status = map_nt_error_from_unix(errno);
4164 0 : return status;
4165 : }
4166 : }
4167 :
4168 : /* Deal with any size changes. */
4169 :
4170 144 : if (S_ISREG(sbuf.st_ex_mode)) {
4171 140 : status = smb_set_file_size(conn, req,
4172 : fsp,
4173 : smb_fname,
4174 : &sbuf,
4175 : size,
4176 : false);
4177 140 : if (!NT_STATUS_IS_OK(status)) {
4178 0 : return status;
4179 : }
4180 : }
4181 :
4182 : /* Deal with any time changes. */
4183 144 : if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
4184 : /* No change, don't cancel anything. */
4185 144 : return status;
4186 : }
4187 :
4188 0 : id = vfs_file_id_from_sbuf(conn, &sbuf);
4189 0 : for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
4190 0 : all_fsps = file_find_di_next(all_fsps, true)) {
4191 : /*
4192 : * We're setting the time explicitly for UNIX.
4193 : * Cancel any pending changes over all handles.
4194 : */
4195 0 : all_fsps->fsp_flags.update_write_time_on_close = false;
4196 0 : TALLOC_FREE(all_fsps->update_write_time_event);
4197 : }
4198 :
4199 : /*
4200 : * Override the "setting_write_time"
4201 : * parameter here as it almost does what
4202 : * we need. Just remember if we modified
4203 : * mtime and send the notify ourselves.
4204 : */
4205 0 : if (is_omit_timespec(&ft.mtime)) {
4206 0 : modify_mtime = false;
4207 : }
4208 :
4209 0 : status = smb_set_file_time(conn,
4210 : fsp,
4211 : smb_fname,
4212 : &ft,
4213 : false);
4214 0 : if (modify_mtime) {
4215 0 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
4216 0 : FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
4217 : }
4218 0 : return status;
4219 : }
4220 :
4221 : /****************************************************************************
4222 : Deal with SMB_SET_FILE_UNIX_INFO2.
4223 : ****************************************************************************/
4224 :
4225 140 : static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
4226 : struct smb_request *req,
4227 : const char *pdata,
4228 : int total_data,
4229 : struct files_struct *dirfsp,
4230 : files_struct *fsp,
4231 : struct smb_filename *smb_fname)
4232 : {
4233 0 : NTSTATUS status;
4234 0 : uint32_t smb_fflags;
4235 0 : uint32_t smb_fmask;
4236 :
4237 140 : if (!CAN_WRITE(conn)) {
4238 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
4239 : }
4240 :
4241 140 : if (total_data < 116) {
4242 0 : return NT_STATUS_INVALID_PARAMETER;
4243 : }
4244 :
4245 : /* Start by setting all the fields that are common between UNIX_BASIC
4246 : * and UNIX_INFO2.
4247 : */
4248 140 : status = smb_set_file_unix_basic(conn,
4249 : req,
4250 : pdata,
4251 : total_data,
4252 : dirfsp,
4253 : fsp,
4254 : smb_fname);
4255 140 : if (!NT_STATUS_IS_OK(status)) {
4256 8 : return status;
4257 : }
4258 :
4259 132 : smb_fflags = IVAL(pdata, 108);
4260 132 : smb_fmask = IVAL(pdata, 112);
4261 :
4262 : /* NB: We should only attempt to alter the file flags if the client
4263 : * sends a non-zero mask.
4264 : */
4265 132 : if (smb_fmask != 0) {
4266 128 : int stat_fflags = 0;
4267 :
4268 128 : if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
4269 : smb_fmask, &stat_fflags)) {
4270 : /* Client asked to alter a flag we don't understand. */
4271 128 : return NT_STATUS_INVALID_PARAMETER;
4272 : }
4273 :
4274 0 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4275 0 : DBG_WARNING("Can't change flags on symlink %s\n",
4276 : smb_fname_str_dbg(smb_fname));
4277 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4278 : }
4279 0 : if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
4280 0 : return map_nt_error_from_unix(errno);
4281 : }
4282 : }
4283 :
4284 : /* XXX: need to add support for changing the create_time here. You
4285 : * can do this for paths on Darwin with setattrlist(2). The right way
4286 : * to hook this up is probably by extending the VFS utimes interface.
4287 : */
4288 :
4289 4 : return NT_STATUS_OK;
4290 : }
4291 :
4292 : /****************************************************************************
4293 : Deal with SMB_SET_POSIX_ACL.
4294 : ****************************************************************************/
4295 :
4296 16 : static NTSTATUS smb_set_posix_acl(connection_struct *conn,
4297 : struct smb_request *req,
4298 : const char *pdata,
4299 : int total_data_in,
4300 : files_struct *fsp,
4301 : struct smb_filename *smb_fname)
4302 : {
4303 : #if !defined(HAVE_POSIX_ACLS)
4304 : return NT_STATUS_INVALID_LEVEL;
4305 : #else
4306 0 : uint16_t posix_acl_version;
4307 0 : uint16_t num_file_acls;
4308 0 : uint16_t num_def_acls;
4309 16 : bool valid_file_acls = true;
4310 16 : bool valid_def_acls = true;
4311 0 : NTSTATUS status;
4312 0 : unsigned int size_needed;
4313 0 : unsigned int total_data;
4314 16 : bool close_fsp = false;
4315 :
4316 16 : if (total_data_in < 0) {
4317 0 : status = NT_STATUS_INVALID_PARAMETER;
4318 0 : goto out;
4319 : }
4320 :
4321 16 : total_data = total_data_in;
4322 :
4323 16 : if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
4324 0 : status = NT_STATUS_INVALID_PARAMETER;
4325 0 : goto out;
4326 : }
4327 16 : posix_acl_version = SVAL(pdata,0);
4328 16 : num_file_acls = SVAL(pdata,2);
4329 16 : num_def_acls = SVAL(pdata,4);
4330 :
4331 16 : if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4332 4 : valid_file_acls = false;
4333 4 : num_file_acls = 0;
4334 : }
4335 :
4336 16 : if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4337 0 : valid_def_acls = false;
4338 0 : num_def_acls = 0;
4339 : }
4340 :
4341 16 : if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
4342 8 : status = NT_STATUS_INVALID_PARAMETER;
4343 8 : goto out;
4344 : }
4345 :
4346 : /* Wrap checks. */
4347 0 : if (num_file_acls + num_def_acls < num_file_acls) {
4348 : status = NT_STATUS_INVALID_PARAMETER;
4349 : goto out;
4350 : }
4351 :
4352 8 : size_needed = num_file_acls + num_def_acls;
4353 :
4354 : /*
4355 : * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
4356 : * than UINT_MAX, so check by division.
4357 : */
4358 8 : if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
4359 0 : status = NT_STATUS_INVALID_PARAMETER;
4360 0 : goto out;
4361 : }
4362 :
4363 8 : size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
4364 8 : if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
4365 0 : status = NT_STATUS_INVALID_PARAMETER;
4366 0 : goto out;
4367 : }
4368 8 : size_needed += SMB_POSIX_ACL_HEADER_SIZE;
4369 :
4370 8 : if (total_data < size_needed) {
4371 0 : status = NT_STATUS_INVALID_PARAMETER;
4372 0 : goto out;
4373 : }
4374 :
4375 : /*
4376 : * Ensure we always operate on a file descriptor, not just
4377 : * the filename.
4378 : */
4379 8 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
4380 8 : uint32_t access_mask = SEC_STD_WRITE_OWNER|
4381 : SEC_STD_WRITE_DAC|
4382 : SEC_STD_READ_CONTROL|
4383 : FILE_READ_ATTRIBUTES|
4384 : FILE_WRITE_ATTRIBUTES;
4385 :
4386 8 : status = get_posix_fsp(conn,
4387 : req,
4388 : smb_fname,
4389 : access_mask,
4390 : &fsp);
4391 :
4392 8 : if (!NT_STATUS_IS_OK(status)) {
4393 4 : goto out;
4394 : }
4395 4 : close_fsp = true;
4396 : }
4397 :
4398 : /* Here we know fsp != NULL */
4399 4 : SMB_ASSERT(fsp != NULL);
4400 :
4401 4 : status = refuse_symlink_fsp(fsp);
4402 4 : if (!NT_STATUS_IS_OK(status)) {
4403 0 : goto out;
4404 : }
4405 :
4406 : /* If we have a default acl, this *must* be a directory. */
4407 4 : if (valid_def_acls && !fsp->fsp_flags.is_directory) {
4408 0 : DBG_INFO("Can't set default acls on "
4409 : "non-directory %s\n",
4410 : fsp_str_dbg(fsp));
4411 0 : return NT_STATUS_INVALID_HANDLE;
4412 : }
4413 :
4414 4 : DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
4415 : "num_def_acls = %"PRIu16"\n",
4416 : fsp_str_dbg(fsp),
4417 : num_file_acls,
4418 : num_def_acls);
4419 :
4420 : /* Move pdata to the start of the file ACL entries. */
4421 4 : pdata += SMB_POSIX_ACL_HEADER_SIZE;
4422 :
4423 4 : if (valid_file_acls) {
4424 0 : status = set_unix_posix_acl(conn,
4425 : fsp,
4426 : num_file_acls,
4427 : pdata);
4428 0 : if (!NT_STATUS_IS_OK(status)) {
4429 0 : goto out;
4430 : }
4431 : }
4432 :
4433 : /* Move pdata to the start of the default ACL entries. */
4434 4 : pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
4435 :
4436 4 : if (valid_def_acls) {
4437 4 : status = set_unix_posix_default_acl(conn,
4438 : fsp,
4439 : num_def_acls,
4440 : pdata);
4441 4 : if (!NT_STATUS_IS_OK(status)) {
4442 0 : goto out;
4443 : }
4444 : }
4445 :
4446 4 : status = NT_STATUS_OK;
4447 :
4448 16 : out:
4449 :
4450 16 : if (close_fsp) {
4451 4 : (void)close_file_free(req, &fsp, NORMAL_CLOSE);
4452 : }
4453 16 : return status;
4454 : #endif
4455 : }
4456 :
4457 1410 : static void call_trans2setpathinfo(
4458 : connection_struct *conn,
4459 : struct smb_request *req,
4460 : char **pparams,
4461 : int total_params,
4462 : char **ppdata,
4463 : int total_data,
4464 : unsigned int max_data_bytes)
4465 : {
4466 12 : uint16_t info_level;
4467 1410 : struct smb_filename *smb_fname = NULL;
4468 1410 : struct files_struct *dirfsp = NULL;
4469 1410 : struct files_struct *fsp = NULL;
4470 1410 : char *params = *pparams;
4471 1410 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4472 1410 : NTTIME twrp = 0;
4473 1410 : char *fname = NULL;
4474 12 : bool info_level_handled;
4475 1410 : int data_return_size = 0;
4476 12 : NTSTATUS status;
4477 :
4478 1410 : if (params == NULL) {
4479 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4480 0 : return;
4481 : }
4482 :
4483 : /* set path info */
4484 1410 : if (total_params < 7) {
4485 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4486 0 : return;
4487 : }
4488 :
4489 1410 : info_level = SVAL(params,0);
4490 :
4491 1410 : if (INFO_LEVEL_IS_UNIX(info_level)) {
4492 1112 : if (!lp_smb1_unix_extensions()) {
4493 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4494 0 : return;
4495 : }
4496 1112 : if (!req->posix_pathnames) {
4497 6 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4498 6 : return;
4499 : }
4500 : }
4501 :
4502 1404 : if (req->posix_pathnames) {
4503 1210 : srvstr_get_path_posix(req,
4504 : params,
4505 1210 : req->flags2,
4506 : &fname,
4507 1210 : ¶ms[6],
4508 1210 : total_params - 6,
4509 : STR_TERMINATE,
4510 : &status);
4511 : } else {
4512 194 : srvstr_get_path(req,
4513 : params,
4514 194 : req->flags2,
4515 : &fname,
4516 194 : ¶ms[6],
4517 194 : total_params - 6,
4518 : STR_TERMINATE,
4519 : &status);
4520 : }
4521 1404 : if (!NT_STATUS_IS_OK(status)) {
4522 0 : reply_nterror(req, status);
4523 0 : return;
4524 : }
4525 :
4526 1404 : DBG_NOTICE("fname=%s info_level=%d totdata=%d\n",
4527 : fname,
4528 : info_level,
4529 : total_data);
4530 :
4531 1404 : if (ucf_flags & UCF_GMT_PATHNAME) {
4532 0 : extract_snapshot_token(fname, &twrp);
4533 : }
4534 1404 : status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
4535 1404 : if (!NT_STATUS_IS_OK(status)) {
4536 0 : reply_nterror(req, status);
4537 0 : return;
4538 : }
4539 1404 : status = filename_convert_dirfsp(req,
4540 : conn,
4541 : fname,
4542 : ucf_flags,
4543 : twrp,
4544 : &dirfsp,
4545 : &smb_fname);
4546 1404 : if (!NT_STATUS_IS_OK(status)) {
4547 60 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4548 0 : reply_botherror(req,
4549 : NT_STATUS_PATH_NOT_COVERED,
4550 : ERRSRV, ERRbadpath);
4551 0 : return;
4552 : }
4553 60 : reply_nterror(req, status);
4554 60 : return;
4555 : }
4556 :
4557 1344 : info_level_handled = true; /* Untouched in switch cases below */
4558 :
4559 1344 : switch (info_level) {
4560 :
4561 294 : default:
4562 294 : info_level_handled = false;
4563 294 : break;
4564 :
4565 174 : case SMB_POSIX_PATH_OPEN:
4566 174 : status = smb_posix_open(conn,
4567 : req,
4568 : ppdata,
4569 : total_data,
4570 : dirfsp,
4571 : smb_fname,
4572 : &data_return_size);
4573 174 : break;
4574 :
4575 532 : case SMB_POSIX_PATH_UNLINK:
4576 532 : status = smb_posix_unlink(conn,
4577 : req,
4578 : *ppdata,
4579 : total_data,
4580 : dirfsp,
4581 : smb_fname);
4582 532 : break;
4583 :
4584 128 : case SMB_SET_FILE_UNIX_LINK:
4585 128 : status = smb_set_file_unix_link(
4586 : conn, req, *ppdata, total_data, smb_fname);
4587 128 : break;
4588 :
4589 16 : case SMB_SET_FILE_UNIX_HLINK:
4590 16 : status = smb_set_file_unix_hlink(
4591 : conn, req, *ppdata, total_data, smb_fname);
4592 16 : break;
4593 :
4594 32 : case SMB_SET_FILE_UNIX_BASIC:
4595 32 : status = smb_set_file_unix_basic(conn,
4596 : req,
4597 : *ppdata,
4598 : total_data,
4599 : dirfsp,
4600 32 : smb_fname->fsp,
4601 : smb_fname);
4602 32 : break;
4603 :
4604 140 : case SMB_SET_FILE_UNIX_INFO2:
4605 140 : status = smb_set_file_unix_info2(conn,
4606 : req,
4607 : *ppdata,
4608 : total_data,
4609 : dirfsp,
4610 140 : smb_fname->fsp,
4611 : smb_fname);
4612 140 : break;
4613 16 : case SMB_SET_POSIX_ACL:
4614 16 : status = smb_set_posix_acl(
4615 : conn, req, *ppdata, total_data, NULL, smb_fname);
4616 16 : break;
4617 : }
4618 :
4619 1332 : if (info_level_handled) {
4620 1038 : handle_trans2setfilepathinfo_result(
4621 : conn,
4622 : req,
4623 : info_level,
4624 : status,
4625 : *ppdata,
4626 : data_return_size,
4627 : max_data_bytes);
4628 1038 : return;
4629 : }
4630 :
4631 : /*
4632 : * smb_fname->fsp may be NULL if smb_fname points at a symlink
4633 : * and we're in POSIX context, so be careful when using fsp
4634 : * below, it can still be NULL.
4635 : */
4636 306 : fsp = smb_fname->fsp;
4637 :
4638 306 : status = smbd_do_setfilepathinfo(
4639 : conn,
4640 : req,
4641 : req,
4642 : info_level,
4643 : fsp,
4644 : smb_fname,
4645 : ppdata,
4646 : total_data,
4647 : &data_return_size);
4648 :
4649 306 : handle_trans2setfilepathinfo_result(
4650 : conn,
4651 : req,
4652 : info_level,
4653 : status,
4654 : *ppdata,
4655 : data_return_size,
4656 : max_data_bytes);
4657 : }
4658 :
4659 4265 : static void call_trans2setfileinfo(
4660 : connection_struct *conn,
4661 : struct smb_request *req,
4662 : char **pparams,
4663 : int total_params,
4664 : char **ppdata,
4665 : int total_data,
4666 : unsigned int max_data_bytes)
4667 : {
4668 4265 : char *pdata = *ppdata;
4669 537 : uint16_t info_level;
4670 4265 : struct smb_filename *smb_fname = NULL;
4671 4265 : struct files_struct *fsp = NULL;
4672 4265 : char *params = *pparams;
4673 4265 : int data_return_size = 0;
4674 537 : bool info_level_handled;
4675 537 : NTSTATUS status;
4676 537 : int ret;
4677 :
4678 4265 : if (params == NULL) {
4679 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4680 0 : return;
4681 : }
4682 4265 : if (total_params < 4) {
4683 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4684 0 : return;
4685 : }
4686 :
4687 4265 : fsp = file_fsp(req, SVAL(params,0));
4688 : /* Basic check for non-null fsp. */
4689 4265 : if (!check_fsp_open(conn, req, fsp)) {
4690 0 : return;
4691 : }
4692 4265 : info_level = SVAL(params,2);
4693 :
4694 4265 : if (INFO_LEVEL_IS_UNIX(info_level)) {
4695 36 : if (!lp_smb1_unix_extensions()) {
4696 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4697 0 : return;
4698 : }
4699 36 : if (!req->posix_pathnames) {
4700 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4701 0 : return;
4702 : }
4703 : }
4704 :
4705 4265 : smb_fname = fsp->fsp_name;
4706 :
4707 4265 : DBG_NOTICE("fnum=%s fname=%s info_level=%d totdata=%d\n",
4708 : fsp_fnum_dbg(fsp),
4709 : fsp_str_dbg(fsp),
4710 : info_level,
4711 : total_data);
4712 :
4713 4265 : if (fsp_get_pathref_fd(fsp) == -1) {
4714 : /*
4715 : * This is actually a SETFILEINFO on a directory
4716 : * handle (returned from an NT SMB). NT5.0 seems
4717 : * to do this call. JRA.
4718 : */
4719 0 : ret = vfs_stat(conn, smb_fname);
4720 0 : if (ret != 0) {
4721 0 : DBG_NOTICE("vfs_stat of %s failed (%s)\n",
4722 : smb_fname_str_dbg(smb_fname),
4723 : strerror(errno));
4724 0 : reply_nterror(req, map_nt_error_from_unix(errno));
4725 0 : return;
4726 : }
4727 4265 : } else if (fsp->print_file) {
4728 : /*
4729 : * Doing a DELETE_ON_CLOSE should cancel a print job.
4730 : */
4731 2 : if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) &&
4732 2 : CVAL(pdata,0)) {
4733 :
4734 2 : fsp->fsp_flags.delete_on_close = true;
4735 :
4736 2 : DBG_NOTICE("Cancelling print job (%s)\n",
4737 : fsp_str_dbg(fsp));
4738 :
4739 2 : SSVAL(params,0,0);
4740 2 : send_trans2_replies(
4741 : conn,
4742 : req,
4743 2 : NT_STATUS_OK,
4744 : params,
4745 : 2,
4746 : *ppdata, 0,
4747 : max_data_bytes);
4748 2 : return;
4749 : } else {
4750 0 : reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
4751 0 : return;
4752 : }
4753 : } else {
4754 : /*
4755 : * Original code - this is an open file.
4756 : */
4757 4263 : status = vfs_stat_fsp(fsp);
4758 4263 : if (!NT_STATUS_IS_OK(status)) {
4759 0 : DBG_NOTICE("fstat of %s failed (%s)\n",
4760 : fsp_fnum_dbg(fsp),
4761 : nt_errstr(status));
4762 0 : reply_nterror(req, status);
4763 0 : return;
4764 : }
4765 : }
4766 :
4767 4263 : info_level_handled = true; /* Untouched in switch cases below */
4768 :
4769 4263 : switch (info_level) {
4770 :
4771 3690 : default:
4772 3690 : info_level_handled = false;
4773 3690 : break;
4774 :
4775 0 : case SMB_SET_FILE_UNIX_BASIC:
4776 0 : status = smb_set_file_unix_basic(conn,
4777 : req,
4778 : pdata,
4779 : total_data,
4780 : NULL,
4781 : fsp,
4782 : smb_fname);
4783 0 : break;
4784 :
4785 0 : case SMB_SET_FILE_UNIX_INFO2:
4786 0 : status = smb_set_file_unix_info2(conn,
4787 : req,
4788 : pdata,
4789 : total_data,
4790 : NULL,
4791 : fsp,
4792 : smb_fname);
4793 0 : break;
4794 :
4795 36 : case SMB_SET_POSIX_LOCK:
4796 36 : status = smb_set_posix_lock(
4797 : conn, req, *ppdata, total_data, fsp);
4798 36 : break;
4799 : }
4800 :
4801 3726 : if (info_level_handled) {
4802 36 : handle_trans2setfilepathinfo_result(
4803 : conn,
4804 : req,
4805 : info_level,
4806 : status,
4807 : *ppdata,
4808 : data_return_size,
4809 : max_data_bytes);
4810 36 : return;
4811 : }
4812 :
4813 4227 : status = smbd_do_setfilepathinfo(
4814 : conn,
4815 : req,
4816 : req,
4817 : info_level,
4818 : fsp,
4819 : smb_fname,
4820 : ppdata,
4821 : total_data,
4822 : &data_return_size);
4823 :
4824 4227 : handle_trans2setfilepathinfo_result(
4825 : conn,
4826 : req,
4827 : info_level,
4828 : status,
4829 : *ppdata,
4830 : data_return_size,
4831 : max_data_bytes);
4832 : }
4833 :
4834 : /****************************************************************************
4835 : Reply to a TRANS2_MKDIR (make directory with extended attributes).
4836 : ****************************************************************************/
4837 :
4838 23 : static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
4839 : char **pparams, int total_params,
4840 : char **ppdata, int total_data,
4841 : unsigned int max_data_bytes)
4842 : {
4843 23 : struct files_struct *dirfsp = NULL;
4844 23 : struct files_struct *fsp = NULL;
4845 23 : struct smb_filename *smb_dname = NULL;
4846 23 : char *params = *pparams;
4847 23 : char *pdata = *ppdata;
4848 23 : char *directory = NULL;
4849 23 : NTSTATUS status = NT_STATUS_OK;
4850 23 : struct ea_list *ea_list = NULL;
4851 23 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4852 23 : NTTIME twrp = 0;
4853 23 : TALLOC_CTX *ctx = talloc_tos();
4854 :
4855 23 : if (!CAN_WRITE(conn)) {
4856 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4857 0 : return;
4858 : }
4859 :
4860 23 : if (total_params < 5) {
4861 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4862 0 : return;
4863 : }
4864 :
4865 23 : if (req->posix_pathnames) {
4866 0 : srvstr_get_path_posix(ctx,
4867 : params,
4868 0 : req->flags2,
4869 : &directory,
4870 0 : ¶ms[4],
4871 0 : total_params - 4,
4872 : STR_TERMINATE,
4873 : &status);
4874 : } else {
4875 23 : srvstr_get_path(ctx,
4876 : params,
4877 23 : req->flags2,
4878 : &directory,
4879 23 : ¶ms[4],
4880 23 : total_params - 4,
4881 : STR_TERMINATE,
4882 : &status);
4883 : }
4884 23 : if (!NT_STATUS_IS_OK(status)) {
4885 0 : reply_nterror(req, status);
4886 0 : return;
4887 : }
4888 :
4889 23 : DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
4890 :
4891 23 : if (ucf_flags & UCF_GMT_PATHNAME) {
4892 0 : extract_snapshot_token(directory, &twrp);
4893 : }
4894 23 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &directory);
4895 23 : if (!NT_STATUS_IS_OK(status)) {
4896 0 : reply_nterror(req, status);
4897 0 : goto out;
4898 : }
4899 23 : status = filename_convert_dirfsp(ctx,
4900 : conn,
4901 : directory,
4902 : ucf_flags,
4903 : twrp,
4904 : &dirfsp,
4905 : &smb_dname);
4906 23 : if (!NT_STATUS_IS_OK(status)) {
4907 5 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4908 0 : reply_botherror(req,
4909 : NT_STATUS_PATH_NOT_COVERED,
4910 : ERRSRV, ERRbadpath);
4911 0 : return;
4912 : }
4913 5 : reply_nterror(req, status);
4914 5 : return;
4915 : }
4916 :
4917 : /*
4918 : * OS/2 workplace shell seems to send SET_EA requests of "null"
4919 : * length (4 bytes containing IVAL 4).
4920 : * They seem to have no effect. Bug #3212. JRA.
4921 : */
4922 :
4923 18 : if (total_data && (total_data != 4)) {
4924 : /* Any data in this call is an EA list. */
4925 5 : if (total_data < 10) {
4926 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4927 0 : goto out;
4928 : }
4929 :
4930 5 : if (IVAL(pdata,0) > total_data) {
4931 0 : DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
4932 : IVAL(pdata,0), (unsigned int)total_data));
4933 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4934 0 : goto out;
4935 : }
4936 :
4937 5 : ea_list = read_ea_list(talloc_tos(), pdata + 4,
4938 5 : total_data - 4);
4939 5 : if (!ea_list) {
4940 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4941 0 : goto out;
4942 : }
4943 :
4944 5 : if (!lp_ea_support(SNUM(conn))) {
4945 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
4946 0 : goto out;
4947 : }
4948 : }
4949 : /* If total_data == 4 Windows doesn't care what values
4950 : * are placed in that field, it just ignores them.
4951 : * The System i QNTC IBM SMB client puts bad values here,
4952 : * so ignore them. */
4953 :
4954 18 : status = SMB_VFS_CREATE_FILE(
4955 : conn, /* conn */
4956 : req, /* req */
4957 : dirfsp, /* dirfsp */
4958 : smb_dname, /* fname */
4959 : MAXIMUM_ALLOWED_ACCESS, /* access_mask */
4960 : FILE_SHARE_NONE, /* share_access */
4961 : FILE_CREATE, /* create_disposition*/
4962 : FILE_DIRECTORY_FILE, /* create_options */
4963 : FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
4964 : 0, /* oplock_request */
4965 : NULL, /* lease */
4966 : 0, /* allocation_size */
4967 : 0, /* private_flags */
4968 : NULL, /* sd */
4969 : NULL, /* ea_list */
4970 : &fsp, /* result */
4971 : NULL, /* pinfo */
4972 : NULL, NULL); /* create context */
4973 18 : if (!NT_STATUS_IS_OK(status)) {
4974 8 : reply_nterror(req, status);
4975 8 : goto out;
4976 : }
4977 :
4978 : /* Try and set any given EA. */
4979 10 : if (ea_list) {
4980 5 : status = set_ea(conn, fsp, ea_list);
4981 5 : if (!NT_STATUS_IS_OK(status)) {
4982 0 : reply_nterror(req, status);
4983 0 : goto out;
4984 : }
4985 : }
4986 :
4987 : /* Realloc the parameter and data sizes */
4988 10 : *pparams = (char *)SMB_REALLOC(*pparams,2);
4989 10 : if(*pparams == NULL) {
4990 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4991 0 : goto out;
4992 : }
4993 10 : params = *pparams;
4994 :
4995 10 : SSVAL(params,0,0);
4996 :
4997 10 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
4998 :
4999 18 : out:
5000 18 : if (fsp != NULL) {
5001 10 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
5002 : }
5003 18 : TALLOC_FREE(smb_dname);
5004 : }
5005 :
5006 : /****************************************************************************
5007 : Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
5008 : We don't actually do this - we just send a null response.
5009 : ****************************************************************************/
5010 :
5011 0 : static void call_trans2findnotifyfirst(connection_struct *conn,
5012 : struct smb_request *req,
5013 : char **pparams, int total_params,
5014 : char **ppdata, int total_data,
5015 : unsigned int max_data_bytes)
5016 : {
5017 0 : char *params = *pparams;
5018 0 : uint16_t info_level;
5019 :
5020 0 : if (total_params < 6) {
5021 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5022 0 : return;
5023 : }
5024 :
5025 0 : info_level = SVAL(params,4);
5026 0 : DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
5027 :
5028 0 : switch (info_level) {
5029 0 : case 1:
5030 : case 2:
5031 0 : break;
5032 0 : default:
5033 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5034 0 : return;
5035 : }
5036 :
5037 : /* Realloc the parameter and data sizes */
5038 0 : *pparams = (char *)SMB_REALLOC(*pparams,6);
5039 0 : if (*pparams == NULL) {
5040 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5041 0 : return;
5042 : }
5043 0 : params = *pparams;
5044 :
5045 0 : SSVAL(params,0,fnf_handle);
5046 0 : SSVAL(params,2,0); /* No changes */
5047 0 : SSVAL(params,4,0); /* No EA errors */
5048 :
5049 0 : fnf_handle++;
5050 :
5051 0 : if(fnf_handle == 0)
5052 0 : fnf_handle = 257;
5053 :
5054 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
5055 : }
5056 :
5057 : /****************************************************************************
5058 : Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
5059 : changes). Currently this does nothing.
5060 : ****************************************************************************/
5061 :
5062 0 : static void call_trans2findnotifynext(connection_struct *conn,
5063 : struct smb_request *req,
5064 : char **pparams, int total_params,
5065 : char **ppdata, int total_data,
5066 : unsigned int max_data_bytes)
5067 : {
5068 0 : char *params = *pparams;
5069 :
5070 0 : DEBUG(3,("call_trans2findnotifynext\n"));
5071 :
5072 : /* Realloc the parameter and data sizes */
5073 0 : *pparams = (char *)SMB_REALLOC(*pparams,4);
5074 0 : if (*pparams == NULL) {
5075 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5076 0 : return;
5077 : }
5078 0 : params = *pparams;
5079 :
5080 0 : SSVAL(params,0,0); /* No changes */
5081 0 : SSVAL(params,2,0); /* No EA errors */
5082 :
5083 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
5084 : }
5085 :
5086 : /****************************************************************************
5087 : Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
5088 : ****************************************************************************/
5089 :
5090 4370 : static void call_trans2getdfsreferral(connection_struct *conn,
5091 : struct smb_request *req,
5092 : char **pparams, int total_params,
5093 : char **ppdata, int total_data,
5094 : unsigned int max_data_bytes)
5095 : {
5096 4370 : char *params = *pparams;
5097 4370 : char *pathname = NULL;
5098 4370 : int reply_size = 0;
5099 0 : int max_referral_level;
5100 4370 : NTSTATUS status = NT_STATUS_OK;
5101 4370 : TALLOC_CTX *ctx = talloc_tos();
5102 :
5103 4370 : DEBUG(10,("call_trans2getdfsreferral\n"));
5104 :
5105 4370 : if (!IS_IPC(conn)) {
5106 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5107 0 : return;
5108 : }
5109 :
5110 4370 : if (total_params < 3) {
5111 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5112 0 : return;
5113 : }
5114 :
5115 4370 : max_referral_level = SVAL(params,0);
5116 :
5117 4370 : if(!lp_host_msdfs()) {
5118 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5119 0 : return;
5120 : }
5121 :
5122 4370 : srvstr_pull_talloc(ctx, params, req->flags2, &pathname, ¶ms[2],
5123 : total_params - 2, STR_TERMINATE);
5124 4370 : if (!pathname) {
5125 0 : reply_nterror(req, NT_STATUS_NOT_FOUND);
5126 0 : return;
5127 : }
5128 4370 : reply_size = setup_dfs_referral(
5129 : conn, pathname, max_referral_level, ppdata, &status);
5130 4370 : if (reply_size < 0) {
5131 3068 : reply_nterror(req, status);
5132 3068 : return;
5133 : }
5134 :
5135 1302 : SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
5136 : SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
5137 1302 : send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
5138 : }
5139 :
5140 : #define LMCAT_SPL 0x53
5141 : #define LMFUNC_GETJOBID 0x60
5142 :
5143 : /****************************************************************************
5144 : Reply to a TRANS2_IOCTL - used for OS/2 printing.
5145 : ****************************************************************************/
5146 :
5147 0 : static void call_trans2ioctl(connection_struct *conn,
5148 : struct smb_request *req,
5149 : char **pparams, int total_params,
5150 : char **ppdata, int total_data,
5151 : unsigned int max_data_bytes)
5152 : {
5153 0 : const struct loadparm_substitution *lp_sub =
5154 0 : loadparm_s3_global_substitution();
5155 0 : char *pdata = *ppdata;
5156 0 : files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
5157 0 : NTSTATUS status;
5158 0 : size_t len = 0;
5159 :
5160 : /* check for an invalid fid before proceeding */
5161 :
5162 0 : if (!fsp) {
5163 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5164 0 : return;
5165 : }
5166 :
5167 0 : if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
5168 0 : && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5169 0 : *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
5170 0 : if (*ppdata == NULL) {
5171 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5172 0 : return;
5173 : }
5174 0 : pdata = *ppdata;
5175 :
5176 : /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
5177 : CAN ACCEPT THIS IN UNICODE. JRA. */
5178 :
5179 : /* Job number */
5180 0 : SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));
5181 :
5182 0 : status = srvstr_push(pdata, req->flags2, pdata + 2,
5183 : lp_netbios_name(), 15,
5184 : STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
5185 0 : if (!NT_STATUS_IS_OK(status)) {
5186 0 : reply_nterror(req, status);
5187 0 : return;
5188 : }
5189 0 : status = srvstr_push(pdata, req->flags2, pdata+18,
5190 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13,
5191 : STR_ASCII|STR_TERMINATE, &len); /* Service name */
5192 0 : if (!NT_STATUS_IS_OK(status)) {
5193 0 : reply_nterror(req, status);
5194 0 : return;
5195 : }
5196 0 : send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
5197 : max_data_bytes);
5198 0 : return;
5199 : }
5200 :
5201 0 : DEBUG(2,("Unknown TRANS2_IOCTL\n"));
5202 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5203 : }
5204 :
5205 37801 : static void handle_trans2(connection_struct *conn, struct smb_request *req,
5206 : struct trans_state *state)
5207 : {
5208 37801 : struct smbXsrv_connection *xconn = req->xconn;
5209 :
5210 37801 : if (xconn->protocol >= PROTOCOL_NT1) {
5211 37799 : req->flags2 |= 0x40; /* IS_LONG_NAME */
5212 37799 : SSVAL((discard_const_p(uint8_t, req->inbuf)),smb_flg2,req->flags2);
5213 : }
5214 :
5215 37801 : if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
5216 0 : if (state->call != TRANSACT2_QFSINFO &&
5217 0 : state->call != TRANSACT2_SETFSINFO) {
5218 0 : DEBUG(0,("handle_trans2: encryption required "
5219 : "with call 0x%x\n",
5220 : (unsigned int)state->call));
5221 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5222 0 : return;
5223 : }
5224 : }
5225 :
5226 : /* Now we must call the relevant TRANS2 function */
5227 37801 : switch(state->call) {
5228 98 : case TRANSACT2_OPEN:
5229 : {
5230 98 : START_PROFILE(Trans2_open);
5231 98 : call_trans2open(conn, req,
5232 98 : &state->param, state->total_param,
5233 98 : &state->data, state->total_data,
5234 : state->max_data_return);
5235 98 : END_PROFILE(Trans2_open);
5236 80 : break;
5237 : }
5238 :
5239 8736 : case TRANSACT2_FINDFIRST:
5240 : {
5241 8736 : START_PROFILE(Trans2_findfirst);
5242 8736 : call_trans2findfirst(conn, req,
5243 8736 : &state->param, state->total_param,
5244 8736 : &state->data, state->total_data,
5245 : state->max_data_return);
5246 8736 : END_PROFILE(Trans2_findfirst);
5247 8561 : break;
5248 : }
5249 :
5250 1724 : case TRANSACT2_FINDNEXT:
5251 : {
5252 1724 : START_PROFILE(Trans2_findnext);
5253 1724 : call_trans2findnext(conn, req,
5254 1724 : &state->param, state->total_param,
5255 1724 : &state->data, state->total_data,
5256 : state->max_data_return);
5257 1724 : END_PROFILE(Trans2_findnext);
5258 1724 : break;
5259 : }
5260 :
5261 1375 : case TRANSACT2_QFSINFO:
5262 : {
5263 1375 : START_PROFILE(Trans2_qfsinfo);
5264 1375 : call_trans2qfsinfo(conn, req,
5265 1375 : &state->param, state->total_param,
5266 1375 : &state->data, state->total_data,
5267 : state->max_data_return);
5268 1375 : END_PROFILE(Trans2_qfsinfo);
5269 1375 : break;
5270 : }
5271 :
5272 1366 : case TRANSACT2_SETFSINFO:
5273 : {
5274 1366 : START_PROFILE(Trans2_setfsinfo);
5275 1366 : call_trans2setfsinfo(conn, req,
5276 1366 : &state->param, state->total_param,
5277 1366 : &state->data, state->total_data,
5278 : state->max_data_return);
5279 1366 : END_PROFILE(Trans2_setfsinfo);
5280 1366 : break;
5281 : }
5282 :
5283 10817 : case TRANSACT2_QPATHINFO:
5284 : {
5285 10817 : START_PROFILE(Trans2_qpathinfo);
5286 10817 : call_trans2qpathinfo(
5287 : conn,
5288 : req,
5289 : &state->param,
5290 10817 : state->total_param,
5291 : &state->data,
5292 10817 : state->total_data,
5293 : state->max_data_return);
5294 10817 : END_PROFILE(Trans2_qpathinfo);
5295 10528 : break;
5296 : }
5297 :
5298 3617 : case TRANSACT2_QFILEINFO:
5299 : {
5300 3617 : START_PROFILE(Trans2_qfileinfo);
5301 3617 : call_trans2qfileinfo(
5302 : conn,
5303 : req,
5304 : &state->param,
5305 3617 : state->total_param,
5306 : &state->data,
5307 3617 : state->total_data,
5308 : state->max_data_return);
5309 3617 : END_PROFILE(Trans2_qfileinfo);
5310 3432 : break;
5311 : }
5312 :
5313 1410 : case TRANSACT2_SETPATHINFO:
5314 : {
5315 1410 : START_PROFILE(Trans2_setpathinfo);
5316 1410 : call_trans2setpathinfo(
5317 : conn,
5318 : req,
5319 : &state->param,
5320 1410 : state->total_param,
5321 : &state->data,
5322 1410 : state->total_data,
5323 : state->max_data_return);
5324 1410 : END_PROFILE(Trans2_setpathinfo);
5325 1398 : break;
5326 : }
5327 :
5328 4265 : case TRANSACT2_SETFILEINFO:
5329 : {
5330 4265 : START_PROFILE(Trans2_setfileinfo);
5331 4265 : call_trans2setfileinfo(
5332 : conn,
5333 : req,
5334 : &state->param,
5335 4265 : state->total_param,
5336 : &state->data,
5337 4265 : state->total_data,
5338 : state->max_data_return);
5339 4265 : END_PROFILE(Trans2_setfileinfo);
5340 3728 : break;
5341 : }
5342 :
5343 0 : case TRANSACT2_FINDNOTIFYFIRST:
5344 : {
5345 0 : START_PROFILE(Trans2_findnotifyfirst);
5346 0 : call_trans2findnotifyfirst(conn, req,
5347 0 : &state->param, state->total_param,
5348 0 : &state->data, state->total_data,
5349 : state->max_data_return);
5350 0 : END_PROFILE(Trans2_findnotifyfirst);
5351 0 : break;
5352 : }
5353 :
5354 0 : case TRANSACT2_FINDNOTIFYNEXT:
5355 : {
5356 0 : START_PROFILE(Trans2_findnotifynext);
5357 0 : call_trans2findnotifynext(conn, req,
5358 0 : &state->param, state->total_param,
5359 0 : &state->data, state->total_data,
5360 : state->max_data_return);
5361 0 : END_PROFILE(Trans2_findnotifynext);
5362 0 : break;
5363 : }
5364 :
5365 23 : case TRANSACT2_MKDIR:
5366 : {
5367 23 : START_PROFILE(Trans2_mkdir);
5368 23 : call_trans2mkdir(conn, req,
5369 23 : &state->param, state->total_param,
5370 23 : &state->data, state->total_data,
5371 : state->max_data_return);
5372 23 : END_PROFILE(Trans2_mkdir);
5373 20 : break;
5374 : }
5375 :
5376 4370 : case TRANSACT2_GET_DFS_REFERRAL:
5377 : {
5378 4370 : START_PROFILE(Trans2_get_dfs_referral);
5379 4370 : call_trans2getdfsreferral(conn, req,
5380 4370 : &state->param, state->total_param,
5381 4370 : &state->data, state->total_data,
5382 : state->max_data_return);
5383 4370 : END_PROFILE(Trans2_get_dfs_referral);
5384 4370 : break;
5385 : }
5386 :
5387 0 : case TRANSACT2_IOCTL:
5388 : {
5389 0 : START_PROFILE(Trans2_ioctl);
5390 0 : call_trans2ioctl(conn, req,
5391 0 : &state->param, state->total_param,
5392 0 : &state->data, state->total_data,
5393 : state->max_data_return);
5394 0 : END_PROFILE(Trans2_ioctl);
5395 0 : break;
5396 : }
5397 :
5398 0 : default:
5399 : /* Error in request */
5400 0 : DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
5401 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5402 : }
5403 : }
5404 :
5405 : /****************************************************************************
5406 : Reply to a SMBtrans2.
5407 : ****************************************************************************/
5408 :
5409 37801 : void reply_trans2(struct smb_request *req)
5410 : {
5411 37801 : connection_struct *conn = req->conn;
5412 1219 : unsigned int dsoff;
5413 1219 : unsigned int dscnt;
5414 1219 : unsigned int psoff;
5415 1219 : unsigned int pscnt;
5416 1219 : unsigned int tran_call;
5417 1219 : struct trans_state *state;
5418 1219 : NTSTATUS result;
5419 :
5420 37801 : START_PROFILE(SMBtrans2);
5421 :
5422 37801 : if (req->wct < 14) {
5423 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5424 0 : END_PROFILE(SMBtrans2);
5425 0 : return;
5426 : }
5427 :
5428 37801 : dsoff = SVAL(req->vwv+12, 0);
5429 37801 : dscnt = SVAL(req->vwv+11, 0);
5430 37801 : psoff = SVAL(req->vwv+10, 0);
5431 37801 : pscnt = SVAL(req->vwv+9, 0);
5432 37801 : tran_call = SVAL(req->vwv+14, 0);
5433 :
5434 37801 : result = allow_new_trans(conn->pending_trans, req->mid);
5435 37801 : if (!NT_STATUS_IS_OK(result)) {
5436 0 : DEBUG(2, ("Got invalid trans2 request: %s\n",
5437 : nt_errstr(result)));
5438 0 : reply_nterror(req, result);
5439 0 : END_PROFILE(SMBtrans2);
5440 0 : return;
5441 : }
5442 :
5443 37801 : if (IS_IPC(conn)) {
5444 5090 : switch (tran_call) {
5445 : /* List the allowed trans2 calls on IPC$ */
5446 5090 : case TRANSACT2_OPEN:
5447 : case TRANSACT2_GET_DFS_REFERRAL:
5448 : case TRANSACT2_QFILEINFO:
5449 : case TRANSACT2_QFSINFO:
5450 : case TRANSACT2_SETFSINFO:
5451 5090 : break;
5452 0 : default:
5453 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5454 0 : END_PROFILE(SMBtrans2);
5455 0 : return;
5456 : }
5457 : }
5458 :
5459 37801 : if ((state = talloc(conn, struct trans_state)) == NULL) {
5460 0 : DEBUG(0, ("talloc failed\n"));
5461 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5462 0 : END_PROFILE(SMBtrans2);
5463 0 : return;
5464 : }
5465 :
5466 37801 : state->cmd = SMBtrans2;
5467 :
5468 37801 : state->mid = req->mid;
5469 37801 : state->vuid = req->vuid;
5470 37801 : state->setup_count = SVAL(req->vwv+13, 0);
5471 37801 : state->setup = NULL;
5472 37801 : state->total_param = SVAL(req->vwv+0, 0);
5473 37801 : state->param = NULL;
5474 37801 : state->total_data = SVAL(req->vwv+1, 0);
5475 37801 : state->data = NULL;
5476 37801 : state->max_param_return = SVAL(req->vwv+2, 0);
5477 37801 : state->max_data_return = SVAL(req->vwv+3, 0);
5478 37801 : state->max_setup_return = SVAL(req->vwv+4, 0);
5479 37801 : state->close_on_completion = BITSETW(req->vwv+5, 0);
5480 37801 : state->one_way = BITSETW(req->vwv+5, 1);
5481 :
5482 37801 : state->call = tran_call;
5483 :
5484 : /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
5485 : is so as a sanity check */
5486 37801 : if (state->setup_count != 1) {
5487 : /*
5488 : * Need to have rc=0 for ioctl to get job id for OS/2.
5489 : * Network printing will fail if function is not successful.
5490 : * Similar function in reply.c will be used if protocol
5491 : * is LANMAN1.0 instead of LM1.2X002.
5492 : * Until DosPrintSetJobInfo with PRJINFO3 is supported,
5493 : * outbuf doesn't have to be set(only job id is used).
5494 : */
5495 0 : if ( (state->setup_count == 4)
5496 0 : && (tran_call == TRANSACT2_IOCTL)
5497 0 : && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
5498 0 : && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5499 0 : DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
5500 : } else {
5501 0 : DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
5502 0 : DEBUG(2,("Transaction is %d\n",tran_call));
5503 0 : TALLOC_FREE(state);
5504 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5505 0 : END_PROFILE(SMBtrans2);
5506 0 : return;
5507 : }
5508 : }
5509 :
5510 37801 : if ((dscnt > state->total_data) || (pscnt > state->total_param))
5511 0 : goto bad_param;
5512 :
5513 37801 : if (state->total_data) {
5514 :
5515 7326 : if (smb_buffer_oob(state->total_data, 0, dscnt)
5516 7326 : || smb_buffer_oob(smb_len(req->inbuf), dsoff, dscnt)) {
5517 0 : goto bad_param;
5518 : }
5519 :
5520 : /* Can't use talloc here, the core routines do realloc on the
5521 : * params and data. */
5522 7326 : state->data = (char *)SMB_MALLOC(state->total_data);
5523 7326 : if (state->data == NULL) {
5524 0 : DEBUG(0,("reply_trans2: data malloc fail for %u "
5525 : "bytes !\n", (unsigned int)state->total_data));
5526 0 : TALLOC_FREE(state);
5527 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5528 0 : END_PROFILE(SMBtrans2);
5529 0 : return;
5530 : }
5531 :
5532 7326 : memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
5533 : }
5534 :
5535 37801 : if (state->total_param) {
5536 :
5537 37801 : if (smb_buffer_oob(state->total_param, 0, pscnt)
5538 37801 : || smb_buffer_oob(smb_len(req->inbuf), psoff, pscnt)) {
5539 0 : goto bad_param;
5540 : }
5541 :
5542 : /* Can't use talloc here, the core routines do realloc on the
5543 : * params and data. */
5544 37801 : state->param = (char *)SMB_MALLOC(state->total_param);
5545 37801 : if (state->param == NULL) {
5546 0 : DEBUG(0,("reply_trans: param malloc fail for %u "
5547 : "bytes !\n", (unsigned int)state->total_param));
5548 0 : SAFE_FREE(state->data);
5549 0 : TALLOC_FREE(state);
5550 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5551 0 : END_PROFILE(SMBtrans2);
5552 0 : return;
5553 : }
5554 :
5555 37801 : memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
5556 : }
5557 :
5558 37801 : state->received_data = dscnt;
5559 37801 : state->received_param = pscnt;
5560 :
5561 37801 : if ((state->received_param == state->total_param) &&
5562 37801 : (state->received_data == state->total_data)) {
5563 :
5564 37801 : handle_trans2(conn, req, state);
5565 :
5566 37801 : SAFE_FREE(state->data);
5567 37801 : SAFE_FREE(state->param);
5568 37801 : TALLOC_FREE(state);
5569 37801 : END_PROFILE(SMBtrans2);
5570 37801 : return;
5571 : }
5572 :
5573 0 : DLIST_ADD(conn->pending_trans, state);
5574 :
5575 : /* We need to send an interim response then receive the rest
5576 : of the parameter/data bytes */
5577 0 : reply_smb1_outbuf(req, 0, 0);
5578 0 : show_msg((char *)req->outbuf);
5579 0 : END_PROFILE(SMBtrans2);
5580 0 : return;
5581 :
5582 0 : bad_param:
5583 :
5584 0 : DEBUG(0,("reply_trans2: invalid trans parameters\n"));
5585 0 : SAFE_FREE(state->data);
5586 0 : SAFE_FREE(state->param);
5587 0 : TALLOC_FREE(state);
5588 0 : END_PROFILE(SMBtrans2);
5589 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5590 : }
5591 :
5592 : /****************************************************************************
5593 : Reply to a SMBtranss2
5594 : ****************************************************************************/
5595 :
5596 0 : void reply_transs2(struct smb_request *req)
5597 : {
5598 0 : connection_struct *conn = req->conn;
5599 0 : unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
5600 0 : struct trans_state *state;
5601 :
5602 0 : START_PROFILE(SMBtranss2);
5603 :
5604 0 : show_msg((const char *)req->inbuf);
5605 :
5606 : /* Windows clients expect all replies to
5607 : a transact secondary (SMBtranss2 0x33)
5608 : to have a command code of transact
5609 : (SMBtrans2 0x32). See bug #8989
5610 : and also [MS-CIFS] section 2.2.4.47.2
5611 : for details.
5612 : */
5613 0 : req->cmd = SMBtrans2;
5614 :
5615 0 : if (req->wct < 8) {
5616 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5617 0 : END_PROFILE(SMBtranss2);
5618 0 : return;
5619 : }
5620 :
5621 0 : for (state = conn->pending_trans; state != NULL;
5622 0 : state = state->next) {
5623 0 : if (state->mid == req->mid) {
5624 0 : break;
5625 : }
5626 : }
5627 :
5628 0 : if ((state == NULL) || (state->cmd != SMBtrans2)) {
5629 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5630 0 : END_PROFILE(SMBtranss2);
5631 0 : return;
5632 : }
5633 :
5634 : /* Revise state->total_param and state->total_data in case they have
5635 : changed downwards */
5636 :
5637 0 : if (SVAL(req->vwv+0, 0) < state->total_param)
5638 0 : state->total_param = SVAL(req->vwv+0, 0);
5639 0 : if (SVAL(req->vwv+1, 0) < state->total_data)
5640 0 : state->total_data = SVAL(req->vwv+1, 0);
5641 :
5642 0 : pcnt = SVAL(req->vwv+2, 0);
5643 0 : poff = SVAL(req->vwv+3, 0);
5644 0 : pdisp = SVAL(req->vwv+4, 0);
5645 :
5646 0 : dcnt = SVAL(req->vwv+5, 0);
5647 0 : doff = SVAL(req->vwv+6, 0);
5648 0 : ddisp = SVAL(req->vwv+7, 0);
5649 :
5650 0 : state->received_param += pcnt;
5651 0 : state->received_data += dcnt;
5652 :
5653 0 : if ((state->received_data > state->total_data) ||
5654 0 : (state->received_param > state->total_param))
5655 0 : goto bad_param;
5656 :
5657 0 : if (pcnt) {
5658 0 : if (smb_buffer_oob(state->total_param, pdisp, pcnt)
5659 0 : || smb_buffer_oob(smb_len(req->inbuf), poff, pcnt)) {
5660 0 : goto bad_param;
5661 : }
5662 0 : memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
5663 : }
5664 :
5665 0 : if (dcnt) {
5666 0 : if (smb_buffer_oob(state->total_data, ddisp, dcnt)
5667 0 : || smb_buffer_oob(smb_len(req->inbuf), doff, dcnt)) {
5668 0 : goto bad_param;
5669 : }
5670 0 : memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
5671 : }
5672 :
5673 0 : if ((state->received_param < state->total_param) ||
5674 0 : (state->received_data < state->total_data)) {
5675 0 : END_PROFILE(SMBtranss2);
5676 0 : return;
5677 : }
5678 :
5679 0 : handle_trans2(conn, req, state);
5680 :
5681 0 : DLIST_REMOVE(conn->pending_trans, state);
5682 0 : SAFE_FREE(state->data);
5683 0 : SAFE_FREE(state->param);
5684 0 : TALLOC_FREE(state);
5685 :
5686 0 : END_PROFILE(SMBtranss2);
5687 0 : return;
5688 :
5689 0 : bad_param:
5690 :
5691 0 : DEBUG(0,("reply_transs2: invalid trans parameters\n"));
5692 0 : DLIST_REMOVE(conn->pending_trans, state);
5693 0 : SAFE_FREE(state->data);
5694 0 : SAFE_FREE(state->param);
5695 0 : TALLOC_FREE(state);
5696 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5697 0 : END_PROFILE(SMBtranss2);
5698 : }
|