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 29500 : 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 29500 : int data_to_send = datasize;
76 29500 : int params_to_send = paramsize;
77 1172 : int useable_space;
78 29500 : const char *pp = params;
79 29500 : const char *pd = pdata;
80 1172 : int params_sent_thistime, data_sent_thistime, total_sent_thistime;
81 29500 : int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
82 29500 : int data_alignment_offset = 0;
83 29500 : bool overflow = False;
84 29500 : struct smbXsrv_connection *xconn = req->xconn;
85 29500 : 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 29500 : 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 29500 : 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 29500 : if (((params_to_send % 4) != 0) && (data_to_send != 0))
128 19731 : 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 29500 : useable_space = max_send - (smb_size
135 : + 2 * 10 /* wct */
136 28328 : + alignment_offset
137 29500 : + data_alignment_offset);
138 :
139 29500 : 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 59028 : while (params_to_send || data_to_send) {
146 : /* Calculate whether we will totally or partially fill this packet */
147 :
148 29528 : 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 29528 : total_sent_thistime = MIN(total_sent_thistime, useable_space);
159 :
160 29528 : reply_smb1_outbuf(req, 10, total_sent_thistime + alignment_offset
161 29528 : + data_alignment_offset);
162 :
163 : /* Set total params and data to be sent */
164 29528 : SSVAL(req->outbuf,smb_tprcnt,paramsize);
165 29528 : 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 29528 : params_sent_thistime = MIN(params_to_send,useable_space);
172 29528 : data_sent_thistime = useable_space - params_sent_thistime;
173 29528 : data_sent_thistime = MIN(data_sent_thistime,data_to_send);
174 :
175 29528 : 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 29528 : SSVAL(req->outbuf,smb_proff,
183 : ((smb_buf(req->outbuf)+alignment_offset)
184 : - smb_base(req->outbuf)));
185 :
186 29528 : if(params_sent_thistime == 0)
187 3119 : SSVAL(req->outbuf,smb_prdisp,0);
188 : else
189 : /* Absolute displacement of param bytes sent in this packet */
190 26409 : SSVAL(req->outbuf,smb_prdisp,pp - params);
191 :
192 29528 : SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
193 29528 : 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 24478 : 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 24478 : SSVAL(req->outbuf,smb_drdisp, pd - pdata);
204 : }
205 :
206 : /* Initialize the padding for alignment */
207 :
208 29528 : if (alignment_offset != 0) {
209 29528 : memset(smb_buf(req->outbuf), 0, alignment_offset);
210 : }
211 :
212 : /* Copy the param bytes into the packet */
213 :
214 29528 : if(params_sent_thistime) {
215 26409 : memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
216 : params_sent_thistime);
217 : }
218 :
219 : /* Copy in the data bytes */
220 29528 : if(data_sent_thistime) {
221 24478 : if (data_alignment_offset != 0) {
222 19751 : memset((smb_buf(req->outbuf)+alignment_offset+
223 : params_sent_thistime), 0,
224 : data_alignment_offset);
225 : }
226 25650 : memcpy(smb_buf(req->outbuf)+alignment_offset
227 24478 : +params_sent_thistime+data_alignment_offset,
228 : pd,data_sent_thistime);
229 : }
230 :
231 29528 : 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 29528 : 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 29528 : if (overflow) {
237 0 : error_packet_set((char *)req->outbuf,
238 : ERRDOS,ERRbufferoverflow,
239 0 : STATUS_BUFFER_OVERFLOW,
240 : __LINE__,__FILE__);
241 29528 : } 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 29528 : show_msg((char *)req->outbuf);
252 29528 : if (!smb1_srv_send(xconn,
253 29528 : (char *)req->outbuf,
254 : true,
255 29528 : req->seqnum + 1,
256 29528 : IS_CONN_ENCRYPTED(conn))) {
257 0 : exit_server_cleanly("send_trans2_replies: smb1_srv_send failed.");
258 : }
259 :
260 29528 : TALLOC_FREE(req->outbuf);
261 :
262 29528 : pp += params_sent_thistime;
263 29528 : pd += data_sent_thistime;
264 :
265 29528 : params_to_send -= params_sent_thistime;
266 29528 : data_to_send -= data_sent_thistime;
267 :
268 : /* Sanity check */
269 29528 : 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 28328 : 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 206901 : 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 206901 : uint8_t align = 4;
791 206901 : const bool do_pad = true;
792 :
793 206901 : if (info_level >= 1 && info_level <= 3) {
794 : /* No alignment on earlier info levels. */
795 114822 : align = 1;
796 : }
797 :
798 206901 : 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 8716 : 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 8716 : struct smb_filename *smb_dname = NULL;
824 8716 : char *params = *pparams;
825 8716 : 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 8716 : char *directory = NULL;
835 8716 : char *mask = NULL;
836 175 : char *p;
837 8716 : int last_entry_off=0;
838 8716 : int dptr_num = -1;
839 8716 : int numentries = 0;
840 175 : int i;
841 8716 : bool finished = False;
842 8716 : bool dont_descend = False;
843 8716 : bool out_of_space = False;
844 175 : int space_remaining;
845 8716 : struct ea_list *ea_list = NULL;
846 8716 : NTSTATUS ntstatus = NT_STATUS_OK;
847 175 : bool ask_sharemode;
848 8716 : struct smbXsrv_connection *xconn = req->xconn;
849 8716 : struct smbd_server_connection *sconn = req->sconn;
850 8716 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
851 8716 : bool backup_priv = false;
852 8716 : bool as_root = false;
853 8716 : files_struct *fsp = NULL;
854 8716 : struct files_struct *dirfsp = NULL;
855 175 : const struct loadparm_substitution *lp_sub =
856 8716 : loadparm_s3_global_substitution();
857 :
858 8716 : if (total_params < 13) {
859 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
860 0 : goto out;
861 : }
862 :
863 8716 : dirtype = SVAL(params,0);
864 8716 : maxentries = SVAL(params,2);
865 8716 : findfirst_flags = SVAL(params,4);
866 8716 : close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
867 8716 : close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
868 8716 : requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
869 8722 : 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 8716 : info_level = SVAL(params,6);
874 :
875 8716 : 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 8716 : if (!maxentries) {
889 : /* W2K3 seems to treat zero as 1. */
890 12 : maxentries = 1;
891 : }
892 :
893 8716 : switch (info_level) {
894 8525 : 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 8700 : 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 8716 : if (req->posix_pathnames) {
921 186 : srvstr_get_path_posix(talloc_tos(),
922 : params,
923 186 : req->flags2,
924 : &directory,
925 186 : params+12,
926 186 : total_params - 12,
927 : STR_TERMINATE,
928 : &ntstatus);
929 : } else {
930 8530 : srvstr_get_path(talloc_tos(),
931 : params,
932 8530 : req->flags2,
933 : &directory,
934 8530 : params+12,
935 8530 : total_params - 12,
936 : STR_TERMINATE,
937 : &ntstatus);
938 : }
939 8716 : if (!NT_STATUS_IS_OK(ntstatus)) {
940 0 : reply_nterror(req, ntstatus);
941 0 : goto out;
942 : }
943 :
944 8716 : if (backup_priv) {
945 0 : become_root();
946 0 : as_root = true;
947 : }
948 8716 : ntstatus = smb1_strip_dfs_path(talloc_tos(), &ucf_flags, &directory);
949 8716 : if (!NT_STATUS_IS_OK(ntstatus)) {
950 0 : reply_nterror(req, ntstatus);
951 0 : goto out;
952 : }
953 :
954 8716 : ntstatus = filename_convert_smb1_search_path(talloc_tos(),
955 : conn,
956 : directory,
957 : ucf_flags,
958 : &dirfsp,
959 : &smb_dname,
960 : &mask);
961 :
962 8716 : 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 8602 : TALLOC_FREE(directory);
973 8602 : directory = smb_dname->base_name;
974 :
975 8602 : DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
976 :
977 8602 : 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 8602 : 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 8602 : *ppdata = (char *)SMB_REALLOC(
1014 : *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
1015 8602 : if(*ppdata == NULL ) {
1016 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1017 0 : goto out;
1018 : }
1019 8602 : pdata = *ppdata;
1020 8602 : 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 8602 : memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data));
1026 : /* Realloc the params space */
1027 8602 : *pparams = (char *)SMB_REALLOC(*pparams, 10);
1028 8602 : if (*pparams == NULL) {
1029 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1030 0 : goto out;
1031 : }
1032 8602 : params = *pparams;
1033 :
1034 : /*
1035 : * Open an fsp on this directory for the dptr.
1036 : */
1037 8602 : 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 8602 : 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 8483 : ntstatus = dptr_create(conn,
1070 : req,
1071 : fsp, /* fsp */
1072 : False,
1073 : mask,
1074 : dirtype,
1075 8483 : &fsp->dptr);
1076 :
1077 8483 : 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 8483 : 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 8483 : dptr_num = dptr_dnum(fsp->dptr);
1095 8483 : 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 8483 : DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1101 : directory,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn))));
1102 8483 : if (in_list(directory,
1103 8483 : lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
1104 8483 : dptr_case_sensitive(fsp->dptr))) {
1105 0 : dont_descend = True;
1106 : }
1107 :
1108 8483 : p = pdata;
1109 8483 : space_remaining = max_data_bytes;
1110 8483 : out_of_space = False;
1111 :
1112 8483 : ask_sharemode = fsp_search_ask_sharemode(fsp);
1113 :
1114 57780 : for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
1115 :
1116 49123 : ntstatus = get_lanman2_dir_entry(talloc_tos(),
1117 : conn,
1118 49123 : fsp->dptr,
1119 49123 : 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 49123 : 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 49111 : if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
1140 0 : out_of_space = true;
1141 : } else {
1142 49111 : finished = !NT_STATUS_IS_OK(ntstatus);
1143 : }
1144 :
1145 49111 : if (!finished && !out_of_space) {
1146 41255 : numentries++;
1147 : }
1148 :
1149 : /* Ensure space_remaining never goes -ve. */
1150 49111 : if (PTR_DIFF(p,pdata) > max_data_bytes) {
1151 0 : space_remaining = 0;
1152 0 : out_of_space = true;
1153 : } else {
1154 49111 : space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
1155 : }
1156 : }
1157 :
1158 : /* Check if we can close the dirptr */
1159 8483 : if(close_after_first || (finished && close_if_end)) {
1160 8349 : DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
1161 8349 : dptr_num = -1;
1162 8349 : 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 8483 : 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 7942 : SSVAL(params,0,dptr_num);
1195 7942 : SSVAL(params,2,numentries);
1196 7942 : SSVAL(params,4,finished);
1197 7942 : SSVAL(params,6,0); /* Never an EA error */
1198 7942 : SSVAL(params,8,last_entry_off);
1199 :
1200 7942 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
1201 : max_data_bytes);
1202 :
1203 7942 : 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 7942 : 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 7942 : if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
1223 153 : char mangled_name[13];
1224 7804 : name_to_8_3(mask, mangled_name, True, conn->params);
1225 : }
1226 138 : out:
1227 :
1228 8716 : if (as_root) {
1229 0 : unbecome_root();
1230 : }
1231 :
1232 8716 : TALLOC_FREE(smb_dname);
1233 8716 : 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 1373 : 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 1373 : char *params = *pparams;
1654 0 : uint16_t info_level;
1655 1373 : int data_len = 0;
1656 0 : size_t fixed_portion;
1657 0 : NTSTATUS status;
1658 :
1659 1373 : if (total_params < 2) {
1660 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1661 0 : return;
1662 : }
1663 :
1664 1373 : info_level = SVAL(params,0);
1665 :
1666 1373 : 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 1373 : DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
1677 :
1678 1373 : status = smbd_do_qfsinfo(req->xconn, conn, req,
1679 : info_level,
1680 1373 : req->flags2,
1681 : max_data_bytes,
1682 : &fixed_portion,
1683 : NULL,
1684 : NULL,
1685 : ppdata, &data_len);
1686 1373 : if (!NT_STATUS_IS_OK(status)) {
1687 0 : reply_nterror(req, status);
1688 0 : return;
1689 : }
1690 :
1691 1373 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
1692 : max_data_bytes);
1693 :
1694 1373 : DEBUG( 4, ( "%s info_level = %d\n",
1695 : smb_fn_name(req->cmd), info_level) );
1696 :
1697 1373 : return;
1698 : }
1699 :
1700 : /****************************************************************************
1701 : Reply to a TRANS2_SETFSINFO (set filesystem info).
1702 : ****************************************************************************/
1703 :
1704 1364 : 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 1364 : loadparm_s3_global_substitution();
1712 1364 : struct smbXsrv_connection *xconn = req->xconn;
1713 1364 : char *pdata = *ppdata;
1714 1364 : char *params = *pparams;
1715 0 : uint16_t info_level;
1716 :
1717 1364 : DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
1718 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1719 :
1720 : /* */
1721 1364 : 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 1364 : info_level = SVAL(params,2);
1729 :
1730 1364 : 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 1364 : 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 1364 : switch(info_level) {
1752 476 : case SMB_SET_CIFS_UNIX_INFO:
1753 476 : 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 476 : if (total_data < 12) {
1764 0 : reply_nterror(
1765 : req,
1766 : NT_STATUS_INVALID_PARAMETER);
1767 0 : return;
1768 : }
1769 476 : xconn->smb1.unix_info.client_major = SVAL(pdata,0);
1770 476 : xconn->smb1.unix_info.client_minor = SVAL(pdata,2);
1771 476 : xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
1772 476 : xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
1773 :
1774 : /* Just print these values for now. */
1775 476 : 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 476 : if (xconn->smb1.unix_info.client_cap_low &
1789 : CIFS_UNIX_POSIX_PATHNAMES_CAP)
1790 : {
1791 476 : lp_set_posix_pathnames();
1792 476 : mangle_change_to_posix();
1793 : }
1794 :
1795 476 : if ((xconn->smb1.unix_info.client_cap_low &
1796 476 : CIFS_UNIX_FCNTL_LOCKS_CAP) &&
1797 476 : !(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 476 : 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 476 : 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 11353 : 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 11353 : char params[2] = { 0, 0, };
1987 11353 : 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 11353 : switch (info_level) {
2002 8 : case SMB_INFO_IS_NAME_VALID:
2003 8 : param_size = 0;
2004 8 : break;
2005 : }
2006 :
2007 11353 : 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 11293 : if (fixed_portion > max_data_bytes) {
2023 0 : reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
2024 0 : return;
2025 : }
2026 :
2027 11293 : send_trans2_replies(
2028 : conn,
2029 : req,
2030 11293 : 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 11115 : 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 11115 : char *params = *pparams;
2056 11115 : char *pdata = *ppdata;
2057 11115 : unsigned int data_size = 0;
2058 11115 : struct ea_list *ea_list = NULL;
2059 449 : size_t fixed_portion;
2060 11115 : NTSTATUS status = NT_STATUS_OK;
2061 :
2062 11115 : 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 11115 : 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 10542 : default:
2105 10542 : break;
2106 : }
2107 :
2108 11115 : *pparams = (char *)SMB_REALLOC(*pparams,2);
2109 11115 : if (*pparams == NULL) {
2110 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2111 0 : return;
2112 : }
2113 11115 : params = *pparams;
2114 11115 : SSVAL(params,0,0);
2115 :
2116 11115 : 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 11115 : status = smbd_do_qfilepathinfo(conn, req, req, info_level,
2126 : fsp, smb_fname,
2127 : delete_pending, write_time_ts,
2128 : ea_list,
2129 11115 : req->flags2, max_data_bytes,
2130 : &fixed_portion,
2131 : ppdata, &data_size);
2132 :
2133 11115 : 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 9909 : 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 9909 : char *params = *pparams;
2615 289 : uint16_t info_level;
2616 9909 : struct smb_filename *smb_fname = NULL;
2617 9909 : bool delete_pending = False;
2618 9909 : struct timespec write_time_ts = { .tv_sec = 0, };
2619 9909 : struct files_struct *dirfsp = NULL;
2620 9909 : files_struct *fsp = NULL;
2621 289 : struct file_id fileid;
2622 289 : uint32_t name_hash;
2623 9909 : char *fname = NULL;
2624 9909 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
2625 9909 : NTTIME twrp = 0;
2626 289 : bool info_level_handled;
2627 9909 : NTSTATUS status = NT_STATUS_OK;
2628 289 : int ret;
2629 :
2630 9909 : if (!params) {
2631 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2632 0 : return;
2633 : }
2634 :
2635 :
2636 : /* qpathinfo */
2637 9909 : if (total_params < 7) {
2638 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2639 0 : return;
2640 : }
2641 :
2642 9909 : info_level = SVAL(params,0);
2643 :
2644 9909 : DBG_NOTICE("TRANSACT2_QPATHINFO: level = %d\n", info_level);
2645 :
2646 9909 : 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 9909 : 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 9459 : srvstr_get_path(req,
2668 : params,
2669 9459 : req->flags2,
2670 : &fname,
2671 9459 : ¶ms[6],
2672 9459 : total_params - 6,
2673 : STR_TERMINATE,
2674 : &status);
2675 : }
2676 9909 : if (!NT_STATUS_IS_OK(status)) {
2677 0 : reply_nterror(req, status);
2678 0 : return;
2679 : }
2680 :
2681 9909 : if (ucf_flags & UCF_GMT_PATHNAME) {
2682 3104 : extract_snapshot_token(fname, &twrp);
2683 : }
2684 9909 : status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
2685 9909 : if (!NT_STATUS_IS_OK(status)) {
2686 0 : reply_nterror(req, status);
2687 0 : return;
2688 : }
2689 9909 : status = filename_convert_dirfsp(req,
2690 : conn,
2691 : fname,
2692 : ucf_flags,
2693 : twrp,
2694 : &dirfsp,
2695 : &smb_fname);
2696 9909 : if (!NT_STATUS_IS_OK(status)) {
2697 1730 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2698 1180 : reply_botherror(req,
2699 : NT_STATUS_PATH_NOT_COVERED,
2700 : ERRSRV, ERRbadpath);
2701 1180 : 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 8179 : if (!VALID_STAT(smb_fname->st)) {
2714 110 : reply_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2715 110 : return;
2716 : }
2717 :
2718 : /*
2719 : * smb_fname->fsp may be NULL if smb_fname points at a symlink
2720 : * and we're in POSIX context, so be careful when using fsp
2721 : * below, it can still be NULL.
2722 : */
2723 8069 : fsp = smb_fname->fsp;
2724 :
2725 : /* If this is a stream, check if there is a delete_pending. */
2726 8069 : if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
2727 3069 : && is_ntfs_stream_smb_fname(smb_fname)) {
2728 0 : struct smb_filename *smb_fname_base;
2729 :
2730 : /* Create an smb_filename with stream_name == NULL. */
2731 60 : smb_fname_base = synthetic_smb_fname(
2732 : talloc_tos(),
2733 60 : smb_fname->base_name,
2734 : NULL,
2735 : NULL,
2736 60 : smb_fname->twrp,
2737 60 : smb_fname->flags);
2738 60 : if (smb_fname_base == NULL) {
2739 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2740 0 : return;
2741 : }
2742 :
2743 60 : ret = vfs_stat(conn, smb_fname_base);
2744 60 : if (ret != 0) {
2745 0 : DBG_NOTICE("vfs_stat of %s failed "
2746 : "(%s)\n",
2747 : smb_fname_str_dbg(smb_fname_base),
2748 : strerror(errno));
2749 0 : TALLOC_FREE(smb_fname_base);
2750 0 : reply_nterror(req,
2751 : map_nt_error_from_unix(errno));
2752 0 : return;
2753 : }
2754 :
2755 60 : status = file_name_hash(conn,
2756 : smb_fname_str_dbg(smb_fname_base),
2757 : &name_hash);
2758 60 : if (!NT_STATUS_IS_OK(status)) {
2759 0 : TALLOC_FREE(smb_fname_base);
2760 0 : reply_nterror(req, status);
2761 0 : return;
2762 : }
2763 :
2764 60 : fileid = vfs_file_id_from_sbuf(conn,
2765 60 : &smb_fname_base->st);
2766 60 : TALLOC_FREE(smb_fname_base);
2767 60 : get_file_infos(fileid, name_hash, &delete_pending, NULL);
2768 60 : if (delete_pending) {
2769 4 : reply_nterror(req, NT_STATUS_DELETE_PENDING);
2770 4 : return;
2771 : }
2772 : }
2773 :
2774 8065 : status = file_name_hash(conn,
2775 : smb_fname_str_dbg(smb_fname),
2776 : &name_hash);
2777 8065 : if (!NT_STATUS_IS_OK(status)) {
2778 0 : reply_nterror(req, status);
2779 0 : return;
2780 : }
2781 :
2782 8065 : if (fsp_getinfo_ask_sharemode(fsp)) {
2783 8065 : fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
2784 8065 : get_file_infos(fileid, name_hash, &delete_pending,
2785 : &write_time_ts);
2786 : }
2787 :
2788 8065 : if (delete_pending) {
2789 119 : reply_nterror(req, NT_STATUS_DELETE_PENDING);
2790 119 : return;
2791 : }
2792 :
2793 7946 : info_level_handled = true; /* Untouched in switch cases below */
2794 :
2795 7946 : switch (info_level) {
2796 :
2797 7448 : default:
2798 7448 : info_level_handled = false;
2799 7448 : break;
2800 :
2801 114 : case SMB_QUERY_FILE_UNIX_BASIC:
2802 114 : status = smb_q_unix_basic(
2803 : conn,
2804 : req,
2805 : smb_fname,
2806 114 : smb_fname->fsp,
2807 : ppdata,
2808 : &total_data);
2809 114 : break;
2810 :
2811 16 : case SMB_QUERY_FILE_UNIX_INFO2:
2812 16 : status = smb_q_unix_info2(
2813 : conn,
2814 : req,
2815 : smb_fname,
2816 16 : smb_fname->fsp,
2817 : ppdata,
2818 : &total_data);
2819 16 : break;
2820 :
2821 80 : case SMB_QUERY_POSIX_ACL:
2822 80 : status = smb_q_posix_acl(
2823 : conn,
2824 : req,
2825 : smb_fname,
2826 80 : smb_fname->fsp,
2827 : ppdata,
2828 : &total_data);
2829 80 : break;
2830 :
2831 24 : case SMB_QUERY_FILE_UNIX_LINK:
2832 24 : status = smb_q_posix_symlink(
2833 : conn,
2834 : req,
2835 : smb_fname,
2836 : ppdata,
2837 : &total_data);
2838 24 : break;
2839 : }
2840 :
2841 7682 : if (info_level_handled) {
2842 234 : handle_trans2qfilepathinfo_result(
2843 : conn,
2844 : req,
2845 : info_level,
2846 : status,
2847 : *ppdata,
2848 : total_data,
2849 : total_data,
2850 : max_data_bytes);
2851 234 : return;
2852 : }
2853 :
2854 7712 : call_trans2qfilepathinfo(
2855 : conn,
2856 : req,
2857 : TRANSACT2_QPATHINFO,
2858 : info_level,
2859 : smb_fname,
2860 : fsp,
2861 : false,
2862 : write_time_ts,
2863 : pparams,
2864 : total_params,
2865 : ppdata,
2866 : total_data,
2867 : max_data_bytes);
2868 : }
2869 :
2870 0 : static NTSTATUS smb_q_posix_lock(
2871 : struct connection_struct *conn,
2872 : struct smb_request *req,
2873 : struct files_struct *fsp,
2874 : char **ppdata,
2875 : int *ptotal_data)
2876 : {
2877 0 : char *pdata = *ppdata;
2878 0 : int total_data = *ptotal_data;
2879 0 : uint64_t count;
2880 0 : uint64_t offset;
2881 0 : uint64_t smblctx;
2882 0 : enum brl_type lock_type;
2883 0 : NTSTATUS status;
2884 :
2885 0 : if (fsp->fsp_flags.is_pathref || (fsp_get_io_fd(fsp) == -1)) {
2886 0 : return NT_STATUS_INVALID_HANDLE;
2887 : }
2888 :
2889 0 : if (total_data != POSIX_LOCK_DATA_SIZE) {
2890 0 : return NT_STATUS_INVALID_PARAMETER;
2891 : }
2892 :
2893 0 : switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
2894 0 : case POSIX_LOCK_TYPE_READ:
2895 0 : lock_type = READ_LOCK;
2896 0 : break;
2897 0 : case POSIX_LOCK_TYPE_WRITE:
2898 0 : lock_type = WRITE_LOCK;
2899 0 : break;
2900 0 : case POSIX_LOCK_TYPE_UNLOCK:
2901 : default:
2902 : /* There's no point in asking for an unlock... */
2903 0 : return NT_STATUS_INVALID_PARAMETER;
2904 : }
2905 :
2906 0 : smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
2907 0 : offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
2908 0 : count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
2909 :
2910 0 : status = query_lock(
2911 : fsp,
2912 : &smblctx,
2913 : &count,
2914 : &offset,
2915 : &lock_type,
2916 : POSIX_LOCK);
2917 :
2918 0 : if (NT_STATUS_IS_OK(status)) {
2919 : /*
2920 : * For success we just return a copy of what we sent
2921 : * with the lock type set to POSIX_LOCK_TYPE_UNLOCK.
2922 : */
2923 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
2924 0 : return NT_STATUS_OK;
2925 : }
2926 :
2927 0 : if (!ERROR_WAS_LOCK_DENIED(status)) {
2928 0 : DBG_DEBUG("query_lock() failed: %s\n", nt_errstr(status));
2929 0 : return status;
2930 : }
2931 :
2932 : /*
2933 : * Here we need to report who has it locked.
2934 : */
2935 :
2936 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
2937 0 : SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
2938 0 : SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
2939 0 : SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
2940 0 : SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
2941 :
2942 0 : return NT_STATUS_OK;
2943 : }
2944 :
2945 3551 : static void call_trans2qfileinfo(
2946 : connection_struct *conn,
2947 : struct smb_request *req,
2948 : char **pparams,
2949 : int total_params,
2950 : char **ppdata,
2951 : int total_data,
2952 : unsigned int max_data_bytes)
2953 : {
2954 3551 : char *params = *pparams;
2955 185 : uint16_t info_level;
2956 3551 : struct smb_filename *smb_fname = NULL;
2957 3551 : bool delete_pending = False;
2958 3551 : struct timespec write_time_ts = { .tv_sec = 0, };
2959 3551 : files_struct *fsp = NULL;
2960 185 : struct file_id fileid;
2961 185 : bool info_level_handled;
2962 3551 : NTSTATUS status = NT_STATUS_OK;
2963 185 : int ret;
2964 :
2965 3551 : if (params == NULL) {
2966 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2967 0 : return;
2968 : }
2969 :
2970 3551 : if (total_params < 4) {
2971 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2972 0 : return;
2973 : }
2974 :
2975 3551 : fsp = file_fsp(req, SVAL(params,0));
2976 3551 : info_level = SVAL(params,2);
2977 :
2978 3551 : if (IS_IPC(conn)) {
2979 0 : call_trans2qpipeinfo(
2980 : conn,
2981 : req,
2982 : fsp,
2983 : info_level,
2984 : TRANSACT2_QFILEINFO,
2985 : pparams,
2986 : total_params,
2987 : ppdata,
2988 : total_data,
2989 : max_data_bytes);
2990 0 : return;
2991 : }
2992 :
2993 3551 : DBG_NOTICE("TRANSACT2_QFILEINFO: level = %d\n", info_level);
2994 :
2995 3551 : if (INFO_LEVEL_IS_UNIX(info_level)) {
2996 4 : if (!lp_smb1_unix_extensions()) {
2997 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2998 0 : return;
2999 : }
3000 4 : if (!req->posix_pathnames) {
3001 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
3002 0 : return;
3003 : }
3004 : }
3005 :
3006 : /* Initial check for valid fsp ptr. */
3007 3551 : if (!check_fsp_open(conn, req, fsp)) {
3008 144 : return;
3009 : }
3010 :
3011 3407 : smb_fname = fsp->fsp_name;
3012 :
3013 3407 : if(fsp->fake_file_handle) {
3014 : /*
3015 : * This is actually for the QUOTA_FAKE_FILE --metze
3016 : */
3017 :
3018 : /* We know this name is ok, it's already passed the checks. */
3019 :
3020 3407 : } else if(fsp_get_pathref_fd(fsp) == -1) {
3021 : /*
3022 : * This is actually a QFILEINFO on a directory
3023 : * handle (returned from an NT SMB). NT5.0 seems
3024 : * to do this call. JRA.
3025 : */
3026 0 : ret = vfs_stat(conn, smb_fname);
3027 0 : if (ret != 0) {
3028 0 : DBG_NOTICE("vfs_stat of %s failed (%s)\n",
3029 : smb_fname_str_dbg(smb_fname),
3030 : strerror(errno));
3031 0 : reply_nterror(req,
3032 : map_nt_error_from_unix(errno));
3033 0 : return;
3034 : }
3035 :
3036 0 : if (fsp_getinfo_ask_sharemode(fsp)) {
3037 0 : fileid = vfs_file_id_from_sbuf(
3038 0 : conn, &smb_fname->st);
3039 0 : get_file_infos(fileid, fsp->name_hash,
3040 : &delete_pending,
3041 : &write_time_ts);
3042 : }
3043 : } else {
3044 : /*
3045 : * Original code - this is an open file.
3046 : */
3047 3407 : status = vfs_stat_fsp(fsp);
3048 3407 : if (!NT_STATUS_IS_OK(status)) {
3049 0 : DEBUG(3, ("fstat of %s failed (%s)\n",
3050 : fsp_fnum_dbg(fsp), nt_errstr(status)));
3051 0 : reply_nterror(req, status);
3052 0 : return;
3053 : }
3054 3407 : if (fsp_getinfo_ask_sharemode(fsp)) {
3055 3407 : fileid = vfs_file_id_from_sbuf(
3056 3407 : conn, &smb_fname->st);
3057 3407 : get_file_infos(fileid, fsp->name_hash,
3058 : &delete_pending,
3059 : &write_time_ts);
3060 : }
3061 : }
3062 :
3063 3407 : info_level_handled = true; /* Untouched in switch cases below */
3064 :
3065 3407 : switch (info_level) {
3066 :
3067 3218 : default:
3068 3218 : info_level_handled = false;
3069 3218 : break;
3070 :
3071 0 : case SMB_QUERY_POSIX_LOCK:
3072 0 : status = smb_q_posix_lock(conn, req, fsp, ppdata, &total_data);
3073 0 : break;
3074 :
3075 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3076 0 : status = smb_q_unix_basic(
3077 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3078 0 : break;
3079 :
3080 4 : case SMB_QUERY_FILE_UNIX_INFO2:
3081 4 : status = smb_q_unix_info2(
3082 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3083 4 : break;
3084 :
3085 0 : case SMB_QUERY_POSIX_ACL:
3086 0 : status = smb_q_posix_acl(
3087 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3088 0 : break;
3089 : }
3090 :
3091 3222 : if (info_level_handled) {
3092 4 : handle_trans2qfilepathinfo_result(
3093 : conn,
3094 : req,
3095 : info_level,
3096 : status,
3097 : *ppdata,
3098 : total_data,
3099 : total_data,
3100 : max_data_bytes);
3101 4 : return;
3102 : }
3103 :
3104 3403 : call_trans2qfilepathinfo(
3105 : conn,
3106 : req,
3107 : TRANSACT2_QFILEINFO,
3108 : info_level,
3109 : smb_fname,
3110 : fsp,
3111 : delete_pending,
3112 : write_time_ts,
3113 : pparams,
3114 : total_params,
3115 : ppdata,
3116 : total_data,
3117 : max_data_bytes);
3118 : }
3119 :
3120 5605 : static void handle_trans2setfilepathinfo_result(
3121 : connection_struct *conn,
3122 : struct smb_request *req,
3123 : uint16_t info_level,
3124 : NTSTATUS status,
3125 : char *pdata,
3126 : int data_return_size,
3127 : unsigned int max_data_bytes)
3128 : {
3129 5605 : char params[2] = { 0, 0, };
3130 :
3131 5605 : if (NT_STATUS_IS_OK(status)) {
3132 4680 : send_trans2_replies(
3133 : conn,
3134 : req,
3135 4680 : NT_STATUS_OK,
3136 : params,
3137 : 2,
3138 : pdata,
3139 : data_return_size,
3140 : max_data_bytes);
3141 4680 : return;
3142 : }
3143 :
3144 925 : if (open_was_deferred(req->xconn, req->mid)) {
3145 : /* We have re-scheduled this call. */
3146 6 : return;
3147 : }
3148 :
3149 919 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3150 32 : bool ok = defer_smb1_sharing_violation(req);
3151 32 : if (ok) {
3152 16 : return;
3153 : }
3154 : }
3155 :
3156 903 : if (NT_STATUS_EQUAL(status, NT_STATUS_EVENT_PENDING)) {
3157 : /* We have re-scheduled this call. */
3158 28 : return;
3159 : }
3160 :
3161 875 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3162 0 : reply_botherror(
3163 : req,
3164 : NT_STATUS_PATH_NOT_COVERED,
3165 : ERRSRV,
3166 : ERRbadpath);
3167 0 : return;
3168 : }
3169 :
3170 875 : if (info_level == SMB_POSIX_PATH_OPEN) {
3171 12 : reply_openerror(req, status);
3172 12 : return;
3173 : }
3174 :
3175 863 : if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
3176 : /*
3177 : * Invalid EA name needs to return 2 param bytes,
3178 : * not a zero-length error packet.
3179 : */
3180 :
3181 235 : send_trans2_replies(
3182 : conn,
3183 : req,
3184 : status,
3185 : params,
3186 : 2,
3187 : NULL,
3188 : 0,
3189 : max_data_bytes);
3190 235 : return;
3191 : }
3192 :
3193 628 : reply_nterror(req, status);
3194 : }
3195 :
3196 : /****************************************************************************
3197 : Create a directory with POSIX semantics.
3198 : ****************************************************************************/
3199 :
3200 48 : static NTSTATUS smb_posix_mkdir(connection_struct *conn,
3201 : struct smb_request *req,
3202 : char **ppdata,
3203 : int total_data,
3204 : struct smb_filename *smb_fname,
3205 : int *pdata_return_size)
3206 : {
3207 48 : NTSTATUS status = NT_STATUS_OK;
3208 48 : uint32_t raw_unixmode = 0;
3209 48 : mode_t unixmode = (mode_t)0;
3210 48 : files_struct *fsp = NULL;
3211 48 : uint16_t info_level_return = 0;
3212 0 : int info;
3213 48 : char *pdata = *ppdata;
3214 48 : struct smb2_create_blobs *posx = NULL;
3215 :
3216 48 : if (total_data < 18) {
3217 0 : return NT_STATUS_INVALID_PARAMETER;
3218 : }
3219 :
3220 48 : raw_unixmode = IVAL(pdata,8);
3221 : /* Next 4 bytes are not yet defined. */
3222 :
3223 48 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3224 : PERM_NEW_DIR, &unixmode);
3225 48 : if (!NT_STATUS_IS_OK(status)) {
3226 0 : return status;
3227 : }
3228 :
3229 48 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3230 48 : if (!NT_STATUS_IS_OK(status)) {
3231 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3232 : nt_errstr(status));
3233 0 : return status;
3234 : }
3235 :
3236 48 : DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
3237 : smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
3238 :
3239 48 : status = SMB_VFS_CREATE_FILE(
3240 : conn, /* conn */
3241 : req, /* req */
3242 : NULL, /* dirfsp */
3243 : smb_fname, /* fname */
3244 : FILE_READ_ATTRIBUTES, /* access_mask */
3245 : FILE_SHARE_NONE, /* share_access */
3246 : FILE_CREATE, /* create_disposition*/
3247 : FILE_DIRECTORY_FILE, /* create_options */
3248 : 0, /* file_attributes */
3249 : 0, /* oplock_request */
3250 : NULL, /* lease */
3251 : 0, /* allocation_size */
3252 : 0, /* private_flags */
3253 : NULL, /* sd */
3254 : NULL, /* ea_list */
3255 : &fsp, /* result */
3256 : &info, /* pinfo */
3257 : posx, /* in_context_blobs */
3258 : NULL); /* out_context_blobs */
3259 :
3260 48 : TALLOC_FREE(posx);
3261 :
3262 48 : if (NT_STATUS_IS_OK(status)) {
3263 48 : close_file_free(req, &fsp, NORMAL_CLOSE);
3264 : }
3265 :
3266 48 : info_level_return = SVAL(pdata,16);
3267 :
3268 48 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3269 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3270 48 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3271 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3272 : } else {
3273 48 : *pdata_return_size = 12;
3274 : }
3275 :
3276 : /* Realloc the data size */
3277 48 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3278 48 : if (*ppdata == NULL) {
3279 0 : *pdata_return_size = 0;
3280 0 : return NT_STATUS_NO_MEMORY;
3281 : }
3282 48 : pdata = *ppdata;
3283 :
3284 48 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
3285 48 : SSVAL(pdata,2,0); /* No fnum. */
3286 48 : SIVAL(pdata,4,info); /* Was directory created. */
3287 :
3288 48 : switch (info_level_return) {
3289 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3290 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3291 0 : SSVAL(pdata,10,0); /* Padding. */
3292 0 : store_file_unix_basic(conn, pdata + 12, fsp,
3293 0 : &smb_fname->st);
3294 0 : break;
3295 0 : case SMB_QUERY_FILE_UNIX_INFO2:
3296 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3297 0 : SSVAL(pdata,10,0); /* Padding. */
3298 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
3299 0 : &smb_fname->st);
3300 0 : break;
3301 48 : default:
3302 48 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3303 48 : SSVAL(pdata,10,0); /* Padding. */
3304 48 : break;
3305 : }
3306 :
3307 48 : return status;
3308 : }
3309 :
3310 : /****************************************************************************
3311 : Open/Create a file with POSIX semantics.
3312 : ****************************************************************************/
3313 :
3314 : #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
3315 : #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
3316 :
3317 174 : static NTSTATUS smb_posix_open(connection_struct *conn,
3318 : struct smb_request *req,
3319 : char **ppdata,
3320 : int total_data,
3321 : struct files_struct *dirfsp,
3322 : struct smb_filename *smb_fname,
3323 : int *pdata_return_size)
3324 : {
3325 174 : bool extended_oplock_granted = False;
3326 174 : char *pdata = *ppdata;
3327 174 : uint32_t flags = 0;
3328 174 : uint32_t wire_open_mode = 0;
3329 174 : uint32_t raw_unixmode = 0;
3330 174 : uint32_t attributes = 0;
3331 174 : uint32_t create_disp = 0;
3332 174 : uint32_t access_mask = 0;
3333 174 : uint32_t create_options = FILE_NON_DIRECTORY_FILE;
3334 174 : NTSTATUS status = NT_STATUS_OK;
3335 174 : mode_t unixmode = (mode_t)0;
3336 174 : files_struct *fsp = NULL;
3337 174 : int oplock_request = 0;
3338 174 : int info = 0;
3339 174 : uint16_t info_level_return = 0;
3340 174 : struct smb2_create_blobs *posx = NULL;
3341 :
3342 174 : if (total_data < 18) {
3343 0 : return NT_STATUS_INVALID_PARAMETER;
3344 : }
3345 :
3346 174 : flags = IVAL(pdata,0);
3347 174 : oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
3348 174 : if (oplock_request) {
3349 0 : oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
3350 : }
3351 :
3352 174 : wire_open_mode = IVAL(pdata,4);
3353 :
3354 174 : if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
3355 48 : return smb_posix_mkdir(conn, req,
3356 : ppdata,
3357 : total_data,
3358 : smb_fname,
3359 : pdata_return_size);
3360 : }
3361 :
3362 126 : switch (wire_open_mode & SMB_ACCMODE) {
3363 28 : case SMB_O_RDONLY:
3364 28 : access_mask = SMB_O_RDONLY_MAPPING;
3365 28 : break;
3366 4 : case SMB_O_WRONLY:
3367 4 : access_mask = SMB_O_WRONLY_MAPPING;
3368 4 : break;
3369 94 : case SMB_O_RDWR:
3370 94 : access_mask = (SMB_O_RDONLY_MAPPING|
3371 : SMB_O_WRONLY_MAPPING);
3372 94 : break;
3373 0 : default:
3374 0 : DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
3375 : (unsigned int)wire_open_mode ));
3376 0 : return NT_STATUS_INVALID_PARAMETER;
3377 : }
3378 :
3379 126 : wire_open_mode &= ~SMB_ACCMODE;
3380 :
3381 : /* First take care of O_CREAT|O_EXCL interactions. */
3382 126 : switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
3383 38 : case (SMB_O_CREAT | SMB_O_EXCL):
3384 : /* File exists fail. File not exist create. */
3385 38 : create_disp = FILE_CREATE;
3386 38 : break;
3387 40 : case SMB_O_CREAT:
3388 : /* File exists open. File not exist create. */
3389 40 : create_disp = FILE_OPEN_IF;
3390 40 : break;
3391 48 : case SMB_O_EXCL:
3392 : /* O_EXCL on its own without O_CREAT is undefined.
3393 : We deliberately ignore it as some versions of
3394 : Linux CIFSFS can send a bare O_EXCL on the
3395 : wire which other filesystems in the kernel
3396 : ignore. See bug 9519 for details. */
3397 :
3398 : /* Fallthrough. */
3399 :
3400 : case 0:
3401 : /* File exists open. File not exist fail. */
3402 48 : create_disp = FILE_OPEN;
3403 48 : break;
3404 0 : default:
3405 0 : DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
3406 : (unsigned int)wire_open_mode ));
3407 0 : return NT_STATUS_INVALID_PARAMETER;
3408 : }
3409 :
3410 : /* Next factor in the effects of O_TRUNC. */
3411 126 : wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
3412 :
3413 126 : if (wire_open_mode & SMB_O_TRUNC) {
3414 4 : switch (create_disp) {
3415 0 : case FILE_CREATE:
3416 : /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
3417 : /* Leave create_disp alone as
3418 : (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
3419 : */
3420 : /* File exists fail. File not exist create. */
3421 4 : break;
3422 0 : case FILE_OPEN_IF:
3423 : /* SMB_O_CREAT | SMB_O_TRUNC */
3424 : /* File exists overwrite. File not exist create. */
3425 0 : create_disp = FILE_OVERWRITE_IF;
3426 0 : break;
3427 4 : case FILE_OPEN:
3428 : /* SMB_O_TRUNC */
3429 : /* File exists overwrite. File not exist fail. */
3430 4 : create_disp = FILE_OVERWRITE;
3431 4 : break;
3432 0 : default:
3433 : /* Cannot get here. */
3434 0 : smb_panic("smb_posix_open: logic error");
3435 : return NT_STATUS_INVALID_PARAMETER;
3436 : }
3437 : }
3438 :
3439 126 : raw_unixmode = IVAL(pdata,8);
3440 : /* Next 4 bytes are not yet defined. */
3441 :
3442 126 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3443 126 : (VALID_STAT(smb_fname->st) ?
3444 : PERM_EXISTING_FILE : PERM_NEW_FILE),
3445 : &unixmode);
3446 :
3447 126 : if (!NT_STATUS_IS_OK(status)) {
3448 0 : return status;
3449 : }
3450 :
3451 126 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3452 126 : if (!NT_STATUS_IS_OK(status)) {
3453 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3454 : nt_errstr(status));
3455 0 : return status;
3456 : }
3457 :
3458 126 : if (wire_open_mode & SMB_O_SYNC) {
3459 0 : create_options |= FILE_WRITE_THROUGH;
3460 : }
3461 126 : if (wire_open_mode & SMB_O_APPEND) {
3462 0 : access_mask |= FILE_APPEND_DATA;
3463 : }
3464 126 : if (wire_open_mode & SMB_O_DIRECT) {
3465 : /*
3466 : * BUG: this doesn't work anymore since
3467 : * e0814dc5082dd4ecca8a155e0ce24b073158fd92. But since
3468 : * FILE_FLAG_NO_BUFFERING isn't used at all in the IO codepath,
3469 : * it doesn't really matter.
3470 : */
3471 0 : attributes |= FILE_FLAG_NO_BUFFERING;
3472 : }
3473 :
3474 126 : if ((wire_open_mode & SMB_O_DIRECTORY) ||
3475 126 : VALID_STAT_OF_DIR(smb_fname->st)) {
3476 8 : if (access_mask != SMB_O_RDONLY_MAPPING) {
3477 4 : return NT_STATUS_FILE_IS_A_DIRECTORY;
3478 : }
3479 4 : create_options &= ~FILE_NON_DIRECTORY_FILE;
3480 4 : create_options |= FILE_DIRECTORY_FILE;
3481 : }
3482 :
3483 122 : DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
3484 : smb_fname_str_dbg(smb_fname),
3485 : (unsigned int)wire_open_mode,
3486 : (unsigned int)unixmode ));
3487 :
3488 122 : status = SMB_VFS_CREATE_FILE(
3489 : conn, /* conn */
3490 : req, /* req */
3491 : dirfsp, /* dirfsp */
3492 : smb_fname, /* fname */
3493 : access_mask, /* access_mask */
3494 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3495 : FILE_SHARE_DELETE),
3496 : create_disp, /* create_disposition*/
3497 : create_options, /* create_options */
3498 : attributes, /* file_attributes */
3499 : oplock_request, /* oplock_request */
3500 : NULL, /* lease */
3501 : 0, /* allocation_size */
3502 : 0, /* private_flags */
3503 : NULL, /* sd */
3504 : NULL, /* ea_list */
3505 : &fsp, /* result */
3506 : &info, /* pinfo */
3507 : posx, /* in_context_blobs */
3508 : NULL); /* out_context_blobs */
3509 :
3510 122 : TALLOC_FREE(posx);
3511 :
3512 122 : if (!NT_STATUS_IS_OK(status)) {
3513 8 : return status;
3514 : }
3515 :
3516 114 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3517 0 : extended_oplock_granted = True;
3518 : }
3519 :
3520 114 : if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3521 0 : extended_oplock_granted = True;
3522 : }
3523 :
3524 114 : info_level_return = SVAL(pdata,16);
3525 :
3526 : /* Allocate the correct return size. */
3527 :
3528 114 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3529 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3530 114 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3531 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3532 : } else {
3533 114 : *pdata_return_size = 12;
3534 : }
3535 :
3536 : /* Realloc the data size */
3537 114 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3538 114 : if (*ppdata == NULL) {
3539 0 : close_file_free(req, &fsp, ERROR_CLOSE);
3540 0 : *pdata_return_size = 0;
3541 0 : return NT_STATUS_NO_MEMORY;
3542 : }
3543 114 : pdata = *ppdata;
3544 :
3545 114 : if (extended_oplock_granted) {
3546 0 : if (flags & REQUEST_BATCH_OPLOCK) {
3547 0 : SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
3548 : } else {
3549 0 : SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
3550 : }
3551 114 : } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
3552 0 : SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
3553 : } else {
3554 114 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
3555 : }
3556 :
3557 114 : SSVAL(pdata,2,fsp->fnum);
3558 114 : SIVAL(pdata,4,info); /* Was file created etc. */
3559 :
3560 114 : switch (info_level_return) {
3561 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3562 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3563 0 : SSVAL(pdata,10,0); /* padding. */
3564 0 : store_file_unix_basic(conn, pdata + 12, fsp,
3565 0 : &smb_fname->st);
3566 0 : break;
3567 0 : case SMB_QUERY_FILE_UNIX_INFO2:
3568 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3569 0 : SSVAL(pdata,10,0); /* padding. */
3570 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
3571 0 : &smb_fname->st);
3572 0 : break;
3573 114 : default:
3574 114 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3575 114 : SSVAL(pdata,10,0); /* padding. */
3576 114 : break;
3577 : }
3578 114 : return NT_STATUS_OK;
3579 : }
3580 :
3581 : /****************************************************************************
3582 : Delete a file with POSIX semantics.
3583 : ****************************************************************************/
3584 :
3585 : struct smb_posix_unlink_state {
3586 : struct smb_filename *smb_fname;
3587 : struct files_struct *fsp;
3588 : NTSTATUS status;
3589 : };
3590 :
3591 248 : static void smb_posix_unlink_locked(struct share_mode_lock *lck,
3592 : void *private_data)
3593 : {
3594 248 : struct smb_posix_unlink_state *state = private_data;
3595 248 : char del = 1;
3596 0 : bool other_nonposix_opens;
3597 :
3598 248 : other_nonposix_opens = has_other_nonposix_opens(lck, state->fsp);
3599 248 : if (other_nonposix_opens) {
3600 : /* Fail with sharing violation. */
3601 8 : state->status = NT_STATUS_SHARING_VIOLATION;
3602 8 : return;
3603 : }
3604 :
3605 : /*
3606 : * Set the delete on close.
3607 : */
3608 240 : state->status = smb_set_file_disposition_info(state->fsp->conn,
3609 : &del,
3610 : 1,
3611 240 : state->fsp,
3612 : state->smb_fname);
3613 : }
3614 :
3615 532 : static NTSTATUS smb_posix_unlink(connection_struct *conn,
3616 : struct smb_request *req,
3617 : const char *pdata,
3618 : int total_data,
3619 : struct files_struct *dirfsp,
3620 : struct smb_filename *smb_fname)
3621 : {
3622 532 : struct smb_posix_unlink_state state = {};
3623 532 : NTSTATUS status = NT_STATUS_OK;
3624 532 : files_struct *fsp = NULL;
3625 532 : uint16_t flags = 0;
3626 532 : int info = 0;
3627 532 : int create_options = FILE_OPEN_REPARSE_POINT;
3628 532 : struct smb2_create_blobs *posx = NULL;
3629 :
3630 532 : if (!CAN_WRITE(conn)) {
3631 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3632 : }
3633 :
3634 532 : if (total_data < 2) {
3635 0 : return NT_STATUS_INVALID_PARAMETER;
3636 : }
3637 :
3638 532 : flags = SVAL(pdata,0);
3639 :
3640 532 : if (!VALID_STAT(smb_fname->st)) {
3641 276 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3642 : }
3643 :
3644 256 : if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
3645 40 : !VALID_STAT_OF_DIR(smb_fname->st)) {
3646 0 : return NT_STATUS_NOT_A_DIRECTORY;
3647 : }
3648 :
3649 256 : DEBUG(10,("smb_posix_unlink: %s %s\n",
3650 : (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
3651 : smb_fname_str_dbg(smb_fname)));
3652 :
3653 256 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
3654 44 : create_options |= FILE_DIRECTORY_FILE;
3655 : }
3656 :
3657 256 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
3658 256 : if (!NT_STATUS_IS_OK(status)) {
3659 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3660 : nt_errstr(status));
3661 0 : return status;
3662 : }
3663 :
3664 256 : status = SMB_VFS_CREATE_FILE(
3665 : conn, /* conn */
3666 : req, /* req */
3667 : dirfsp, /* dirfsp */
3668 : smb_fname, /* fname */
3669 : DELETE_ACCESS, /* access_mask */
3670 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3671 : FILE_SHARE_DELETE),
3672 : FILE_OPEN, /* create_disposition*/
3673 : create_options, /* create_options */
3674 : 0, /* file_attributes */
3675 : 0, /* oplock_request */
3676 : NULL, /* lease */
3677 : 0, /* allocation_size */
3678 : 0, /* private_flags */
3679 : NULL, /* sd */
3680 : NULL, /* ea_list */
3681 : &fsp, /* result */
3682 : &info, /* pinfo */
3683 : posx, /* in_context_blobs */
3684 : NULL); /* out_context_blobs */
3685 :
3686 256 : TALLOC_FREE(posx);
3687 :
3688 256 : if (!NT_STATUS_IS_OK(status)) {
3689 8 : return status;
3690 : }
3691 :
3692 : /*
3693 : * Don't lie to client. If we can't really delete due to
3694 : * non-POSIX opens return SHARING_VIOLATION.
3695 : */
3696 :
3697 248 : state = (struct smb_posix_unlink_state) {
3698 : .smb_fname = smb_fname,
3699 : .fsp = fsp,
3700 : };
3701 :
3702 248 : status = share_mode_do_locked_vfs_allowed(fsp->file_id,
3703 : smb_posix_unlink_locked,
3704 : &state);
3705 248 : if (!NT_STATUS_IS_OK(status)) {
3706 0 : DBG_ERR("share_mode_do_locked_vfs_allowed(%s) failed - %s\n",
3707 : fsp_str_dbg(fsp), nt_errstr(status));
3708 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
3709 0 : return NT_STATUS_INVALID_PARAMETER;
3710 : }
3711 :
3712 248 : status = state.status;
3713 248 : if (!NT_STATUS_IS_OK(status)) {
3714 8 : close_file_free(req, &fsp, NORMAL_CLOSE);
3715 8 : return status;
3716 : }
3717 240 : return close_file_free(req, &fsp, NORMAL_CLOSE);
3718 : }
3719 :
3720 : /****************************************************************************
3721 : Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
3722 : ****************************************************************************/
3723 :
3724 128 : static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
3725 : struct smb_request *req,
3726 : const char *pdata,
3727 : int total_data,
3728 : struct smb_filename *new_smb_fname)
3729 : {
3730 128 : char *link_target = NULL;
3731 0 : struct smb_filename target_fname;
3732 128 : TALLOC_CTX *ctx = talloc_tos();
3733 0 : NTSTATUS status;
3734 0 : int ret;
3735 128 : struct smb_filename *parent_fname = NULL;
3736 128 : struct smb_filename *base_name = NULL;
3737 :
3738 128 : if (!CAN_WRITE(conn)) {
3739 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3740 : }
3741 :
3742 : /* Set a symbolic link. */
3743 : /* Don't allow this if follow links is false. */
3744 :
3745 128 : if (total_data == 0) {
3746 0 : return NT_STATUS_INVALID_PARAMETER;
3747 : }
3748 :
3749 128 : if (!lp_follow_symlinks(SNUM(conn))) {
3750 0 : return NT_STATUS_ACCESS_DENIED;
3751 : }
3752 :
3753 128 : srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
3754 : total_data, STR_TERMINATE);
3755 :
3756 128 : if (!link_target) {
3757 0 : return NT_STATUS_INVALID_PARAMETER;
3758 : }
3759 :
3760 128 : target_fname = (struct smb_filename) {
3761 : .base_name = link_target,
3762 : };
3763 :
3764 : /* Removes @GMT tokens if any */
3765 128 : status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
3766 128 : if (!NT_STATUS_IS_OK(status)) {
3767 0 : return status;
3768 : }
3769 :
3770 128 : DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
3771 : new_smb_fname->base_name, link_target ));
3772 :
3773 128 : status = parent_pathref(talloc_tos(),
3774 : conn->cwd_fsp,
3775 : new_smb_fname,
3776 : &parent_fname,
3777 : &base_name);
3778 128 : if (!NT_STATUS_IS_OK(status)) {
3779 0 : return status;
3780 : }
3781 :
3782 128 : ret = SMB_VFS_SYMLINKAT(conn,
3783 : &target_fname,
3784 : parent_fname->fsp,
3785 : base_name);
3786 128 : if (ret != 0) {
3787 8 : TALLOC_FREE(parent_fname);
3788 8 : return map_nt_error_from_unix(errno);
3789 : }
3790 :
3791 120 : TALLOC_FREE(parent_fname);
3792 120 : return NT_STATUS_OK;
3793 : }
3794 :
3795 : /****************************************************************************
3796 : Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
3797 : ****************************************************************************/
3798 :
3799 16 : static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
3800 : struct smb_request *req,
3801 : const char *pdata, int total_data,
3802 : struct smb_filename *smb_fname_new)
3803 : {
3804 16 : char *oldname = NULL;
3805 16 : struct files_struct *src_dirfsp = NULL;
3806 16 : struct smb_filename *smb_fname_old = NULL;
3807 16 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
3808 16 : NTTIME old_twrp = 0;
3809 16 : TALLOC_CTX *ctx = talloc_tos();
3810 16 : NTSTATUS status = NT_STATUS_OK;
3811 :
3812 16 : if (!CAN_WRITE(conn)) {
3813 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3814 : }
3815 :
3816 : /* Set a hard link. */
3817 16 : if (total_data == 0) {
3818 0 : return NT_STATUS_INVALID_PARAMETER;
3819 : }
3820 :
3821 16 : if (req->posix_pathnames) {
3822 16 : srvstr_get_path_posix(ctx,
3823 : pdata,
3824 16 : req->flags2,
3825 : &oldname,
3826 : pdata,
3827 : total_data,
3828 : STR_TERMINATE,
3829 : &status);
3830 : } else {
3831 0 : srvstr_get_path(ctx,
3832 : pdata,
3833 0 : req->flags2,
3834 : &oldname,
3835 : pdata,
3836 : total_data,
3837 : STR_TERMINATE,
3838 : &status);
3839 : }
3840 16 : if (!NT_STATUS_IS_OK(status)) {
3841 0 : return status;
3842 : }
3843 :
3844 16 : DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
3845 : smb_fname_str_dbg(smb_fname_new), oldname));
3846 :
3847 16 : if (ucf_flags & UCF_GMT_PATHNAME) {
3848 0 : extract_snapshot_token(oldname, &old_twrp);
3849 : }
3850 16 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &oldname);
3851 16 : if (!NT_STATUS_IS_OK(status)) {
3852 0 : return status;
3853 : }
3854 16 : status = filename_convert_dirfsp(ctx,
3855 : conn,
3856 : oldname,
3857 : ucf_flags,
3858 : old_twrp,
3859 : &src_dirfsp,
3860 : &smb_fname_old);
3861 16 : if (!NT_STATUS_IS_OK(status)) {
3862 0 : return status;
3863 : }
3864 :
3865 16 : return hardlink_internals(ctx,
3866 : conn,
3867 : req,
3868 : false,
3869 : smb_fname_old,
3870 : smb_fname_new);
3871 : }
3872 :
3873 : /****************************************************************************
3874 : Allow a UNIX info mknod.
3875 : ****************************************************************************/
3876 :
3877 2 : static NTSTATUS smb_unix_mknod(connection_struct *conn,
3878 : const char *pdata,
3879 : int total_data,
3880 : struct files_struct *dirfsp,
3881 : const struct smb_filename *smb_fname)
3882 : {
3883 2 : uint32_t file_type = IVAL(pdata,56);
3884 : #if defined(HAVE_MAKEDEV)
3885 2 : uint32_t dev_major = IVAL(pdata,60);
3886 2 : uint32_t dev_minor = IVAL(pdata,68);
3887 : #endif
3888 2 : SMB_DEV_T dev = (SMB_DEV_T)0;
3889 2 : uint32_t raw_unixmode = IVAL(pdata,84);
3890 0 : NTSTATUS status;
3891 0 : mode_t unixmode;
3892 0 : int ret;
3893 2 : struct smb_filename *parent_fname = NULL;
3894 2 : struct smb_filename *atname = NULL;
3895 :
3896 2 : if (total_data < 100) {
3897 0 : return NT_STATUS_INVALID_PARAMETER;
3898 : }
3899 :
3900 2 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3901 : PERM_NEW_FILE, &unixmode);
3902 2 : if (!NT_STATUS_IS_OK(status)) {
3903 0 : return status;
3904 : }
3905 :
3906 : #if defined(HAVE_MAKEDEV)
3907 2 : dev = makedev(dev_major, dev_minor);
3908 : #endif
3909 :
3910 2 : switch (file_type) {
3911 : /* We can't create other objects here. */
3912 0 : case UNIX_TYPE_FILE:
3913 : case UNIX_TYPE_DIR:
3914 : case UNIX_TYPE_SYMLINK:
3915 0 : return NT_STATUS_ACCESS_DENIED;
3916 : #if defined(S_IFIFO)
3917 1 : case UNIX_TYPE_FIFO:
3918 1 : unixmode |= S_IFIFO;
3919 1 : break;
3920 : #endif
3921 : #if defined(S_IFSOCK)
3922 1 : case UNIX_TYPE_SOCKET:
3923 1 : unixmode |= S_IFSOCK;
3924 1 : break;
3925 : #endif
3926 : #if defined(S_IFCHR)
3927 0 : case UNIX_TYPE_CHARDEV:
3928 : /* This is only allowed for root. */
3929 0 : if (get_current_uid(conn) != sec_initial_uid()) {
3930 0 : return NT_STATUS_ACCESS_DENIED;
3931 : }
3932 0 : unixmode |= S_IFCHR;
3933 0 : break;
3934 : #endif
3935 : #if defined(S_IFBLK)
3936 0 : case UNIX_TYPE_BLKDEV:
3937 0 : if (get_current_uid(conn) != sec_initial_uid()) {
3938 0 : return NT_STATUS_ACCESS_DENIED;
3939 : }
3940 0 : unixmode |= S_IFBLK;
3941 0 : break;
3942 : #endif
3943 0 : default:
3944 0 : return NT_STATUS_INVALID_PARAMETER;
3945 : }
3946 :
3947 2 : DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
3948 : "%.0f mode 0%o for file %s\n", (double)dev,
3949 : (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
3950 :
3951 2 : status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
3952 : talloc_tos(),
3953 : smb_fname,
3954 : &parent_fname,
3955 : &atname);
3956 2 : if (!NT_STATUS_IS_OK(status)) {
3957 0 : return status;
3958 : }
3959 :
3960 : /* Ok - do the mknod. */
3961 2 : ret = SMB_VFS_MKNODAT(conn,
3962 : dirfsp,
3963 : atname,
3964 : unixmode,
3965 : dev);
3966 :
3967 2 : if (ret != 0) {
3968 0 : TALLOC_FREE(parent_fname);
3969 0 : return map_nt_error_from_unix(errno);
3970 : }
3971 :
3972 : /* If any of the other "set" calls fail we
3973 : * don't want to end up with a half-constructed mknod.
3974 : */
3975 :
3976 2 : if (lp_inherit_permissions(SNUM(conn))) {
3977 0 : inherit_access_posix_acl(conn,
3978 : dirfsp,
3979 : smb_fname,
3980 : unixmode);
3981 : }
3982 2 : TALLOC_FREE(parent_fname);
3983 :
3984 2 : return NT_STATUS_OK;
3985 : }
3986 :
3987 : /****************************************************************************
3988 : Deal with SMB_SET_FILE_UNIX_BASIC.
3989 : ****************************************************************************/
3990 :
3991 170 : static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
3992 : struct smb_request *req,
3993 : const char *pdata,
3994 : int total_data,
3995 : struct files_struct *dirfsp,
3996 : files_struct *fsp,
3997 : struct smb_filename *smb_fname)
3998 : {
3999 0 : struct smb_file_time ft;
4000 0 : uint32_t raw_unixmode;
4001 0 : mode_t unixmode;
4002 170 : off_t size = 0;
4003 170 : uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
4004 170 : gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
4005 170 : NTSTATUS status = NT_STATUS_OK;
4006 0 : enum perm_type ptype;
4007 170 : files_struct *all_fsps = NULL;
4008 170 : bool modify_mtime = true;
4009 0 : struct file_id id;
4010 0 : SMB_STRUCT_STAT sbuf;
4011 :
4012 170 : if (!CAN_WRITE(conn)) {
4013 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
4014 : }
4015 :
4016 170 : init_smb_file_time(&ft);
4017 :
4018 170 : if (total_data < 100) {
4019 0 : return NT_STATUS_INVALID_PARAMETER;
4020 : }
4021 :
4022 170 : if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
4023 16 : IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
4024 16 : size=IVAL(pdata,0); /* first 8 Bytes are size */
4025 16 : size |= (((off_t)IVAL(pdata,4)) << 32);
4026 : }
4027 :
4028 170 : ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
4029 170 : ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
4030 170 : set_owner = (uid_t)IVAL(pdata,40);
4031 170 : set_grp = (gid_t)IVAL(pdata,48);
4032 170 : raw_unixmode = IVAL(pdata,84);
4033 :
4034 170 : if (VALID_STAT(smb_fname->st)) {
4035 168 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
4036 4 : ptype = PERM_EXISTING_DIR;
4037 : } else {
4038 164 : ptype = PERM_EXISTING_FILE;
4039 : }
4040 : } else {
4041 2 : ptype = PERM_NEW_FILE;
4042 : }
4043 :
4044 170 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
4045 : ptype, &unixmode);
4046 170 : if (!NT_STATUS_IS_OK(status)) {
4047 0 : return status;
4048 : }
4049 :
4050 170 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
4051 : "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
4052 : smb_fname_str_dbg(smb_fname), (double)size,
4053 : (unsigned int)set_owner, (unsigned int)set_grp,
4054 : (int)raw_unixmode));
4055 :
4056 170 : sbuf = smb_fname->st;
4057 :
4058 170 : if (!VALID_STAT(sbuf)) {
4059 : /*
4060 : * The only valid use of this is to create character and block
4061 : * devices, and named pipes. This is deprecated (IMHO) and
4062 : * a new info level should be used for mknod. JRA.
4063 : */
4064 :
4065 2 : if (dirfsp == NULL) {
4066 0 : return NT_STATUS_INVALID_PARAMETER;
4067 : }
4068 :
4069 2 : return smb_unix_mknod(conn,
4070 : pdata,
4071 : total_data,
4072 : dirfsp,
4073 : smb_fname);
4074 : }
4075 :
4076 : #if 1
4077 : /* Horrible backwards compatibility hack as an old server bug
4078 : * allowed a CIFS client bug to remain unnoticed :-(. JRA.
4079 : * */
4080 :
4081 168 : if (!size) {
4082 168 : size = get_file_size_stat(&sbuf);
4083 : }
4084 : #endif
4085 :
4086 : /*
4087 : * Deal with the UNIX specific mode set.
4088 : */
4089 :
4090 168 : if (raw_unixmode != SMB_MODE_NO_CHANGE) {
4091 0 : int ret;
4092 :
4093 36 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4094 24 : DBG_WARNING("Can't set mode on symlink %s\n",
4095 : smb_fname_str_dbg(smb_fname));
4096 24 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4097 : }
4098 :
4099 12 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4100 : "setting mode 0%o for file %s\n",
4101 : (unsigned int)unixmode,
4102 : smb_fname_str_dbg(smb_fname)));
4103 12 : ret = SMB_VFS_FCHMOD(fsp, unixmode);
4104 12 : if (ret != 0) {
4105 0 : return map_nt_error_from_unix(errno);
4106 : }
4107 : }
4108 :
4109 : /*
4110 : * Deal with the UNIX specific uid set.
4111 : */
4112 :
4113 144 : if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
4114 0 : (sbuf.st_ex_uid != set_owner)) {
4115 0 : int ret;
4116 :
4117 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4118 : "changing owner %u for path %s\n",
4119 : (unsigned int)set_owner,
4120 : smb_fname_str_dbg(smb_fname)));
4121 :
4122 0 : if (fsp &&
4123 0 : !fsp->fsp_flags.is_pathref &&
4124 0 : fsp_get_io_fd(fsp) != -1)
4125 : {
4126 0 : ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
4127 : } else {
4128 : /*
4129 : * UNIX extensions calls must always operate
4130 : * on symlinks.
4131 : */
4132 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname,
4133 : set_owner, (gid_t)-1);
4134 : }
4135 :
4136 0 : if (ret != 0) {
4137 0 : status = map_nt_error_from_unix(errno);
4138 0 : return status;
4139 : }
4140 : }
4141 :
4142 : /*
4143 : * Deal with the UNIX specific gid set.
4144 : */
4145 :
4146 144 : if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
4147 0 : (sbuf.st_ex_gid != set_grp)) {
4148 0 : int ret;
4149 :
4150 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4151 : "changing group %u for file %s\n",
4152 : (unsigned int)set_grp,
4153 : smb_fname_str_dbg(smb_fname)));
4154 0 : if (fsp &&
4155 0 : !fsp->fsp_flags.is_pathref &&
4156 0 : fsp_get_io_fd(fsp) != -1)
4157 : {
4158 0 : ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
4159 : } else {
4160 : /*
4161 : * UNIX extensions calls must always operate
4162 : * on symlinks.
4163 : */
4164 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
4165 : set_grp);
4166 : }
4167 0 : if (ret != 0) {
4168 0 : status = map_nt_error_from_unix(errno);
4169 0 : return status;
4170 : }
4171 : }
4172 :
4173 : /* Deal with any size changes. */
4174 :
4175 144 : if (S_ISREG(sbuf.st_ex_mode)) {
4176 140 : status = smb_set_file_size(conn, req,
4177 : fsp,
4178 : smb_fname,
4179 : &sbuf,
4180 : size,
4181 : false);
4182 140 : if (!NT_STATUS_IS_OK(status)) {
4183 0 : return status;
4184 : }
4185 : }
4186 :
4187 : /* Deal with any time changes. */
4188 144 : if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
4189 : /* No change, don't cancel anything. */
4190 144 : return status;
4191 : }
4192 :
4193 0 : id = vfs_file_id_from_sbuf(conn, &sbuf);
4194 0 : for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
4195 0 : all_fsps = file_find_di_next(all_fsps, true)) {
4196 : /*
4197 : * We're setting the time explicitly for UNIX.
4198 : * Cancel any pending changes over all handles.
4199 : */
4200 0 : all_fsps->fsp_flags.update_write_time_on_close = false;
4201 0 : TALLOC_FREE(all_fsps->update_write_time_event);
4202 : }
4203 :
4204 : /*
4205 : * Override the "setting_write_time"
4206 : * parameter here as it almost does what
4207 : * we need. Just remember if we modified
4208 : * mtime and send the notify ourselves.
4209 : */
4210 0 : if (is_omit_timespec(&ft.mtime)) {
4211 0 : modify_mtime = false;
4212 : }
4213 :
4214 0 : status = smb_set_file_time(conn,
4215 : fsp,
4216 : smb_fname,
4217 : &ft,
4218 : false);
4219 0 : if (modify_mtime) {
4220 0 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
4221 0 : FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
4222 : }
4223 0 : return status;
4224 : }
4225 :
4226 : /****************************************************************************
4227 : Deal with SMB_SET_FILE_UNIX_INFO2.
4228 : ****************************************************************************/
4229 :
4230 140 : static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
4231 : struct smb_request *req,
4232 : const char *pdata,
4233 : int total_data,
4234 : struct files_struct *dirfsp,
4235 : files_struct *fsp,
4236 : struct smb_filename *smb_fname)
4237 : {
4238 0 : NTSTATUS status;
4239 0 : uint32_t smb_fflags;
4240 0 : uint32_t smb_fmask;
4241 :
4242 140 : if (!CAN_WRITE(conn)) {
4243 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
4244 : }
4245 :
4246 140 : if (total_data < 116) {
4247 0 : return NT_STATUS_INVALID_PARAMETER;
4248 : }
4249 :
4250 : /* Start by setting all the fields that are common between UNIX_BASIC
4251 : * and UNIX_INFO2.
4252 : */
4253 140 : status = smb_set_file_unix_basic(conn,
4254 : req,
4255 : pdata,
4256 : total_data,
4257 : dirfsp,
4258 : fsp,
4259 : smb_fname);
4260 140 : if (!NT_STATUS_IS_OK(status)) {
4261 8 : return status;
4262 : }
4263 :
4264 132 : smb_fflags = IVAL(pdata, 108);
4265 132 : smb_fmask = IVAL(pdata, 112);
4266 :
4267 : /* NB: We should only attempt to alter the file flags if the client
4268 : * sends a non-zero mask.
4269 : */
4270 132 : if (smb_fmask != 0) {
4271 128 : int stat_fflags = 0;
4272 :
4273 128 : if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
4274 : smb_fmask, &stat_fflags)) {
4275 : /* Client asked to alter a flag we don't understand. */
4276 128 : return NT_STATUS_INVALID_PARAMETER;
4277 : }
4278 :
4279 0 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4280 0 : DBG_WARNING("Can't change flags on symlink %s\n",
4281 : smb_fname_str_dbg(smb_fname));
4282 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4283 : }
4284 0 : if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
4285 0 : return map_nt_error_from_unix(errno);
4286 : }
4287 : }
4288 :
4289 : /* XXX: need to add support for changing the create_time here. You
4290 : * can do this for paths on Darwin with setattrlist(2). The right way
4291 : * to hook this up is probably by extending the VFS utimes interface.
4292 : */
4293 :
4294 4 : return NT_STATUS_OK;
4295 : }
4296 :
4297 : /****************************************************************************
4298 : Deal with SMB_SET_POSIX_ACL.
4299 : ****************************************************************************/
4300 :
4301 16 : static NTSTATUS smb_set_posix_acl(connection_struct *conn,
4302 : struct smb_request *req,
4303 : const char *pdata,
4304 : int total_data_in,
4305 : files_struct *fsp,
4306 : struct smb_filename *smb_fname)
4307 : {
4308 : #if !defined(HAVE_POSIX_ACLS)
4309 : return NT_STATUS_INVALID_LEVEL;
4310 : #else
4311 0 : uint16_t posix_acl_version;
4312 0 : uint16_t num_file_acls;
4313 0 : uint16_t num_def_acls;
4314 16 : bool valid_file_acls = true;
4315 16 : bool valid_def_acls = true;
4316 0 : NTSTATUS status;
4317 0 : unsigned int size_needed;
4318 0 : unsigned int total_data;
4319 16 : bool close_fsp = false;
4320 :
4321 16 : if (total_data_in < 0) {
4322 0 : status = NT_STATUS_INVALID_PARAMETER;
4323 0 : goto out;
4324 : }
4325 :
4326 16 : total_data = total_data_in;
4327 :
4328 16 : if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
4329 0 : status = NT_STATUS_INVALID_PARAMETER;
4330 0 : goto out;
4331 : }
4332 16 : posix_acl_version = SVAL(pdata,0);
4333 16 : num_file_acls = SVAL(pdata,2);
4334 16 : num_def_acls = SVAL(pdata,4);
4335 :
4336 16 : if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4337 4 : valid_file_acls = false;
4338 4 : num_file_acls = 0;
4339 : }
4340 :
4341 16 : if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4342 0 : valid_def_acls = false;
4343 0 : num_def_acls = 0;
4344 : }
4345 :
4346 16 : if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
4347 8 : status = NT_STATUS_INVALID_PARAMETER;
4348 8 : goto out;
4349 : }
4350 :
4351 : /* Wrap checks. */
4352 0 : if (num_file_acls + num_def_acls < num_file_acls) {
4353 : status = NT_STATUS_INVALID_PARAMETER;
4354 : goto out;
4355 : }
4356 :
4357 8 : size_needed = num_file_acls + num_def_acls;
4358 :
4359 : /*
4360 : * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
4361 : * than UINT_MAX, so check by division.
4362 : */
4363 8 : if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
4364 0 : status = NT_STATUS_INVALID_PARAMETER;
4365 0 : goto out;
4366 : }
4367 :
4368 8 : size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
4369 8 : if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
4370 0 : status = NT_STATUS_INVALID_PARAMETER;
4371 0 : goto out;
4372 : }
4373 8 : size_needed += SMB_POSIX_ACL_HEADER_SIZE;
4374 :
4375 8 : if (total_data < size_needed) {
4376 0 : status = NT_STATUS_INVALID_PARAMETER;
4377 0 : goto out;
4378 : }
4379 :
4380 : /*
4381 : * Ensure we always operate on a file descriptor, not just
4382 : * the filename.
4383 : */
4384 8 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
4385 8 : uint32_t access_mask = SEC_STD_WRITE_OWNER|
4386 : SEC_STD_WRITE_DAC|
4387 : SEC_STD_READ_CONTROL|
4388 : FILE_READ_ATTRIBUTES|
4389 : FILE_WRITE_ATTRIBUTES;
4390 :
4391 8 : status = get_posix_fsp(conn,
4392 : req,
4393 : smb_fname,
4394 : access_mask,
4395 : &fsp);
4396 :
4397 8 : if (!NT_STATUS_IS_OK(status)) {
4398 4 : goto out;
4399 : }
4400 4 : close_fsp = true;
4401 : }
4402 :
4403 : /* Here we know fsp != NULL */
4404 4 : SMB_ASSERT(fsp != NULL);
4405 :
4406 4 : status = refuse_symlink_fsp(fsp);
4407 4 : if (!NT_STATUS_IS_OK(status)) {
4408 0 : goto out;
4409 : }
4410 :
4411 : /* If we have a default acl, this *must* be a directory. */
4412 4 : if (valid_def_acls && !fsp->fsp_flags.is_directory) {
4413 0 : DBG_INFO("Can't set default acls on "
4414 : "non-directory %s\n",
4415 : fsp_str_dbg(fsp));
4416 0 : return NT_STATUS_INVALID_HANDLE;
4417 : }
4418 :
4419 4 : DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
4420 : "num_def_acls = %"PRIu16"\n",
4421 : fsp_str_dbg(fsp),
4422 : num_file_acls,
4423 : num_def_acls);
4424 :
4425 : /* Move pdata to the start of the file ACL entries. */
4426 4 : pdata += SMB_POSIX_ACL_HEADER_SIZE;
4427 :
4428 4 : if (valid_file_acls) {
4429 0 : status = set_unix_posix_acl(conn,
4430 : fsp,
4431 : num_file_acls,
4432 : pdata);
4433 0 : if (!NT_STATUS_IS_OK(status)) {
4434 0 : goto out;
4435 : }
4436 : }
4437 :
4438 : /* Move pdata to the start of the default ACL entries. */
4439 4 : pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
4440 :
4441 4 : if (valid_def_acls) {
4442 4 : status = set_unix_posix_default_acl(conn,
4443 : fsp,
4444 : num_def_acls,
4445 : pdata);
4446 4 : if (!NT_STATUS_IS_OK(status)) {
4447 0 : goto out;
4448 : }
4449 : }
4450 :
4451 4 : status = NT_STATUS_OK;
4452 :
4453 16 : out:
4454 :
4455 16 : if (close_fsp) {
4456 4 : (void)close_file_free(req, &fsp, NORMAL_CLOSE);
4457 : }
4458 16 : return status;
4459 : #endif
4460 : }
4461 :
4462 1408 : static void call_trans2setpathinfo(
4463 : connection_struct *conn,
4464 : struct smb_request *req,
4465 : char **pparams,
4466 : int total_params,
4467 : char **ppdata,
4468 : int total_data,
4469 : unsigned int max_data_bytes)
4470 : {
4471 12 : uint16_t info_level;
4472 1408 : struct smb_filename *smb_fname = NULL;
4473 1408 : struct files_struct *dirfsp = NULL;
4474 1408 : struct files_struct *fsp = NULL;
4475 1408 : char *params = *pparams;
4476 1408 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4477 1408 : NTTIME twrp = 0;
4478 1408 : char *fname = NULL;
4479 12 : bool info_level_handled;
4480 1408 : int data_return_size = 0;
4481 12 : NTSTATUS status;
4482 :
4483 1408 : if (params == NULL) {
4484 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4485 0 : return;
4486 : }
4487 :
4488 : /* set path info */
4489 1408 : if (total_params < 7) {
4490 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4491 0 : return;
4492 : }
4493 :
4494 1408 : info_level = SVAL(params,0);
4495 :
4496 1408 : if (INFO_LEVEL_IS_UNIX(info_level)) {
4497 1110 : if (!lp_smb1_unix_extensions()) {
4498 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4499 0 : return;
4500 : }
4501 1110 : if (!req->posix_pathnames) {
4502 6 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4503 6 : return;
4504 : }
4505 : }
4506 :
4507 1402 : if (req->posix_pathnames) {
4508 1208 : srvstr_get_path_posix(req,
4509 : params,
4510 1208 : req->flags2,
4511 : &fname,
4512 1208 : ¶ms[6],
4513 1208 : total_params - 6,
4514 : STR_TERMINATE,
4515 : &status);
4516 : } else {
4517 194 : srvstr_get_path(req,
4518 : params,
4519 194 : req->flags2,
4520 : &fname,
4521 194 : ¶ms[6],
4522 194 : total_params - 6,
4523 : STR_TERMINATE,
4524 : &status);
4525 : }
4526 1402 : if (!NT_STATUS_IS_OK(status)) {
4527 0 : reply_nterror(req, status);
4528 0 : return;
4529 : }
4530 :
4531 1402 : DBG_NOTICE("fname=%s info_level=%d totdata=%d\n",
4532 : fname,
4533 : info_level,
4534 : total_data);
4535 :
4536 1402 : if (ucf_flags & UCF_GMT_PATHNAME) {
4537 0 : extract_snapshot_token(fname, &twrp);
4538 : }
4539 1402 : status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
4540 1402 : if (!NT_STATUS_IS_OK(status)) {
4541 0 : reply_nterror(req, status);
4542 0 : return;
4543 : }
4544 1402 : status = filename_convert_dirfsp(req,
4545 : conn,
4546 : fname,
4547 : ucf_flags,
4548 : twrp,
4549 : &dirfsp,
4550 : &smb_fname);
4551 1402 : if (!NT_STATUS_IS_OK(status)) {
4552 60 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4553 0 : reply_botherror(req,
4554 : NT_STATUS_PATH_NOT_COVERED,
4555 : ERRSRV, ERRbadpath);
4556 0 : return;
4557 : }
4558 60 : reply_nterror(req, status);
4559 60 : return;
4560 : }
4561 :
4562 1342 : info_level_handled = true; /* Untouched in switch cases below */
4563 :
4564 1342 : switch (info_level) {
4565 :
4566 294 : default:
4567 294 : info_level_handled = false;
4568 294 : break;
4569 :
4570 174 : case SMB_POSIX_PATH_OPEN:
4571 174 : status = smb_posix_open(conn,
4572 : req,
4573 : ppdata,
4574 : total_data,
4575 : dirfsp,
4576 : smb_fname,
4577 : &data_return_size);
4578 174 : break;
4579 :
4580 532 : case SMB_POSIX_PATH_UNLINK:
4581 532 : status = smb_posix_unlink(conn,
4582 : req,
4583 : *ppdata,
4584 : total_data,
4585 : dirfsp,
4586 : smb_fname);
4587 532 : break;
4588 :
4589 128 : case SMB_SET_FILE_UNIX_LINK:
4590 128 : status = smb_set_file_unix_link(
4591 : conn, req, *ppdata, total_data, smb_fname);
4592 128 : break;
4593 :
4594 16 : case SMB_SET_FILE_UNIX_HLINK:
4595 16 : status = smb_set_file_unix_hlink(
4596 : conn, req, *ppdata, total_data, smb_fname);
4597 16 : break;
4598 :
4599 30 : case SMB_SET_FILE_UNIX_BASIC:
4600 30 : status = smb_set_file_unix_basic(conn,
4601 : req,
4602 : *ppdata,
4603 : total_data,
4604 : dirfsp,
4605 30 : smb_fname->fsp,
4606 : smb_fname);
4607 30 : break;
4608 :
4609 140 : case SMB_SET_FILE_UNIX_INFO2:
4610 140 : status = smb_set_file_unix_info2(conn,
4611 : req,
4612 : *ppdata,
4613 : total_data,
4614 : dirfsp,
4615 140 : smb_fname->fsp,
4616 : smb_fname);
4617 140 : break;
4618 16 : case SMB_SET_POSIX_ACL:
4619 16 : status = smb_set_posix_acl(
4620 : conn, req, *ppdata, total_data, NULL, smb_fname);
4621 16 : break;
4622 : }
4623 :
4624 1330 : if (info_level_handled) {
4625 1036 : handle_trans2setfilepathinfo_result(
4626 : conn,
4627 : req,
4628 : info_level,
4629 : status,
4630 : *ppdata,
4631 : data_return_size,
4632 : max_data_bytes);
4633 1036 : return;
4634 : }
4635 :
4636 : /*
4637 : * smb_fname->fsp may be NULL if smb_fname points at a symlink
4638 : * and we're in POSIX context, so be careful when using fsp
4639 : * below, it can still be NULL.
4640 : */
4641 306 : fsp = smb_fname->fsp;
4642 :
4643 306 : status = smbd_do_setfilepathinfo(
4644 : conn,
4645 : req,
4646 : req,
4647 : info_level,
4648 : fsp,
4649 : smb_fname,
4650 : ppdata,
4651 : total_data,
4652 : &data_return_size);
4653 :
4654 306 : handle_trans2setfilepathinfo_result(
4655 : conn,
4656 : req,
4657 : info_level,
4658 : status,
4659 : *ppdata,
4660 : data_return_size,
4661 : max_data_bytes);
4662 : }
4663 :
4664 4265 : static void call_trans2setfileinfo(
4665 : connection_struct *conn,
4666 : struct smb_request *req,
4667 : char **pparams,
4668 : int total_params,
4669 : char **ppdata,
4670 : int total_data,
4671 : unsigned int max_data_bytes)
4672 : {
4673 4265 : char *pdata = *ppdata;
4674 537 : uint16_t info_level;
4675 4265 : struct smb_filename *smb_fname = NULL;
4676 4265 : struct files_struct *fsp = NULL;
4677 4265 : char *params = *pparams;
4678 4265 : int data_return_size = 0;
4679 537 : bool info_level_handled;
4680 537 : NTSTATUS status;
4681 537 : int ret;
4682 :
4683 4265 : if (params == NULL) {
4684 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4685 0 : return;
4686 : }
4687 4265 : if (total_params < 4) {
4688 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4689 0 : return;
4690 : }
4691 :
4692 4265 : fsp = file_fsp(req, SVAL(params,0));
4693 : /* Basic check for non-null fsp. */
4694 4265 : if (!check_fsp_open(conn, req, fsp)) {
4695 0 : return;
4696 : }
4697 4265 : info_level = SVAL(params,2);
4698 :
4699 4265 : if (INFO_LEVEL_IS_UNIX(info_level)) {
4700 36 : if (!lp_smb1_unix_extensions()) {
4701 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4702 0 : return;
4703 : }
4704 36 : if (!req->posix_pathnames) {
4705 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4706 0 : return;
4707 : }
4708 : }
4709 :
4710 4265 : smb_fname = fsp->fsp_name;
4711 :
4712 4265 : DBG_NOTICE("fnum=%s fname=%s info_level=%d totdata=%d\n",
4713 : fsp_fnum_dbg(fsp),
4714 : fsp_str_dbg(fsp),
4715 : info_level,
4716 : total_data);
4717 :
4718 4265 : if (fsp_get_pathref_fd(fsp) == -1) {
4719 : /*
4720 : * This is actually a SETFILEINFO on a directory
4721 : * handle (returned from an NT SMB). NT5.0 seems
4722 : * to do this call. JRA.
4723 : */
4724 0 : ret = vfs_stat(conn, smb_fname);
4725 0 : if (ret != 0) {
4726 0 : DBG_NOTICE("vfs_stat of %s failed (%s)\n",
4727 : smb_fname_str_dbg(smb_fname),
4728 : strerror(errno));
4729 0 : reply_nterror(req, map_nt_error_from_unix(errno));
4730 0 : return;
4731 : }
4732 4265 : } else if (fsp->print_file) {
4733 : /*
4734 : * Doing a DELETE_ON_CLOSE should cancel a print job.
4735 : */
4736 2 : if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) &&
4737 2 : CVAL(pdata,0)) {
4738 :
4739 2 : fsp->fsp_flags.delete_on_close = true;
4740 :
4741 2 : DBG_NOTICE("Cancelling print job (%s)\n",
4742 : fsp_str_dbg(fsp));
4743 :
4744 2 : SSVAL(params,0,0);
4745 2 : send_trans2_replies(
4746 : conn,
4747 : req,
4748 2 : NT_STATUS_OK,
4749 : params,
4750 : 2,
4751 : *ppdata, 0,
4752 : max_data_bytes);
4753 2 : return;
4754 : } else {
4755 0 : reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
4756 0 : return;
4757 : }
4758 : } else {
4759 : /*
4760 : * Original code - this is an open file.
4761 : */
4762 4263 : status = vfs_stat_fsp(fsp);
4763 4263 : if (!NT_STATUS_IS_OK(status)) {
4764 0 : DBG_NOTICE("fstat of %s failed (%s)\n",
4765 : fsp_fnum_dbg(fsp),
4766 : nt_errstr(status));
4767 0 : reply_nterror(req, status);
4768 0 : return;
4769 : }
4770 : }
4771 :
4772 4263 : info_level_handled = true; /* Untouched in switch cases below */
4773 :
4774 4263 : switch (info_level) {
4775 :
4776 3690 : default:
4777 3690 : info_level_handled = false;
4778 3690 : break;
4779 :
4780 0 : case SMB_SET_FILE_UNIX_BASIC:
4781 0 : status = smb_set_file_unix_basic(conn,
4782 : req,
4783 : pdata,
4784 : total_data,
4785 : NULL,
4786 : fsp,
4787 : smb_fname);
4788 0 : break;
4789 :
4790 0 : case SMB_SET_FILE_UNIX_INFO2:
4791 0 : status = smb_set_file_unix_info2(conn,
4792 : req,
4793 : pdata,
4794 : total_data,
4795 : NULL,
4796 : fsp,
4797 : smb_fname);
4798 0 : break;
4799 :
4800 36 : case SMB_SET_POSIX_LOCK:
4801 36 : status = smb_set_posix_lock(
4802 : conn, req, *ppdata, total_data, fsp);
4803 36 : break;
4804 : }
4805 :
4806 3726 : if (info_level_handled) {
4807 36 : handle_trans2setfilepathinfo_result(
4808 : conn,
4809 : req,
4810 : info_level,
4811 : status,
4812 : *ppdata,
4813 : data_return_size,
4814 : max_data_bytes);
4815 36 : return;
4816 : }
4817 :
4818 4227 : status = smbd_do_setfilepathinfo(
4819 : conn,
4820 : req,
4821 : req,
4822 : info_level,
4823 : fsp,
4824 : smb_fname,
4825 : ppdata,
4826 : total_data,
4827 : &data_return_size);
4828 :
4829 4227 : handle_trans2setfilepathinfo_result(
4830 : conn,
4831 : req,
4832 : info_level,
4833 : status,
4834 : *ppdata,
4835 : data_return_size,
4836 : max_data_bytes);
4837 : }
4838 :
4839 : /****************************************************************************
4840 : Reply to a TRANS2_MKDIR (make directory with extended attributes).
4841 : ****************************************************************************/
4842 :
4843 23 : static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
4844 : char **pparams, int total_params,
4845 : char **ppdata, int total_data,
4846 : unsigned int max_data_bytes)
4847 : {
4848 23 : struct files_struct *dirfsp = NULL;
4849 23 : struct files_struct *fsp = NULL;
4850 23 : struct smb_filename *smb_dname = NULL;
4851 23 : char *params = *pparams;
4852 23 : char *pdata = *ppdata;
4853 23 : char *directory = NULL;
4854 23 : NTSTATUS status = NT_STATUS_OK;
4855 23 : struct ea_list *ea_list = NULL;
4856 23 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4857 23 : NTTIME twrp = 0;
4858 23 : TALLOC_CTX *ctx = talloc_tos();
4859 :
4860 23 : if (!CAN_WRITE(conn)) {
4861 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4862 0 : return;
4863 : }
4864 :
4865 23 : if (total_params < 5) {
4866 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4867 0 : return;
4868 : }
4869 :
4870 23 : if (req->posix_pathnames) {
4871 0 : srvstr_get_path_posix(ctx,
4872 : params,
4873 0 : req->flags2,
4874 : &directory,
4875 0 : ¶ms[4],
4876 0 : total_params - 4,
4877 : STR_TERMINATE,
4878 : &status);
4879 : } else {
4880 23 : srvstr_get_path(ctx,
4881 : params,
4882 23 : req->flags2,
4883 : &directory,
4884 23 : ¶ms[4],
4885 23 : total_params - 4,
4886 : STR_TERMINATE,
4887 : &status);
4888 : }
4889 23 : if (!NT_STATUS_IS_OK(status)) {
4890 0 : reply_nterror(req, status);
4891 0 : return;
4892 : }
4893 :
4894 23 : DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
4895 :
4896 23 : if (ucf_flags & UCF_GMT_PATHNAME) {
4897 0 : extract_snapshot_token(directory, &twrp);
4898 : }
4899 23 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &directory);
4900 23 : if (!NT_STATUS_IS_OK(status)) {
4901 0 : reply_nterror(req, status);
4902 0 : goto out;
4903 : }
4904 23 : status = filename_convert_dirfsp(ctx,
4905 : conn,
4906 : directory,
4907 : ucf_flags,
4908 : twrp,
4909 : &dirfsp,
4910 : &smb_dname);
4911 23 : if (!NT_STATUS_IS_OK(status)) {
4912 5 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4913 0 : reply_botherror(req,
4914 : NT_STATUS_PATH_NOT_COVERED,
4915 : ERRSRV, ERRbadpath);
4916 0 : return;
4917 : }
4918 5 : reply_nterror(req, status);
4919 5 : return;
4920 : }
4921 :
4922 : /*
4923 : * OS/2 workplace shell seems to send SET_EA requests of "null"
4924 : * length (4 bytes containing IVAL 4).
4925 : * They seem to have no effect. Bug #3212. JRA.
4926 : */
4927 :
4928 18 : if (total_data && (total_data != 4)) {
4929 : /* Any data in this call is an EA list. */
4930 5 : if (total_data < 10) {
4931 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4932 0 : goto out;
4933 : }
4934 :
4935 5 : if (IVAL(pdata,0) > total_data) {
4936 0 : DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
4937 : IVAL(pdata,0), (unsigned int)total_data));
4938 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4939 0 : goto out;
4940 : }
4941 :
4942 5 : ea_list = read_ea_list(talloc_tos(), pdata + 4,
4943 5 : total_data - 4);
4944 5 : if (!ea_list) {
4945 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4946 0 : goto out;
4947 : }
4948 :
4949 5 : if (!lp_ea_support(SNUM(conn))) {
4950 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
4951 0 : goto out;
4952 : }
4953 : }
4954 : /* If total_data == 4 Windows doesn't care what values
4955 : * are placed in that field, it just ignores them.
4956 : * The System i QNTC IBM SMB client puts bad values here,
4957 : * so ignore them. */
4958 :
4959 18 : status = SMB_VFS_CREATE_FILE(
4960 : conn, /* conn */
4961 : req, /* req */
4962 : dirfsp, /* dirfsp */
4963 : smb_dname, /* fname */
4964 : MAXIMUM_ALLOWED_ACCESS, /* access_mask */
4965 : FILE_SHARE_NONE, /* share_access */
4966 : FILE_CREATE, /* create_disposition*/
4967 : FILE_DIRECTORY_FILE, /* create_options */
4968 : FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
4969 : 0, /* oplock_request */
4970 : NULL, /* lease */
4971 : 0, /* allocation_size */
4972 : 0, /* private_flags */
4973 : NULL, /* sd */
4974 : NULL, /* ea_list */
4975 : &fsp, /* result */
4976 : NULL, /* pinfo */
4977 : NULL, NULL); /* create context */
4978 18 : if (!NT_STATUS_IS_OK(status)) {
4979 8 : reply_nterror(req, status);
4980 8 : goto out;
4981 : }
4982 :
4983 : /* Try and set any given EA. */
4984 10 : if (ea_list) {
4985 5 : status = set_ea(conn, fsp, ea_list);
4986 5 : if (!NT_STATUS_IS_OK(status)) {
4987 0 : reply_nterror(req, status);
4988 0 : goto out;
4989 : }
4990 : }
4991 :
4992 : /* Realloc the parameter and data sizes */
4993 10 : *pparams = (char *)SMB_REALLOC(*pparams,2);
4994 10 : if(*pparams == NULL) {
4995 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4996 0 : goto out;
4997 : }
4998 10 : params = *pparams;
4999 :
5000 10 : SSVAL(params,0,0);
5001 :
5002 10 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
5003 :
5004 18 : out:
5005 18 : if (fsp != NULL) {
5006 10 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
5007 : }
5008 18 : TALLOC_FREE(smb_dname);
5009 : }
5010 :
5011 : /****************************************************************************
5012 : Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
5013 : We don't actually do this - we just send a null response.
5014 : ****************************************************************************/
5015 :
5016 0 : static void call_trans2findnotifyfirst(connection_struct *conn,
5017 : struct smb_request *req,
5018 : char **pparams, int total_params,
5019 : char **ppdata, int total_data,
5020 : unsigned int max_data_bytes)
5021 : {
5022 0 : char *params = *pparams;
5023 0 : uint16_t info_level;
5024 :
5025 0 : if (total_params < 6) {
5026 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5027 0 : return;
5028 : }
5029 :
5030 0 : info_level = SVAL(params,4);
5031 0 : DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
5032 :
5033 0 : switch (info_level) {
5034 0 : case 1:
5035 : case 2:
5036 0 : break;
5037 0 : default:
5038 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5039 0 : return;
5040 : }
5041 :
5042 : /* Realloc the parameter and data sizes */
5043 0 : *pparams = (char *)SMB_REALLOC(*pparams,6);
5044 0 : if (*pparams == NULL) {
5045 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5046 0 : return;
5047 : }
5048 0 : params = *pparams;
5049 :
5050 0 : SSVAL(params,0,fnf_handle);
5051 0 : SSVAL(params,2,0); /* No changes */
5052 0 : SSVAL(params,4,0); /* No EA errors */
5053 :
5054 0 : fnf_handle++;
5055 :
5056 0 : if(fnf_handle == 0)
5057 0 : fnf_handle = 257;
5058 :
5059 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
5060 : }
5061 :
5062 : /****************************************************************************
5063 : Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
5064 : changes). Currently this does nothing.
5065 : ****************************************************************************/
5066 :
5067 0 : static void call_trans2findnotifynext(connection_struct *conn,
5068 : struct smb_request *req,
5069 : char **pparams, int total_params,
5070 : char **ppdata, int total_data,
5071 : unsigned int max_data_bytes)
5072 : {
5073 0 : char *params = *pparams;
5074 :
5075 0 : DEBUG(3,("call_trans2findnotifynext\n"));
5076 :
5077 : /* Realloc the parameter and data sizes */
5078 0 : *pparams = (char *)SMB_REALLOC(*pparams,4);
5079 0 : if (*pparams == NULL) {
5080 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5081 0 : return;
5082 : }
5083 0 : params = *pparams;
5084 :
5085 0 : SSVAL(params,0,0); /* No changes */
5086 0 : SSVAL(params,2,0); /* No EA errors */
5087 :
5088 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
5089 : }
5090 :
5091 : /****************************************************************************
5092 : Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
5093 : ****************************************************************************/
5094 :
5095 4187 : static void call_trans2getdfsreferral(connection_struct *conn,
5096 : struct smb_request *req,
5097 : char **pparams, int total_params,
5098 : char **ppdata, int total_data,
5099 : unsigned int max_data_bytes)
5100 : {
5101 4187 : char *params = *pparams;
5102 4187 : char *pathname = NULL;
5103 4187 : int reply_size = 0;
5104 0 : int max_referral_level;
5105 4187 : NTSTATUS status = NT_STATUS_OK;
5106 4187 : TALLOC_CTX *ctx = talloc_tos();
5107 :
5108 4187 : DEBUG(10,("call_trans2getdfsreferral\n"));
5109 :
5110 4187 : if (!IS_IPC(conn)) {
5111 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5112 0 : return;
5113 : }
5114 :
5115 4187 : if (total_params < 3) {
5116 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5117 0 : return;
5118 : }
5119 :
5120 4187 : max_referral_level = SVAL(params,0);
5121 :
5122 4187 : if(!lp_host_msdfs()) {
5123 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5124 0 : return;
5125 : }
5126 :
5127 4187 : srvstr_pull_talloc(ctx, params, req->flags2, &pathname, ¶ms[2],
5128 : total_params - 2, STR_TERMINATE);
5129 4187 : if (!pathname) {
5130 0 : reply_nterror(req, NT_STATUS_NOT_FOUND);
5131 0 : return;
5132 : }
5133 4187 : reply_size = setup_dfs_referral(
5134 : conn, pathname, max_referral_level, ppdata, &status);
5135 4187 : if (reply_size < 0) {
5136 2913 : reply_nterror(req, status);
5137 2913 : return;
5138 : }
5139 :
5140 1274 : SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
5141 : SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
5142 1274 : send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
5143 : }
5144 :
5145 : #define LMCAT_SPL 0x53
5146 : #define LMFUNC_GETJOBID 0x60
5147 :
5148 : /****************************************************************************
5149 : Reply to a TRANS2_IOCTL - used for OS/2 printing.
5150 : ****************************************************************************/
5151 :
5152 0 : static void call_trans2ioctl(connection_struct *conn,
5153 : struct smb_request *req,
5154 : char **pparams, int total_params,
5155 : char **ppdata, int total_data,
5156 : unsigned int max_data_bytes)
5157 : {
5158 0 : const struct loadparm_substitution *lp_sub =
5159 0 : loadparm_s3_global_substitution();
5160 0 : char *pdata = *ppdata;
5161 0 : files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
5162 0 : NTSTATUS status;
5163 0 : size_t len = 0;
5164 :
5165 : /* check for an invalid fid before proceeding */
5166 :
5167 0 : if (!fsp) {
5168 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5169 0 : return;
5170 : }
5171 :
5172 0 : if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
5173 0 : && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5174 0 : *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
5175 0 : if (*ppdata == NULL) {
5176 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5177 0 : return;
5178 : }
5179 0 : pdata = *ppdata;
5180 :
5181 : /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
5182 : CAN ACCEPT THIS IN UNICODE. JRA. */
5183 :
5184 : /* Job number */
5185 0 : SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));
5186 :
5187 0 : status = srvstr_push(pdata, req->flags2, pdata + 2,
5188 : lp_netbios_name(), 15,
5189 : STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
5190 0 : if (!NT_STATUS_IS_OK(status)) {
5191 0 : reply_nterror(req, status);
5192 0 : return;
5193 : }
5194 0 : status = srvstr_push(pdata, req->flags2, pdata+18,
5195 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13,
5196 : STR_ASCII|STR_TERMINATE, &len); /* Service name */
5197 0 : if (!NT_STATUS_IS_OK(status)) {
5198 0 : reply_nterror(req, status);
5199 0 : return;
5200 : }
5201 0 : send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
5202 : max_data_bytes);
5203 0 : return;
5204 : }
5205 :
5206 0 : DEBUG(2,("Unknown TRANS2_IOCTL\n"));
5207 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5208 : }
5209 :
5210 36618 : static void handle_trans2(connection_struct *conn, struct smb_request *req,
5211 : struct trans_state *state)
5212 : {
5213 36618 : struct smbXsrv_connection *xconn = req->xconn;
5214 :
5215 36618 : if (xconn->protocol >= PROTOCOL_NT1) {
5216 36616 : req->flags2 |= 0x40; /* IS_LONG_NAME */
5217 36616 : SSVAL((discard_const_p(uint8_t, req->inbuf)),smb_flg2,req->flags2);
5218 : }
5219 :
5220 36618 : if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
5221 0 : if (state->call != TRANSACT2_QFSINFO &&
5222 0 : state->call != TRANSACT2_SETFSINFO) {
5223 0 : DEBUG(0,("handle_trans2: encryption required "
5224 : "with call 0x%x\n",
5225 : (unsigned int)state->call));
5226 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5227 0 : return;
5228 : }
5229 : }
5230 :
5231 : /* Now we must call the relevant TRANS2 function */
5232 36618 : switch(state->call) {
5233 98 : case TRANSACT2_OPEN:
5234 : {
5235 98 : START_PROFILE(Trans2_open);
5236 98 : call_trans2open(conn, req,
5237 98 : &state->param, state->total_param,
5238 98 : &state->data, state->total_data,
5239 : state->max_data_return);
5240 98 : END_PROFILE(Trans2_open);
5241 80 : break;
5242 : }
5243 :
5244 8716 : case TRANSACT2_FINDFIRST:
5245 : {
5246 8716 : START_PROFILE(Trans2_findfirst);
5247 8716 : call_trans2findfirst(conn, req,
5248 8716 : &state->param, state->total_param,
5249 8716 : &state->data, state->total_data,
5250 : state->max_data_return);
5251 8716 : END_PROFILE(Trans2_findfirst);
5252 8541 : break;
5253 : }
5254 :
5255 1724 : case TRANSACT2_FINDNEXT:
5256 : {
5257 1724 : START_PROFILE(Trans2_findnext);
5258 1724 : call_trans2findnext(conn, req,
5259 1724 : &state->param, state->total_param,
5260 1724 : &state->data, state->total_data,
5261 : state->max_data_return);
5262 1724 : END_PROFILE(Trans2_findnext);
5263 1724 : break;
5264 : }
5265 :
5266 1373 : case TRANSACT2_QFSINFO:
5267 : {
5268 1373 : START_PROFILE(Trans2_qfsinfo);
5269 1373 : call_trans2qfsinfo(conn, req,
5270 1373 : &state->param, state->total_param,
5271 1373 : &state->data, state->total_data,
5272 : state->max_data_return);
5273 1373 : END_PROFILE(Trans2_qfsinfo);
5274 1373 : break;
5275 : }
5276 :
5277 1364 : case TRANSACT2_SETFSINFO:
5278 : {
5279 1364 : START_PROFILE(Trans2_setfsinfo);
5280 1364 : call_trans2setfsinfo(conn, req,
5281 1364 : &state->param, state->total_param,
5282 1364 : &state->data, state->total_data,
5283 : state->max_data_return);
5284 1364 : END_PROFILE(Trans2_setfsinfo);
5285 1364 : break;
5286 : }
5287 :
5288 9909 : case TRANSACT2_QPATHINFO:
5289 : {
5290 9909 : START_PROFILE(Trans2_qpathinfo);
5291 9909 : call_trans2qpathinfo(
5292 : conn,
5293 : req,
5294 : &state->param,
5295 9909 : state->total_param,
5296 : &state->data,
5297 9909 : state->total_data,
5298 : state->max_data_return);
5299 9909 : END_PROFILE(Trans2_qpathinfo);
5300 9620 : break;
5301 : }
5302 :
5303 3551 : case TRANSACT2_QFILEINFO:
5304 : {
5305 3551 : START_PROFILE(Trans2_qfileinfo);
5306 3551 : call_trans2qfileinfo(
5307 : conn,
5308 : req,
5309 : &state->param,
5310 3551 : state->total_param,
5311 : &state->data,
5312 3551 : state->total_data,
5313 : state->max_data_return);
5314 3551 : END_PROFILE(Trans2_qfileinfo);
5315 3366 : break;
5316 : }
5317 :
5318 1408 : case TRANSACT2_SETPATHINFO:
5319 : {
5320 1408 : START_PROFILE(Trans2_setpathinfo);
5321 1408 : call_trans2setpathinfo(
5322 : conn,
5323 : req,
5324 : &state->param,
5325 1408 : state->total_param,
5326 : &state->data,
5327 1408 : state->total_data,
5328 : state->max_data_return);
5329 1408 : END_PROFILE(Trans2_setpathinfo);
5330 1396 : break;
5331 : }
5332 :
5333 4265 : case TRANSACT2_SETFILEINFO:
5334 : {
5335 4265 : START_PROFILE(Trans2_setfileinfo);
5336 4265 : call_trans2setfileinfo(
5337 : conn,
5338 : req,
5339 : &state->param,
5340 4265 : state->total_param,
5341 : &state->data,
5342 4265 : state->total_data,
5343 : state->max_data_return);
5344 4265 : END_PROFILE(Trans2_setfileinfo);
5345 3728 : break;
5346 : }
5347 :
5348 0 : case TRANSACT2_FINDNOTIFYFIRST:
5349 : {
5350 0 : START_PROFILE(Trans2_findnotifyfirst);
5351 0 : call_trans2findnotifyfirst(conn, req,
5352 0 : &state->param, state->total_param,
5353 0 : &state->data, state->total_data,
5354 : state->max_data_return);
5355 0 : END_PROFILE(Trans2_findnotifyfirst);
5356 0 : break;
5357 : }
5358 :
5359 0 : case TRANSACT2_FINDNOTIFYNEXT:
5360 : {
5361 0 : START_PROFILE(Trans2_findnotifynext);
5362 0 : call_trans2findnotifynext(conn, req,
5363 0 : &state->param, state->total_param,
5364 0 : &state->data, state->total_data,
5365 : state->max_data_return);
5366 0 : END_PROFILE(Trans2_findnotifynext);
5367 0 : break;
5368 : }
5369 :
5370 23 : case TRANSACT2_MKDIR:
5371 : {
5372 23 : START_PROFILE(Trans2_mkdir);
5373 23 : call_trans2mkdir(conn, req,
5374 23 : &state->param, state->total_param,
5375 23 : &state->data, state->total_data,
5376 : state->max_data_return);
5377 23 : END_PROFILE(Trans2_mkdir);
5378 20 : break;
5379 : }
5380 :
5381 4187 : case TRANSACT2_GET_DFS_REFERRAL:
5382 : {
5383 4187 : START_PROFILE(Trans2_get_dfs_referral);
5384 4187 : call_trans2getdfsreferral(conn, req,
5385 4187 : &state->param, state->total_param,
5386 4187 : &state->data, state->total_data,
5387 : state->max_data_return);
5388 4187 : END_PROFILE(Trans2_get_dfs_referral);
5389 4187 : break;
5390 : }
5391 :
5392 0 : case TRANSACT2_IOCTL:
5393 : {
5394 0 : START_PROFILE(Trans2_ioctl);
5395 0 : call_trans2ioctl(conn, req,
5396 0 : &state->param, state->total_param,
5397 0 : &state->data, state->total_data,
5398 : state->max_data_return);
5399 0 : END_PROFILE(Trans2_ioctl);
5400 0 : break;
5401 : }
5402 :
5403 0 : default:
5404 : /* Error in request */
5405 0 : DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
5406 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5407 : }
5408 : }
5409 :
5410 : /****************************************************************************
5411 : Reply to a SMBtrans2.
5412 : ****************************************************************************/
5413 :
5414 36618 : void reply_trans2(struct smb_request *req)
5415 : {
5416 36618 : connection_struct *conn = req->conn;
5417 1219 : unsigned int dsoff;
5418 1219 : unsigned int dscnt;
5419 1219 : unsigned int psoff;
5420 1219 : unsigned int pscnt;
5421 1219 : unsigned int tran_call;
5422 1219 : struct trans_state *state;
5423 1219 : NTSTATUS result;
5424 :
5425 36618 : START_PROFILE(SMBtrans2);
5426 :
5427 36618 : if (req->wct < 14) {
5428 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5429 0 : END_PROFILE(SMBtrans2);
5430 0 : return;
5431 : }
5432 :
5433 36618 : dsoff = SVAL(req->vwv+12, 0);
5434 36618 : dscnt = SVAL(req->vwv+11, 0);
5435 36618 : psoff = SVAL(req->vwv+10, 0);
5436 36618 : pscnt = SVAL(req->vwv+9, 0);
5437 36618 : tran_call = SVAL(req->vwv+14, 0);
5438 :
5439 36618 : result = allow_new_trans(conn->pending_trans, req->mid);
5440 36618 : if (!NT_STATUS_IS_OK(result)) {
5441 0 : DEBUG(2, ("Got invalid trans2 request: %s\n",
5442 : nt_errstr(result)));
5443 0 : reply_nterror(req, result);
5444 0 : END_PROFILE(SMBtrans2);
5445 0 : return;
5446 : }
5447 :
5448 36618 : if (IS_IPC(conn)) {
5449 4907 : switch (tran_call) {
5450 : /* List the allowed trans2 calls on IPC$ */
5451 4907 : case TRANSACT2_OPEN:
5452 : case TRANSACT2_GET_DFS_REFERRAL:
5453 : case TRANSACT2_QFILEINFO:
5454 : case TRANSACT2_QFSINFO:
5455 : case TRANSACT2_SETFSINFO:
5456 4907 : break;
5457 0 : default:
5458 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5459 0 : END_PROFILE(SMBtrans2);
5460 0 : return;
5461 : }
5462 : }
5463 :
5464 36618 : if ((state = talloc(conn, struct trans_state)) == NULL) {
5465 0 : DEBUG(0, ("talloc failed\n"));
5466 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5467 0 : END_PROFILE(SMBtrans2);
5468 0 : return;
5469 : }
5470 :
5471 36618 : state->cmd = SMBtrans2;
5472 :
5473 36618 : state->mid = req->mid;
5474 36618 : state->vuid = req->vuid;
5475 36618 : state->setup_count = SVAL(req->vwv+13, 0);
5476 36618 : state->setup = NULL;
5477 36618 : state->total_param = SVAL(req->vwv+0, 0);
5478 36618 : state->param = NULL;
5479 36618 : state->total_data = SVAL(req->vwv+1, 0);
5480 36618 : state->data = NULL;
5481 36618 : state->max_param_return = SVAL(req->vwv+2, 0);
5482 36618 : state->max_data_return = SVAL(req->vwv+3, 0);
5483 36618 : state->max_setup_return = SVAL(req->vwv+4, 0);
5484 36618 : state->close_on_completion = BITSETW(req->vwv+5, 0);
5485 36618 : state->one_way = BITSETW(req->vwv+5, 1);
5486 :
5487 36618 : state->call = tran_call;
5488 :
5489 : /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
5490 : is so as a sanity check */
5491 36618 : if (state->setup_count != 1) {
5492 : /*
5493 : * Need to have rc=0 for ioctl to get job id for OS/2.
5494 : * Network printing will fail if function is not successful.
5495 : * Similar function in reply.c will be used if protocol
5496 : * is LANMAN1.0 instead of LM1.2X002.
5497 : * Until DosPrintSetJobInfo with PRJINFO3 is supported,
5498 : * outbuf doesn't have to be set(only job id is used).
5499 : */
5500 0 : if ( (state->setup_count == 4)
5501 0 : && (tran_call == TRANSACT2_IOCTL)
5502 0 : && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
5503 0 : && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5504 0 : DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
5505 : } else {
5506 0 : DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
5507 0 : DEBUG(2,("Transaction is %d\n",tran_call));
5508 0 : TALLOC_FREE(state);
5509 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5510 0 : END_PROFILE(SMBtrans2);
5511 0 : return;
5512 : }
5513 : }
5514 :
5515 36618 : if ((dscnt > state->total_data) || (pscnt > state->total_param))
5516 0 : goto bad_param;
5517 :
5518 36618 : if (state->total_data) {
5519 :
5520 7322 : if (smb_buffer_oob(state->total_data, 0, dscnt)
5521 7322 : || smb_buffer_oob(smb_len(req->inbuf), dsoff, dscnt)) {
5522 0 : goto bad_param;
5523 : }
5524 :
5525 : /* Can't use talloc here, the core routines do realloc on the
5526 : * params and data. */
5527 7322 : state->data = (char *)SMB_MALLOC(state->total_data);
5528 7322 : if (state->data == NULL) {
5529 0 : DEBUG(0,("reply_trans2: data malloc fail for %u "
5530 : "bytes !\n", (unsigned int)state->total_data));
5531 0 : TALLOC_FREE(state);
5532 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5533 0 : END_PROFILE(SMBtrans2);
5534 0 : return;
5535 : }
5536 :
5537 7322 : memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
5538 : }
5539 :
5540 36618 : if (state->total_param) {
5541 :
5542 36618 : if (smb_buffer_oob(state->total_param, 0, pscnt)
5543 36618 : || smb_buffer_oob(smb_len(req->inbuf), psoff, pscnt)) {
5544 0 : goto bad_param;
5545 : }
5546 :
5547 : /* Can't use talloc here, the core routines do realloc on the
5548 : * params and data. */
5549 36618 : state->param = (char *)SMB_MALLOC(state->total_param);
5550 36618 : if (state->param == NULL) {
5551 0 : DEBUG(0,("reply_trans: param malloc fail for %u "
5552 : "bytes !\n", (unsigned int)state->total_param));
5553 0 : SAFE_FREE(state->data);
5554 0 : TALLOC_FREE(state);
5555 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5556 0 : END_PROFILE(SMBtrans2);
5557 0 : return;
5558 : }
5559 :
5560 36618 : memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
5561 : }
5562 :
5563 36618 : state->received_data = dscnt;
5564 36618 : state->received_param = pscnt;
5565 :
5566 36618 : if ((state->received_param == state->total_param) &&
5567 36618 : (state->received_data == state->total_data)) {
5568 :
5569 36618 : handle_trans2(conn, req, state);
5570 :
5571 36618 : SAFE_FREE(state->data);
5572 36618 : SAFE_FREE(state->param);
5573 36618 : TALLOC_FREE(state);
5574 36618 : END_PROFILE(SMBtrans2);
5575 36618 : return;
5576 : }
5577 :
5578 0 : DLIST_ADD(conn->pending_trans, state);
5579 :
5580 : /* We need to send an interim response then receive the rest
5581 : of the parameter/data bytes */
5582 0 : reply_smb1_outbuf(req, 0, 0);
5583 0 : show_msg((char *)req->outbuf);
5584 0 : END_PROFILE(SMBtrans2);
5585 0 : return;
5586 :
5587 0 : bad_param:
5588 :
5589 0 : DEBUG(0,("reply_trans2: invalid trans parameters\n"));
5590 0 : SAFE_FREE(state->data);
5591 0 : SAFE_FREE(state->param);
5592 0 : TALLOC_FREE(state);
5593 0 : END_PROFILE(SMBtrans2);
5594 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5595 : }
5596 :
5597 : /****************************************************************************
5598 : Reply to a SMBtranss2
5599 : ****************************************************************************/
5600 :
5601 0 : void reply_transs2(struct smb_request *req)
5602 : {
5603 0 : connection_struct *conn = req->conn;
5604 0 : unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
5605 0 : struct trans_state *state;
5606 :
5607 0 : START_PROFILE(SMBtranss2);
5608 :
5609 0 : show_msg((const char *)req->inbuf);
5610 :
5611 : /* Windows clients expect all replies to
5612 : a transact secondary (SMBtranss2 0x33)
5613 : to have a command code of transact
5614 : (SMBtrans2 0x32). See bug #8989
5615 : and also [MS-CIFS] section 2.2.4.47.2
5616 : for details.
5617 : */
5618 0 : req->cmd = SMBtrans2;
5619 :
5620 0 : if (req->wct < 8) {
5621 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5622 0 : END_PROFILE(SMBtranss2);
5623 0 : return;
5624 : }
5625 :
5626 0 : for (state = conn->pending_trans; state != NULL;
5627 0 : state = state->next) {
5628 0 : if (state->mid == req->mid) {
5629 0 : break;
5630 : }
5631 : }
5632 :
5633 0 : if ((state == NULL) || (state->cmd != SMBtrans2)) {
5634 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5635 0 : END_PROFILE(SMBtranss2);
5636 0 : return;
5637 : }
5638 :
5639 : /* Revise state->total_param and state->total_data in case they have
5640 : changed downwards */
5641 :
5642 0 : if (SVAL(req->vwv+0, 0) < state->total_param)
5643 0 : state->total_param = SVAL(req->vwv+0, 0);
5644 0 : if (SVAL(req->vwv+1, 0) < state->total_data)
5645 0 : state->total_data = SVAL(req->vwv+1, 0);
5646 :
5647 0 : pcnt = SVAL(req->vwv+2, 0);
5648 0 : poff = SVAL(req->vwv+3, 0);
5649 0 : pdisp = SVAL(req->vwv+4, 0);
5650 :
5651 0 : dcnt = SVAL(req->vwv+5, 0);
5652 0 : doff = SVAL(req->vwv+6, 0);
5653 0 : ddisp = SVAL(req->vwv+7, 0);
5654 :
5655 0 : state->received_param += pcnt;
5656 0 : state->received_data += dcnt;
5657 :
5658 0 : if ((state->received_data > state->total_data) ||
5659 0 : (state->received_param > state->total_param))
5660 0 : goto bad_param;
5661 :
5662 0 : if (pcnt) {
5663 0 : if (smb_buffer_oob(state->total_param, pdisp, pcnt)
5664 0 : || smb_buffer_oob(smb_len(req->inbuf), poff, pcnt)) {
5665 0 : goto bad_param;
5666 : }
5667 0 : memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
5668 : }
5669 :
5670 0 : if (dcnt) {
5671 0 : if (smb_buffer_oob(state->total_data, ddisp, dcnt)
5672 0 : || smb_buffer_oob(smb_len(req->inbuf), doff, dcnt)) {
5673 0 : goto bad_param;
5674 : }
5675 0 : memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
5676 : }
5677 :
5678 0 : if ((state->received_param < state->total_param) ||
5679 0 : (state->received_data < state->total_data)) {
5680 0 : END_PROFILE(SMBtranss2);
5681 0 : return;
5682 : }
5683 :
5684 0 : handle_trans2(conn, req, state);
5685 :
5686 0 : DLIST_REMOVE(conn->pending_trans, state);
5687 0 : SAFE_FREE(state->data);
5688 0 : SAFE_FREE(state->param);
5689 0 : TALLOC_FREE(state);
5690 :
5691 0 : END_PROFILE(SMBtranss2);
5692 0 : return;
5693 :
5694 0 : bad_param:
5695 :
5696 0 : DEBUG(0,("reply_transs2: invalid trans parameters\n"));
5697 0 : DLIST_REMOVE(conn->pending_trans, state);
5698 0 : SAFE_FREE(state->data);
5699 0 : SAFE_FREE(state->param);
5700 0 : TALLOC_FREE(state);
5701 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5702 0 : END_PROFILE(SMBtranss2);
5703 : }
|