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 30514 : 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 30514 : int data_to_send = datasize;
76 30514 : int params_to_send = paramsize;
77 1172 : int useable_space;
78 30514 : const char *pp = params;
79 30514 : const char *pd = pdata;
80 1172 : int params_sent_thistime, data_sent_thistime, total_sent_thistime;
81 30514 : int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
82 30514 : int data_alignment_offset = 0;
83 30514 : bool overflow = False;
84 30514 : struct smbXsrv_connection *xconn = req->xconn;
85 30514 : 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 30514 : 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 30514 : 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 30514 : if (((params_to_send % 4) != 0) && (data_to_send != 0))
128 20703 : 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 30514 : useable_space = max_send - (smb_size
135 : + 2 * 10 /* wct */
136 29342 : + alignment_offset
137 30514 : + data_alignment_offset);
138 :
139 30514 : 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 61056 : while (params_to_send || data_to_send) {
146 : /* Calculate whether we will totally or partially fill this packet */
147 :
148 30542 : 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 30542 : total_sent_thistime = MIN(total_sent_thistime, useable_space);
159 :
160 30542 : reply_smb1_outbuf(req, 10, total_sent_thistime + alignment_offset
161 30542 : + data_alignment_offset);
162 :
163 : /* Set total params and data to be sent */
164 30542 : SSVAL(req->outbuf,smb_tprcnt,paramsize);
165 30542 : 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 30542 : params_sent_thistime = MIN(params_to_send,useable_space);
172 30542 : data_sent_thistime = useable_space - params_sent_thistime;
173 30542 : data_sent_thistime = MIN(data_sent_thistime,data_to_send);
174 :
175 30542 : 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 30542 : SSVAL(req->outbuf,smb_proff,
183 : ((smb_buf(req->outbuf)+alignment_offset)
184 : - smb_base(req->outbuf)));
185 :
186 30542 : if(params_sent_thistime == 0)
187 3161 : SSVAL(req->outbuf,smb_prdisp,0);
188 : else
189 : /* Absolute displacement of param bytes sent in this packet */
190 27381 : SSVAL(req->outbuf,smb_prdisp,pp - params);
191 :
192 30542 : SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
193 30542 : 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 25492 : 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 25492 : SSVAL(req->outbuf,smb_drdisp, pd - pdata);
204 : }
205 :
206 : /* Initialize the padding for alignment */
207 :
208 30542 : if (alignment_offset != 0) {
209 30542 : memset(smb_buf(req->outbuf), 0, alignment_offset);
210 : }
211 :
212 : /* Copy the param bytes into the packet */
213 :
214 30542 : if(params_sent_thistime) {
215 27381 : memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
216 : params_sent_thistime);
217 : }
218 :
219 : /* Copy in the data bytes */
220 30542 : if(data_sent_thistime) {
221 25492 : if (data_alignment_offset != 0) {
222 20723 : memset((smb_buf(req->outbuf)+alignment_offset+
223 : params_sent_thistime), 0,
224 : data_alignment_offset);
225 : }
226 26664 : memcpy(smb_buf(req->outbuf)+alignment_offset
227 25492 : +params_sent_thistime+data_alignment_offset,
228 : pd,data_sent_thistime);
229 : }
230 :
231 30542 : 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 30542 : 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 30542 : if (overflow) {
237 0 : error_packet_set((char *)req->outbuf,
238 : ERRDOS,ERRbufferoverflow,
239 0 : STATUS_BUFFER_OVERFLOW,
240 : __LINE__,__FILE__);
241 30542 : } 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 30542 : show_msg((char *)req->outbuf);
252 30542 : if (!smb1_srv_send(xconn,
253 30542 : (char *)req->outbuf,
254 : true,
255 30542 : req->seqnum + 1,
256 30542 : IS_CONN_ENCRYPTED(conn))) {
257 0 : exit_server_cleanly("send_trans2_replies: smb1_srv_send failed.");
258 : }
259 :
260 30542 : TALLOC_FREE(req->outbuf);
261 :
262 30542 : pp += params_sent_thistime;
263 30542 : pd += data_sent_thistime;
264 :
265 30542 : params_to_send -= params_sent_thistime;
266 30542 : data_to_send -= data_sent_thistime;
267 :
268 : /* Sanity check */
269 30542 : 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 29342 : 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 207192 : 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 207192 : uint8_t align = 4;
791 207192 : const bool do_pad = true;
792 :
793 207192 : if (info_level >= 1 && info_level <= 3) {
794 : /* No alignment on earlier info levels. */
795 114822 : align = 1;
796 : }
797 :
798 207192 : 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 8740 : 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 8740 : struct smb_filename *smb_dname = NULL;
824 8740 : char *params = *pparams;
825 8740 : 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 8740 : char *directory = NULL;
835 8740 : char *mask = NULL;
836 175 : char *p;
837 8740 : int last_entry_off=0;
838 8740 : int dptr_num = -1;
839 8740 : int numentries = 0;
840 175 : int i;
841 8740 : bool finished = False;
842 8740 : bool dont_descend = False;
843 8740 : bool out_of_space = False;
844 175 : int space_remaining;
845 8740 : struct ea_list *ea_list = NULL;
846 8740 : NTSTATUS ntstatus = NT_STATUS_OK;
847 175 : bool ask_sharemode;
848 8740 : struct smbXsrv_connection *xconn = req->xconn;
849 8740 : struct smbd_server_connection *sconn = req->sconn;
850 8740 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
851 8740 : bool backup_priv = false;
852 8740 : bool as_root = false;
853 8740 : files_struct *fsp = NULL;
854 8740 : struct files_struct *dirfsp = NULL;
855 175 : const struct loadparm_substitution *lp_sub =
856 8740 : loadparm_s3_global_substitution();
857 :
858 8740 : if (total_params < 13) {
859 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
860 0 : goto out;
861 : }
862 :
863 8740 : dirtype = SVAL(params,0);
864 8740 : maxentries = SVAL(params,2);
865 8740 : findfirst_flags = SVAL(params,4);
866 8740 : close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
867 8740 : close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
868 8740 : requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
869 8746 : 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 8740 : info_level = SVAL(params,6);
874 :
875 8740 : 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 8740 : if (!maxentries) {
889 : /* W2K3 seems to treat zero as 1. */
890 12 : maxentries = 1;
891 : }
892 :
893 8740 : switch (info_level) {
894 8549 : 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 8724 : 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 8740 : if (req->posix_pathnames) {
921 190 : srvstr_get_path_posix(talloc_tos(),
922 : params,
923 190 : req->flags2,
924 : &directory,
925 190 : params+12,
926 190 : total_params - 12,
927 : STR_TERMINATE,
928 : &ntstatus);
929 : } else {
930 8550 : srvstr_get_path(talloc_tos(),
931 : params,
932 8550 : req->flags2,
933 : &directory,
934 8550 : params+12,
935 8550 : total_params - 12,
936 : STR_TERMINATE,
937 : &ntstatus);
938 : }
939 8740 : if (!NT_STATUS_IS_OK(ntstatus)) {
940 0 : reply_nterror(req, ntstatus);
941 0 : goto out;
942 : }
943 :
944 8740 : if (backup_priv) {
945 0 : become_root();
946 0 : as_root = true;
947 : }
948 8740 : ntstatus = smb1_strip_dfs_path(talloc_tos(), &ucf_flags, &directory);
949 8740 : if (!NT_STATUS_IS_OK(ntstatus)) {
950 0 : reply_nterror(req, ntstatus);
951 0 : goto out;
952 : }
953 :
954 8740 : ntstatus = filename_convert_smb1_search_path(talloc_tos(),
955 : conn,
956 : directory,
957 : ucf_flags,
958 : &dirfsp,
959 : &smb_dname,
960 : &mask);
961 :
962 8740 : 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 8626 : TALLOC_FREE(directory);
973 8626 : directory = smb_dname->base_name;
974 :
975 8626 : DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
976 :
977 8626 : 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 8626 : 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 8626 : *ppdata = (char *)SMB_REALLOC(
1014 : *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
1015 8626 : if(*ppdata == NULL ) {
1016 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1017 0 : goto out;
1018 : }
1019 8626 : pdata = *ppdata;
1020 8626 : 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 8626 : memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data));
1026 : /* Realloc the params space */
1027 8626 : *pparams = (char *)SMB_REALLOC(*pparams, 10);
1028 8626 : if (*pparams == NULL) {
1029 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1030 0 : goto out;
1031 : }
1032 8626 : params = *pparams;
1033 :
1034 : /*
1035 : * Open an fsp on this directory for the dptr.
1036 : */
1037 8626 : 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 8626 : 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 8507 : ntstatus = dptr_create(conn,
1070 : req,
1071 : fsp, /* fsp */
1072 : False,
1073 : mask,
1074 : dirtype,
1075 8507 : &fsp->dptr);
1076 :
1077 8507 : 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 8507 : 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 8507 : dptr_num = dptr_dnum(fsp->dptr);
1095 8507 : 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 8507 : DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1101 : directory,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn))));
1102 8507 : if (in_list(directory,
1103 8507 : lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
1104 8507 : dptr_case_sensitive(fsp->dptr))) {
1105 0 : dont_descend = True;
1106 : }
1107 :
1108 8507 : p = pdata;
1109 8507 : space_remaining = max_data_bytes;
1110 8507 : out_of_space = False;
1111 :
1112 8507 : ask_sharemode = fsp_search_ask_sharemode(fsp);
1113 :
1114 58095 : for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
1115 :
1116 49414 : ntstatus = get_lanman2_dir_entry(talloc_tos(),
1117 : conn,
1118 49414 : fsp->dptr,
1119 49414 : 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 49414 : 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 49402 : if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
1140 0 : out_of_space = true;
1141 : } else {
1142 49402 : finished = !NT_STATUS_IS_OK(ntstatus);
1143 : }
1144 :
1145 49402 : if (!finished && !out_of_space) {
1146 41522 : numentries++;
1147 : }
1148 :
1149 : /* Ensure space_remaining never goes -ve. */
1150 49402 : if (PTR_DIFF(p,pdata) > max_data_bytes) {
1151 0 : space_remaining = 0;
1152 0 : out_of_space = true;
1153 : } else {
1154 49402 : space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
1155 : }
1156 : }
1157 :
1158 : /* Check if we can close the dirptr */
1159 8507 : if(close_after_first || (finished && close_if_end)) {
1160 8373 : DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
1161 8373 : dptr_num = -1;
1162 8373 : 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 8507 : 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 7966 : SSVAL(params,0,dptr_num);
1195 7966 : SSVAL(params,2,numentries);
1196 7966 : SSVAL(params,4,finished);
1197 7966 : SSVAL(params,6,0); /* Never an EA error */
1198 7966 : SSVAL(params,8,last_entry_off);
1199 :
1200 7966 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
1201 : max_data_bytes);
1202 :
1203 7966 : 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 7966 : 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 7966 : if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
1223 153 : char mangled_name[13];
1224 7828 : name_to_8_3(mask, mangled_name, True, conn->params);
1225 : }
1226 138 : out:
1227 :
1228 8740 : if (as_root) {
1229 0 : unbecome_root();
1230 : }
1231 :
1232 8740 : TALLOC_FREE(smb_dname);
1233 8740 : 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 1377 : 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 1377 : char *params = *pparams;
1654 0 : uint16_t info_level;
1655 1377 : int data_len = 0;
1656 0 : size_t fixed_portion;
1657 0 : NTSTATUS status;
1658 :
1659 1377 : if (total_params < 2) {
1660 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1661 0 : return;
1662 : }
1663 :
1664 1377 : info_level = SVAL(params,0);
1665 :
1666 1377 : 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 1377 : DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
1677 :
1678 1377 : status = smbd_do_qfsinfo(req->xconn, conn, req,
1679 : info_level,
1680 1377 : req->flags2,
1681 : max_data_bytes,
1682 : &fixed_portion,
1683 : NULL,
1684 : NULL,
1685 : ppdata, &data_len);
1686 1377 : if (!NT_STATUS_IS_OK(status)) {
1687 0 : reply_nterror(req, status);
1688 0 : return;
1689 : }
1690 :
1691 1377 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
1692 : max_data_bytes);
1693 :
1694 1377 : DEBUG( 4, ( "%s info_level = %d\n",
1695 : smb_fn_name(req->cmd), info_level) );
1696 :
1697 1377 : return;
1698 : }
1699 :
1700 : /****************************************************************************
1701 : Reply to a TRANS2_SETFSINFO (set filesystem info).
1702 : ****************************************************************************/
1703 :
1704 1370 : 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 1370 : loadparm_s3_global_substitution();
1712 1370 : struct smbXsrv_connection *xconn = req->xconn;
1713 1370 : char *pdata = *ppdata;
1714 1370 : char *params = *pparams;
1715 0 : uint16_t info_level;
1716 :
1717 1370 : DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
1718 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1719 :
1720 : /* */
1721 1370 : 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 1370 : info_level = SVAL(params,2);
1729 :
1730 1370 : if (IS_IPC(conn)) {
1731 484 : 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 1370 : 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 1370 : switch(info_level) {
1752 478 : case SMB_SET_CIFS_UNIX_INFO:
1753 478 : if (!lp_smb1_unix_extensions()) {
1754 0 : DEBUG(2,("call_trans2setfsinfo: "
1755 : "SMB_SET_CIFS_UNIX_INFO is invalid with "
1756 : "unix extensions off\n"));
1757 0 : reply_nterror(req,
1758 : NT_STATUS_INVALID_LEVEL);
1759 0 : return;
1760 : }
1761 :
1762 : /* There should be 12 bytes of capabilities set. */
1763 478 : if (total_data < 12) {
1764 0 : reply_nterror(
1765 : req,
1766 : NT_STATUS_INVALID_PARAMETER);
1767 0 : return;
1768 : }
1769 478 : xconn->smb1.unix_info.client_major = SVAL(pdata,0);
1770 478 : xconn->smb1.unix_info.client_minor = SVAL(pdata,2);
1771 478 : xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
1772 478 : xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
1773 :
1774 : /* Just print these values for now. */
1775 478 : DBG_DEBUG("set unix_info info. "
1776 : "major = %"PRIu16", minor = %"PRIu16
1777 : "cap_low = 0x%"PRIx32", "
1778 : "cap_high = 0x%"PRIx32"\n",
1779 : xconn->smb1.unix_info.client_major,
1780 : xconn->smb1.unix_info.client_minor,
1781 : xconn->smb1.unix_info.client_cap_low,
1782 : xconn->smb1.unix_info.client_cap_high);
1783 :
1784 : /*
1785 : * Here is where we must switch to posix
1786 : * pathname processing...
1787 : */
1788 478 : if (xconn->smb1.unix_info.client_cap_low &
1789 : CIFS_UNIX_POSIX_PATHNAMES_CAP)
1790 : {
1791 478 : lp_set_posix_pathnames();
1792 478 : mangle_change_to_posix();
1793 : }
1794 :
1795 478 : if ((xconn->smb1.unix_info.client_cap_low &
1796 478 : CIFS_UNIX_FCNTL_LOCKS_CAP) &&
1797 478 : !(xconn->smb1.unix_info.client_cap_low &
1798 : CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP))
1799 : {
1800 : /* Client that knows how to do posix locks,
1801 : * but not posix open/mkdir operations. Set a
1802 : * default type for read/write checks. */
1803 :
1804 0 : lp_set_posix_default_cifsx_readwrite_locktype(
1805 : POSIX_LOCK);
1806 :
1807 : }
1808 478 : break;
1809 :
1810 892 : case SMB_REQUEST_TRANSPORT_ENCRYPTION:
1811 : {
1812 0 : NTSTATUS status;
1813 892 : size_t param_len = 0;
1814 892 : size_t data_len = total_data;
1815 :
1816 892 : if (!lp_smb1_unix_extensions()) {
1817 0 : reply_nterror(
1818 : req,
1819 : NT_STATUS_INVALID_LEVEL);
1820 0 : return;
1821 : }
1822 :
1823 892 : 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 892 : 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 892 : DEBUG( 4,("call_trans2setfsinfo: "
1842 : "request transport encryption.\n"));
1843 :
1844 892 : status = srv_request_encryption_setup(conn,
1845 : (unsigned char **)ppdata,
1846 : &data_len,
1847 : (unsigned char **)pparams,
1848 : ¶m_len);
1849 :
1850 892 : if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
1851 446 : !NT_STATUS_IS_OK(status)) {
1852 0 : reply_nterror(req, status);
1853 0 : return;
1854 : }
1855 :
1856 892 : send_trans2_replies(conn, req,
1857 892 : NT_STATUS_OK,
1858 : *pparams,
1859 : param_len,
1860 : *ppdata,
1861 : data_len,
1862 : max_data_bytes);
1863 :
1864 892 : if (NT_STATUS_IS_OK(status)) {
1865 : /* Server-side transport
1866 : * encryption is now *on*. */
1867 446 : status = srv_encryption_start(conn);
1868 446 : 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 892 : return;
1877 : }
1878 :
1879 0 : case SMB_FS_QUOTA_INFORMATION:
1880 : {
1881 0 : NTSTATUS status;
1882 0 : DATA_BLOB qdata = {
1883 : .data = (uint8_t *)pdata,
1884 : .length = total_data
1885 : };
1886 0 : files_struct *fsp = NULL;
1887 0 : fsp = file_fsp(req, SVAL(params,0));
1888 :
1889 0 : status = smb_set_fsquota(conn,
1890 : req,
1891 : fsp,
1892 : &qdata);
1893 0 : if (!NT_STATUS_IS_OK(status)) {
1894 0 : reply_nterror(req, status);
1895 0 : return;
1896 : }
1897 0 : break;
1898 : }
1899 0 : default:
1900 0 : DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
1901 : info_level));
1902 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1903 0 : return;
1904 0 : break;
1905 : }
1906 :
1907 : /*
1908 : * sending this reply works fine,
1909 : * but I'm not sure it's the same
1910 : * like windows do...
1911 : * --metze
1912 : */
1913 478 : reply_smb1_outbuf(req, 10, 0);
1914 : }
1915 :
1916 : /****************************************************************************
1917 : Reply to a TRANSACT2_QFILEINFO on a PIPE !
1918 : ****************************************************************************/
1919 :
1920 0 : static void call_trans2qpipeinfo(connection_struct *conn,
1921 : struct smb_request *req,
1922 : files_struct *fsp,
1923 : uint16_t info_level,
1924 : unsigned int tran_call,
1925 : char **pparams, int total_params,
1926 : char **ppdata, int total_data,
1927 : unsigned int max_data_bytes)
1928 : {
1929 0 : char *params = *pparams;
1930 0 : char *pdata = *ppdata;
1931 0 : unsigned int data_size = 0;
1932 0 : unsigned int param_size = 2;
1933 :
1934 0 : if (!fsp_is_np(fsp)) {
1935 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1936 0 : return;
1937 : }
1938 :
1939 0 : *pparams = (char *)SMB_REALLOC(*pparams,2);
1940 0 : if (*pparams == NULL) {
1941 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1942 0 : return;
1943 : }
1944 0 : params = *pparams;
1945 0 : SSVAL(params,0,0);
1946 0 : if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
1947 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1948 0 : return;
1949 : }
1950 0 : data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
1951 0 : *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
1952 0 : if (*ppdata == NULL ) {
1953 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1954 0 : return;
1955 : }
1956 0 : pdata = *ppdata;
1957 :
1958 0 : switch (info_level) {
1959 0 : case SMB_FILE_STANDARD_INFORMATION:
1960 0 : memset(pdata,0,24);
1961 0 : SOFF_T(pdata,0,4096LL);
1962 0 : SIVAL(pdata,16,1);
1963 0 : SIVAL(pdata,20,1);
1964 0 : data_size = 24;
1965 0 : break;
1966 :
1967 0 : default:
1968 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1969 0 : return;
1970 : }
1971 :
1972 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
1973 : max_data_bytes);
1974 : }
1975 :
1976 12299 : static void handle_trans2qfilepathinfo_result(
1977 : connection_struct *conn,
1978 : struct smb_request *req,
1979 : uint16_t info_level,
1980 : NTSTATUS status,
1981 : char *pdata,
1982 : int data_return_size,
1983 : size_t fixed_portion,
1984 : unsigned int max_data_bytes)
1985 : {
1986 12299 : char params[2] = { 0, 0, };
1987 12299 : int param_size = 2;
1988 :
1989 : /*
1990 : * draft-leach-cifs-v1-spec-02.txt
1991 : * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
1992 : * says:
1993 : *
1994 : * The requested information is placed in the Data portion of the
1995 : * transaction response. For the information levels greater than 0x100,
1996 : * the transaction response has 1 parameter word which should be
1997 : * ignored by the client.
1998 : *
1999 : * However Windows only follows this rule for the IS_NAME_VALID call.
2000 : */
2001 12299 : switch (info_level) {
2002 8 : case SMB_INFO_IS_NAME_VALID:
2003 8 : param_size = 0;
2004 8 : break;
2005 : }
2006 :
2007 12299 : if (!NT_STATUS_IS_OK(status)) {
2008 60 : if (open_was_deferred(req->xconn, req->mid)) {
2009 : /* We have re-scheduled this call. */
2010 60 : return;
2011 : }
2012 56 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2013 0 : bool ok = defer_smb1_sharing_violation(req);
2014 0 : if (ok) {
2015 0 : return;
2016 : }
2017 : }
2018 56 : reply_nterror(req, status);
2019 56 : return;
2020 : }
2021 :
2022 12239 : if (fixed_portion > max_data_bytes) {
2023 0 : reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
2024 0 : return;
2025 : }
2026 :
2027 12239 : send_trans2_replies(
2028 : conn,
2029 : req,
2030 12239 : NT_STATUS_OK,
2031 : params,
2032 : param_size,
2033 : pdata,
2034 : data_return_size,
2035 : max_data_bytes);
2036 : }
2037 :
2038 : /****************************************************************************
2039 : Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
2040 : file name or file id).
2041 : ****************************************************************************/
2042 :
2043 12061 : static void call_trans2qfilepathinfo(connection_struct *conn,
2044 : struct smb_request *req,
2045 : unsigned int tran_call,
2046 : uint16_t info_level,
2047 : struct smb_filename *smb_fname,
2048 : struct files_struct *fsp,
2049 : bool delete_pending,
2050 : struct timespec write_time_ts,
2051 : char **pparams, int total_params,
2052 : char **ppdata, int total_data,
2053 : unsigned int max_data_bytes)
2054 : {
2055 12061 : char *params = *pparams;
2056 12061 : char *pdata = *ppdata;
2057 12061 : unsigned int data_size = 0;
2058 12061 : struct ea_list *ea_list = NULL;
2059 449 : size_t fixed_portion;
2060 12061 : NTSTATUS status = NT_STATUS_OK;
2061 :
2062 12061 : DEBUG(3,("call_trans2qfilepathinfo %s (%s) level=%d call=%d "
2063 : "total_data=%d\n", smb_fname_str_dbg(smb_fname),
2064 : fsp_fnum_dbg(fsp),
2065 : info_level,tran_call,total_data));
2066 :
2067 : /* Pull out any data sent here before we realloc. */
2068 12061 : switch (info_level) {
2069 152 : case SMB_INFO_QUERY_EAS_FROM_LIST:
2070 : {
2071 : /* Pull any EA list from the data portion. */
2072 28 : uint32_t ea_size;
2073 :
2074 152 : if (total_data < 4) {
2075 0 : reply_nterror(
2076 : req, NT_STATUS_INVALID_PARAMETER);
2077 0 : return;
2078 : }
2079 152 : ea_size = IVAL(pdata,0);
2080 :
2081 152 : if (total_data > 0 && ea_size != total_data) {
2082 0 : DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
2083 : total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2084 0 : reply_nterror(
2085 : req, NT_STATUS_INVALID_PARAMETER);
2086 0 : return;
2087 : }
2088 :
2089 152 : if (!lp_ea_support(SNUM(conn))) {
2090 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
2091 0 : return;
2092 : }
2093 :
2094 : /* Pull out the list of names. */
2095 152 : ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
2096 152 : if (!ea_list) {
2097 0 : reply_nterror(
2098 : req, NT_STATUS_INVALID_PARAMETER);
2099 0 : return;
2100 : }
2101 124 : break;
2102 : }
2103 :
2104 11488 : default:
2105 11488 : break;
2106 : }
2107 :
2108 12061 : *pparams = (char *)SMB_REALLOC(*pparams,2);
2109 12061 : if (*pparams == NULL) {
2110 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2111 0 : return;
2112 : }
2113 12061 : params = *pparams;
2114 12061 : SSVAL(params,0,0);
2115 :
2116 12061 : if ((info_level & SMB2_INFO_SPECIAL) == SMB2_INFO_SPECIAL) {
2117 : /*
2118 : * We use levels that start with 0xFF00
2119 : * internally to represent SMB2 specific levels
2120 : */
2121 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2122 0 : return;
2123 : }
2124 :
2125 12061 : status = smbd_do_qfilepathinfo(conn, req, req, info_level,
2126 : fsp, smb_fname,
2127 : delete_pending, write_time_ts,
2128 : ea_list,
2129 12061 : req->flags2, max_data_bytes,
2130 : &fixed_portion,
2131 : ppdata, &data_size);
2132 :
2133 12061 : handle_trans2qfilepathinfo_result(
2134 : conn,
2135 : req,
2136 : info_level,
2137 : status,
2138 : *ppdata,
2139 : data_size,
2140 : fixed_portion,
2141 : max_data_bytes);
2142 : }
2143 :
2144 114 : static NTSTATUS smb_q_unix_basic(
2145 : struct connection_struct *conn,
2146 : struct smb_request *req,
2147 : struct smb_filename *smb_fname,
2148 : struct files_struct *fsp,
2149 : char **ppdata,
2150 : int *ptotal_data)
2151 : {
2152 114 : const int total_data = 100;
2153 :
2154 114 : *ppdata = SMB_REALLOC(*ppdata, total_data);
2155 114 : if (*ppdata == NULL) {
2156 0 : return NT_STATUS_NO_MEMORY;
2157 : }
2158 114 : store_file_unix_basic(conn, *ppdata, fsp, &smb_fname->st);
2159 :
2160 114 : *ptotal_data = total_data;
2161 :
2162 114 : return NT_STATUS_OK;
2163 : }
2164 :
2165 20 : static NTSTATUS smb_q_unix_info2(
2166 : struct connection_struct *conn,
2167 : struct smb_request *req,
2168 : struct smb_filename *smb_fname,
2169 : struct files_struct *fsp,
2170 : char **ppdata,
2171 : int *ptotal_data)
2172 : {
2173 20 : const int total_data = 116;
2174 :
2175 20 : *ppdata = SMB_REALLOC(*ppdata, total_data);
2176 20 : if (*ppdata == NULL) {
2177 0 : return NT_STATUS_NO_MEMORY;
2178 : }
2179 20 : store_file_unix_basic_info2(conn, *ppdata, fsp, &smb_fname->st);
2180 :
2181 20 : *ptotal_data = total_data;
2182 :
2183 20 : return NT_STATUS_OK;
2184 : }
2185 :
2186 : #if defined(HAVE_POSIX_ACLS)
2187 : /****************************************************************************
2188 : Utility function to open a fsp for a POSIX handle operation.
2189 : ****************************************************************************/
2190 :
2191 88 : static NTSTATUS get_posix_fsp(connection_struct *conn,
2192 : struct smb_request *req,
2193 : struct smb_filename *smb_fname,
2194 : uint32_t access_mask,
2195 : files_struct **ret_fsp)
2196 : {
2197 0 : NTSTATUS status;
2198 88 : uint32_t create_disposition = FILE_OPEN;
2199 88 : uint32_t share_access = FILE_SHARE_READ|
2200 : FILE_SHARE_WRITE|
2201 : FILE_SHARE_DELETE;
2202 88 : struct smb2_create_blobs *posx = NULL;
2203 :
2204 : /*
2205 : * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
2206 : * but set reasonable defaults.
2207 : */
2208 88 : uint32_t file_attributes = 0664;
2209 88 : uint32_t oplock = NO_OPLOCK;
2210 88 : uint32_t create_options = FILE_NON_DIRECTORY_FILE;
2211 :
2212 : /* File or directory must exist. */
2213 88 : if (!VALID_STAT(smb_fname->st)) {
2214 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2215 : }
2216 : /* Cannot be a symlink. */
2217 88 : if (S_ISLNK(smb_fname->st.st_ex_mode)) {
2218 16 : return NT_STATUS_ACCESS_DENIED;
2219 : }
2220 : /* Set options correctly for directory open. */
2221 72 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
2222 : /*
2223 : * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
2224 : * directories, but set reasonable defaults.
2225 : */
2226 24 : file_attributes = 0775;
2227 24 : create_options = FILE_DIRECTORY_FILE;
2228 : }
2229 :
2230 72 : status = make_smb2_posix_create_ctx(
2231 : talloc_tos(), &posx, file_attributes);
2232 72 : if (!NT_STATUS_IS_OK(status)) {
2233 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
2234 : nt_errstr(status));
2235 0 : goto done;
2236 : }
2237 :
2238 72 : status = SMB_VFS_CREATE_FILE(
2239 : conn, /* conn */
2240 : req, /* req */
2241 : NULL, /* dirfsp */
2242 : smb_fname, /* fname */
2243 : access_mask, /* access_mask */
2244 : share_access, /* share_access */
2245 : create_disposition,/* create_disposition*/
2246 : create_options, /* create_options */
2247 : file_attributes,/* file_attributes */
2248 : oplock, /* oplock_request */
2249 : NULL, /* lease */
2250 : 0, /* allocation_size */
2251 : 0, /* private_flags */
2252 : NULL, /* sd */
2253 : NULL, /* ea_list */
2254 : ret_fsp, /* result */
2255 : NULL, /* pinfo */
2256 : posx, /* in_context */
2257 : NULL); /* out_context */
2258 :
2259 72 : done:
2260 72 : TALLOC_FREE(posx);
2261 72 : return status;
2262 : }
2263 :
2264 : /****************************************************************************
2265 : Utility function to count the number of entries in a POSIX acl.
2266 : ****************************************************************************/
2267 :
2268 128 : static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
2269 : {
2270 128 : unsigned int ace_count = 0;
2271 128 : int entry_id = SMB_ACL_FIRST_ENTRY;
2272 0 : SMB_ACL_ENTRY_T entry;
2273 :
2274 396 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2275 268 : entry_id = SMB_ACL_NEXT_ENTRY;
2276 268 : ace_count++;
2277 : }
2278 128 : return ace_count;
2279 : }
2280 :
2281 : /****************************************************************************
2282 : Utility function to marshall a POSIX acl into wire format.
2283 : ****************************************************************************/
2284 :
2285 128 : static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
2286 : {
2287 128 : int entry_id = SMB_ACL_FIRST_ENTRY;
2288 0 : SMB_ACL_ENTRY_T entry;
2289 :
2290 396 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2291 0 : SMB_ACL_TAG_T tagtype;
2292 0 : SMB_ACL_PERMSET_T permset;
2293 268 : unsigned char perms = 0;
2294 0 : unsigned int own_grp;
2295 :
2296 268 : entry_id = SMB_ACL_NEXT_ENTRY;
2297 :
2298 268 : if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
2299 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
2300 0 : return False;
2301 : }
2302 :
2303 268 : if (sys_acl_get_permset(entry, &permset) == -1) {
2304 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
2305 0 : return False;
2306 : }
2307 :
2308 268 : perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
2309 268 : perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
2310 268 : perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
2311 :
2312 268 : SCVAL(pdata,1,perms);
2313 :
2314 268 : switch (tagtype) {
2315 52 : case SMB_ACL_USER_OBJ:
2316 52 : SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
2317 52 : own_grp = (unsigned int)pst->st_ex_uid;
2318 52 : SIVAL(pdata,2,own_grp);
2319 52 : SIVAL(pdata,6,0);
2320 52 : break;
2321 40 : case SMB_ACL_USER:
2322 : {
2323 40 : uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2324 40 : if (!puid) {
2325 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2326 0 : return False;
2327 : }
2328 40 : own_grp = (unsigned int)*puid;
2329 40 : SCVAL(pdata,0,SMB_POSIX_ACL_USER);
2330 40 : SIVAL(pdata,2,own_grp);
2331 40 : SIVAL(pdata,6,0);
2332 40 : break;
2333 : }
2334 52 : case SMB_ACL_GROUP_OBJ:
2335 52 : SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
2336 52 : own_grp = (unsigned int)pst->st_ex_gid;
2337 52 : SIVAL(pdata,2,own_grp);
2338 52 : SIVAL(pdata,6,0);
2339 52 : break;
2340 36 : case SMB_ACL_GROUP:
2341 : {
2342 36 : gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
2343 36 : if (!pgid) {
2344 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2345 0 : return False;
2346 : }
2347 36 : own_grp = (unsigned int)*pgid;
2348 36 : SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
2349 36 : SIVAL(pdata,2,own_grp);
2350 36 : SIVAL(pdata,6,0);
2351 36 : break;
2352 : }
2353 36 : case SMB_ACL_MASK:
2354 36 : SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
2355 36 : SIVAL(pdata,2,0xFFFFFFFF);
2356 36 : SIVAL(pdata,6,0xFFFFFFFF);
2357 36 : break;
2358 52 : case SMB_ACL_OTHER:
2359 52 : SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
2360 52 : SIVAL(pdata,2,0xFFFFFFFF);
2361 52 : SIVAL(pdata,6,0xFFFFFFFF);
2362 52 : break;
2363 0 : default:
2364 0 : DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
2365 0 : return False;
2366 : }
2367 268 : pdata += SMB_POSIX_ACL_ENTRY_SIZE;
2368 : }
2369 :
2370 128 : return True;
2371 : }
2372 : #endif
2373 :
2374 80 : static NTSTATUS smb_q_posix_acl(
2375 : struct connection_struct *conn,
2376 : struct smb_request *req,
2377 : struct smb_filename *smb_fname,
2378 : struct files_struct *fsp,
2379 : char **ppdata,
2380 : int *ptotal_data)
2381 : {
2382 : #if !defined(HAVE_POSIX_ACLS)
2383 : return NT_STATUS_INVALID_LEVEL;
2384 : #else
2385 80 : char *pdata = NULL;
2386 80 : SMB_ACL_T file_acl = NULL;
2387 80 : SMB_ACL_T def_acl = NULL;
2388 80 : uint16_t num_file_acls = 0;
2389 80 : uint16_t num_def_acls = 0;
2390 80 : unsigned int size_needed = 0;
2391 0 : NTSTATUS status;
2392 0 : bool ok;
2393 80 : bool close_fsp = false;
2394 :
2395 : /*
2396 : * Ensure we always operate on a file descriptor, not just
2397 : * the filename.
2398 : */
2399 80 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
2400 80 : uint32_t access_mask = SEC_STD_READ_CONTROL|
2401 : FILE_READ_ATTRIBUTES|
2402 : FILE_WRITE_ATTRIBUTES;
2403 :
2404 80 : status = get_posix_fsp(conn,
2405 : req,
2406 : smb_fname,
2407 : access_mask,
2408 : &fsp);
2409 :
2410 80 : if (!NT_STATUS_IS_OK(status)) {
2411 16 : goto out;
2412 : }
2413 64 : close_fsp = true;
2414 : }
2415 :
2416 64 : SMB_ASSERT(fsp != NULL);
2417 :
2418 64 : status = refuse_symlink_fsp(fsp);
2419 64 : if (!NT_STATUS_IS_OK(status)) {
2420 0 : goto out;
2421 : }
2422 :
2423 64 : file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, SMB_ACL_TYPE_ACCESS,
2424 : talloc_tos());
2425 :
2426 64 : if (file_acl == NULL && no_acl_syscall_error(errno)) {
2427 0 : DBG_INFO("ACLs not implemented on "
2428 : "filesystem containing %s\n",
2429 : fsp_str_dbg(fsp));
2430 0 : status = NT_STATUS_NOT_IMPLEMENTED;
2431 0 : goto out;
2432 : }
2433 :
2434 64 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2435 : /*
2436 : * We can only have default POSIX ACLs on
2437 : * directories.
2438 : */
2439 20 : if (!fsp->fsp_flags.is_directory) {
2440 0 : DBG_INFO("Non-directory open %s\n",
2441 : fsp_str_dbg(fsp));
2442 0 : status = NT_STATUS_INVALID_HANDLE;
2443 0 : goto out;
2444 : }
2445 20 : def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
2446 : SMB_ACL_TYPE_DEFAULT,
2447 : talloc_tos());
2448 20 : def_acl = free_empty_sys_acl(conn, def_acl);
2449 : }
2450 :
2451 64 : num_file_acls = count_acl_entries(conn, file_acl);
2452 64 : num_def_acls = count_acl_entries(conn, def_acl);
2453 :
2454 : /* Wrap checks. */
2455 0 : if (num_file_acls + num_def_acls < num_file_acls) {
2456 : status = NT_STATUS_INVALID_PARAMETER;
2457 : goto out;
2458 : }
2459 :
2460 64 : size_needed = num_file_acls + num_def_acls;
2461 :
2462 : /*
2463 : * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
2464 : * than UINT_MAX, so check by division.
2465 : */
2466 64 : if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
2467 0 : status = NT_STATUS_INVALID_PARAMETER;
2468 0 : goto out;
2469 : }
2470 :
2471 64 : size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
2472 64 : if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
2473 0 : status = NT_STATUS_INVALID_PARAMETER;
2474 0 : goto out;
2475 : }
2476 64 : size_needed += SMB_POSIX_ACL_HEADER_SIZE;
2477 :
2478 64 : *ppdata = SMB_REALLOC(*ppdata, size_needed);
2479 64 : if (*ppdata == NULL) {
2480 0 : status = NT_STATUS_NO_MEMORY;
2481 0 : goto out;
2482 : }
2483 64 : pdata = *ppdata;
2484 :
2485 64 : SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
2486 64 : SSVAL(pdata,2,num_file_acls);
2487 64 : SSVAL(pdata,4,num_def_acls);
2488 64 : pdata += SMB_POSIX_ACL_HEADER_SIZE;
2489 :
2490 64 : ok = marshall_posix_acl(conn,
2491 : pdata,
2492 64 : &fsp->fsp_name->st,
2493 : file_acl);
2494 64 : if (!ok) {
2495 0 : status = NT_STATUS_INTERNAL_ERROR;
2496 0 : goto out;
2497 : }
2498 64 : pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
2499 :
2500 64 : ok = marshall_posix_acl(conn,
2501 : pdata,
2502 64 : &fsp->fsp_name->st,
2503 : def_acl);
2504 64 : if (!ok) {
2505 0 : status = NT_STATUS_INTERNAL_ERROR;
2506 0 : goto out;
2507 : }
2508 :
2509 64 : *ptotal_data = size_needed;
2510 64 : status = NT_STATUS_OK;
2511 :
2512 80 : out:
2513 :
2514 80 : if (close_fsp) {
2515 : /*
2516 : * Ensure the stat struct in smb_fname is up to
2517 : * date. Structure copy.
2518 : */
2519 64 : smb_fname->st = fsp->fsp_name->st;
2520 64 : (void)close_file_free(req, &fsp, NORMAL_CLOSE);
2521 : }
2522 :
2523 80 : TALLOC_FREE(file_acl);
2524 80 : TALLOC_FREE(def_acl);
2525 80 : return status;
2526 : #endif
2527 : }
2528 :
2529 24 : static NTSTATUS smb_q_posix_symlink(
2530 : struct connection_struct *conn,
2531 : struct smb_request *req,
2532 : struct files_struct *dirfsp,
2533 : struct smb_filename *smb_fname,
2534 : char **ppdata,
2535 : int *ptotal_data)
2536 : {
2537 24 : char *target = NULL;
2538 0 : size_t needed, len;
2539 24 : char *pdata = NULL;
2540 0 : NTSTATUS status;
2541 :
2542 24 : DBG_DEBUG("SMB_QUERY_FILE_UNIX_LINK for file %s\n",
2543 : smb_fname_str_dbg(smb_fname));
2544 :
2545 24 : if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
2546 0 : return NT_STATUS_DOS(ERRSRV, ERRbadlink);
2547 : }
2548 :
2549 24 : if (fsp_get_pathref_fd(smb_fname->fsp) != -1) {
2550 : /*
2551 : * fsp is an O_PATH open, Linux does a "freadlink"
2552 : * with an empty name argument to readlinkat
2553 : */
2554 12 : status = readlink_talloc(talloc_tos(),
2555 : smb_fname->fsp,
2556 : NULL,
2557 : &target);
2558 : } else {
2559 12 : struct smb_filename smb_fname_rel = *smb_fname;
2560 12 : char *slash = NULL;
2561 :
2562 12 : slash = strrchr_m(smb_fname->base_name, '/');
2563 12 : if (slash != NULL) {
2564 0 : smb_fname_rel.base_name = slash + 1;
2565 : }
2566 12 : status = readlink_talloc(talloc_tos(),
2567 : dirfsp,
2568 : &smb_fname_rel,
2569 : &target);
2570 : }
2571 :
2572 24 : if (!NT_STATUS_IS_OK(status)) {
2573 0 : DBG_DEBUG("readlink_talloc() failed: %s\n", nt_errstr(status));
2574 0 : return status;
2575 : }
2576 :
2577 24 : needed = talloc_get_size(target) * 2;
2578 :
2579 24 : *ppdata = SMB_REALLOC(*ppdata, needed);
2580 24 : if (*ppdata == NULL) {
2581 0 : TALLOC_FREE(target);
2582 0 : return NT_STATUS_NO_MEMORY;
2583 : }
2584 24 : pdata = *ppdata;
2585 :
2586 24 : status = srvstr_push(
2587 : pdata,
2588 : req->flags2,
2589 : pdata,
2590 : target,
2591 : needed,
2592 : STR_TERMINATE,
2593 : &len);
2594 24 : TALLOC_FREE(target);
2595 24 : if (!NT_STATUS_IS_OK(status)) {
2596 0 : return status;
2597 : }
2598 24 : *ptotal_data = len;
2599 :
2600 24 : return NT_STATUS_OK;
2601 : }
2602 :
2603 10825 : static void call_trans2qpathinfo(
2604 : connection_struct *conn,
2605 : struct smb_request *req,
2606 : char **pparams,
2607 : int total_params,
2608 : char **ppdata,
2609 : int total_data,
2610 : unsigned int max_data_bytes)
2611 : {
2612 10825 : char *params = *pparams;
2613 289 : uint16_t info_level;
2614 10825 : struct smb_filename *smb_fname = NULL;
2615 10825 : bool delete_pending = False;
2616 10825 : struct timespec write_time_ts = { .tv_sec = 0, };
2617 10825 : struct files_struct *dirfsp = NULL;
2618 10825 : files_struct *fsp = NULL;
2619 10825 : char *fname = NULL;
2620 10825 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
2621 10825 : NTTIME twrp = 0;
2622 289 : bool info_level_handled;
2623 10825 : NTSTATUS status = NT_STATUS_OK;
2624 :
2625 10825 : if (!params) {
2626 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2627 0 : return;
2628 : }
2629 :
2630 :
2631 : /* qpathinfo */
2632 10825 : if (total_params < 7) {
2633 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2634 0 : return;
2635 : }
2636 :
2637 10825 : info_level = SVAL(params,0);
2638 :
2639 10825 : DBG_NOTICE("TRANSACT2_QPATHINFO: level = %d\n", info_level);
2640 :
2641 10825 : if (INFO_LEVEL_IS_UNIX(info_level)) {
2642 242 : if (!lp_smb1_unix_extensions()) {
2643 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2644 0 : return;
2645 : }
2646 242 : if (!req->posix_pathnames) {
2647 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2648 0 : return;
2649 : }
2650 : }
2651 :
2652 10825 : if (req->posix_pathnames) {
2653 450 : srvstr_get_path_posix(req,
2654 : params,
2655 450 : req->flags2,
2656 : &fname,
2657 450 : ¶ms[6],
2658 450 : total_params - 6,
2659 : STR_TERMINATE,
2660 : &status);
2661 : } else {
2662 10375 : srvstr_get_path(req,
2663 : params,
2664 10375 : req->flags2,
2665 : &fname,
2666 10375 : ¶ms[6],
2667 10375 : total_params - 6,
2668 : STR_TERMINATE,
2669 : &status);
2670 : }
2671 10825 : if (!NT_STATUS_IS_OK(status)) {
2672 0 : reply_nterror(req, status);
2673 0 : return;
2674 : }
2675 :
2676 10825 : if (ucf_flags & UCF_GMT_PATHNAME) {
2677 3632 : extract_snapshot_token(fname, &twrp);
2678 : }
2679 10825 : status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
2680 10825 : if (!NT_STATUS_IS_OK(status)) {
2681 0 : reply_nterror(req, status);
2682 0 : return;
2683 : }
2684 10825 : status = filename_convert_dirfsp(req,
2685 : conn,
2686 : fname,
2687 : ucf_flags,
2688 : twrp,
2689 : &dirfsp,
2690 : &smb_fname);
2691 10825 : if (!NT_STATUS_IS_OK(status)) {
2692 1766 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2693 1216 : reply_botherror(req,
2694 : NT_STATUS_PATH_NOT_COVERED,
2695 : ERRSRV, ERRbadpath);
2696 1216 : return;
2697 : }
2698 550 : reply_nterror(req, status);
2699 550 : return;
2700 : }
2701 :
2702 : /*
2703 : * qpathinfo must operate on an existing file, so we
2704 : * can exit early if filename_convert_dirfsp() returned the
2705 : * "new file" NT_STATUS_OK, !VALID_STAT case.
2706 : */
2707 :
2708 9059 : if (!VALID_STAT(smb_fname->st)) {
2709 110 : reply_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2710 110 : return;
2711 : }
2712 :
2713 8949 : fsp = smb_fname->fsp;
2714 :
2715 : /* If this is a stream, check if there is a delete_pending. */
2716 8949 : if (fsp_is_alternate_stream(fsp)) {
2717 :
2718 60 : struct files_struct *base_fsp = fsp->base_fsp;
2719 :
2720 60 : get_file_infos(base_fsp->file_id,
2721 : base_fsp->name_hash,
2722 : &delete_pending,
2723 : NULL);
2724 60 : if (delete_pending) {
2725 4 : reply_nterror(req, NT_STATUS_DELETE_PENDING);
2726 4 : return;
2727 : }
2728 : }
2729 :
2730 8945 : if (fsp_getinfo_ask_sharemode(fsp)) {
2731 8945 : get_file_infos(fsp->file_id,
2732 : fsp->name_hash,
2733 : &delete_pending,
2734 : &write_time_ts);
2735 : }
2736 :
2737 8945 : if (delete_pending) {
2738 119 : reply_nterror(req, NT_STATUS_DELETE_PENDING);
2739 119 : return;
2740 : }
2741 :
2742 8826 : info_level_handled = true; /* Untouched in switch cases below */
2743 :
2744 8826 : switch (info_level) {
2745 :
2746 8328 : default:
2747 8328 : info_level_handled = false;
2748 8328 : break;
2749 :
2750 114 : case SMB_QUERY_FILE_UNIX_BASIC:
2751 114 : status = smb_q_unix_basic(
2752 : conn,
2753 : req,
2754 : smb_fname,
2755 114 : smb_fname->fsp,
2756 : ppdata,
2757 : &total_data);
2758 114 : break;
2759 :
2760 16 : case SMB_QUERY_FILE_UNIX_INFO2:
2761 16 : status = smb_q_unix_info2(
2762 : conn,
2763 : req,
2764 : smb_fname,
2765 16 : smb_fname->fsp,
2766 : ppdata,
2767 : &total_data);
2768 16 : break;
2769 :
2770 80 : case SMB_QUERY_POSIX_ACL:
2771 80 : status = smb_q_posix_acl(
2772 : conn,
2773 : req,
2774 : smb_fname,
2775 80 : smb_fname->fsp,
2776 : ppdata,
2777 : &total_data);
2778 80 : break;
2779 :
2780 24 : case SMB_QUERY_FILE_UNIX_LINK:
2781 24 : status = smb_q_posix_symlink(
2782 : conn,
2783 : req,
2784 : dirfsp,
2785 : smb_fname,
2786 : ppdata,
2787 : &total_data);
2788 24 : break;
2789 : }
2790 :
2791 8562 : if (info_level_handled) {
2792 234 : handle_trans2qfilepathinfo_result(
2793 : conn,
2794 : req,
2795 : info_level,
2796 : status,
2797 : *ppdata,
2798 : total_data,
2799 : total_data,
2800 : max_data_bytes);
2801 234 : return;
2802 : }
2803 :
2804 8592 : call_trans2qfilepathinfo(
2805 : conn,
2806 : req,
2807 : TRANSACT2_QPATHINFO,
2808 : info_level,
2809 : smb_fname,
2810 : fsp,
2811 : false,
2812 : write_time_ts,
2813 : pparams,
2814 : total_params,
2815 : ppdata,
2816 : total_data,
2817 : max_data_bytes);
2818 : }
2819 :
2820 0 : static NTSTATUS smb_q_posix_lock(
2821 : struct connection_struct *conn,
2822 : struct smb_request *req,
2823 : struct files_struct *fsp,
2824 : char **ppdata,
2825 : int *ptotal_data)
2826 : {
2827 0 : char *pdata = *ppdata;
2828 0 : int total_data = *ptotal_data;
2829 0 : uint64_t count;
2830 0 : uint64_t offset;
2831 0 : uint64_t smblctx;
2832 0 : enum brl_type lock_type;
2833 0 : NTSTATUS status;
2834 :
2835 0 : if (fsp->fsp_flags.is_pathref || (fsp_get_io_fd(fsp) == -1)) {
2836 0 : return NT_STATUS_INVALID_HANDLE;
2837 : }
2838 :
2839 0 : if (total_data != POSIX_LOCK_DATA_SIZE) {
2840 0 : return NT_STATUS_INVALID_PARAMETER;
2841 : }
2842 :
2843 0 : switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
2844 0 : case POSIX_LOCK_TYPE_READ:
2845 0 : lock_type = READ_LOCK;
2846 0 : break;
2847 0 : case POSIX_LOCK_TYPE_WRITE:
2848 0 : lock_type = WRITE_LOCK;
2849 0 : break;
2850 0 : case POSIX_LOCK_TYPE_UNLOCK:
2851 : default:
2852 : /* There's no point in asking for an unlock... */
2853 0 : return NT_STATUS_INVALID_PARAMETER;
2854 : }
2855 :
2856 0 : smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
2857 0 : offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
2858 0 : count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
2859 :
2860 0 : status = query_lock(
2861 : fsp,
2862 : &smblctx,
2863 : &count,
2864 : &offset,
2865 : &lock_type,
2866 : POSIX_LOCK);
2867 :
2868 0 : if (NT_STATUS_IS_OK(status)) {
2869 : /*
2870 : * For success we just return a copy of what we sent
2871 : * with the lock type set to POSIX_LOCK_TYPE_UNLOCK.
2872 : */
2873 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
2874 0 : return NT_STATUS_OK;
2875 : }
2876 :
2877 0 : if (!ERROR_WAS_LOCK_DENIED(status)) {
2878 0 : DBG_DEBUG("query_lock() failed: %s\n", nt_errstr(status));
2879 0 : return status;
2880 : }
2881 :
2882 : /*
2883 : * Here we need to report who has it locked.
2884 : */
2885 :
2886 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
2887 0 : SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
2888 0 : SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
2889 0 : SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
2890 0 : SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
2891 :
2892 0 : return NT_STATUS_OK;
2893 : }
2894 :
2895 3617 : static void call_trans2qfileinfo(
2896 : connection_struct *conn,
2897 : struct smb_request *req,
2898 : char **pparams,
2899 : int total_params,
2900 : char **ppdata,
2901 : int total_data,
2902 : unsigned int max_data_bytes)
2903 : {
2904 3617 : char *params = *pparams;
2905 185 : uint16_t info_level;
2906 3617 : struct smb_filename *smb_fname = NULL;
2907 3617 : bool delete_pending = False;
2908 3617 : struct timespec write_time_ts = { .tv_sec = 0, };
2909 3617 : files_struct *fsp = NULL;
2910 185 : struct file_id fileid;
2911 185 : bool info_level_handled;
2912 3617 : NTSTATUS status = NT_STATUS_OK;
2913 185 : int ret;
2914 :
2915 3617 : if (params == NULL) {
2916 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2917 0 : return;
2918 : }
2919 :
2920 3617 : if (total_params < 4) {
2921 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2922 0 : return;
2923 : }
2924 :
2925 3617 : fsp = file_fsp(req, SVAL(params,0));
2926 3617 : info_level = SVAL(params,2);
2927 :
2928 3617 : if (IS_IPC(conn)) {
2929 0 : call_trans2qpipeinfo(
2930 : conn,
2931 : req,
2932 : fsp,
2933 : info_level,
2934 : TRANSACT2_QFILEINFO,
2935 : pparams,
2936 : total_params,
2937 : ppdata,
2938 : total_data,
2939 : max_data_bytes);
2940 0 : return;
2941 : }
2942 :
2943 3617 : DBG_NOTICE("TRANSACT2_QFILEINFO: level = %d\n", info_level);
2944 :
2945 3617 : if (INFO_LEVEL_IS_UNIX(info_level)) {
2946 4 : if (!lp_smb1_unix_extensions()) {
2947 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2948 0 : return;
2949 : }
2950 4 : if (!req->posix_pathnames) {
2951 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2952 0 : return;
2953 : }
2954 : }
2955 :
2956 : /* Initial check for valid fsp ptr. */
2957 3617 : if (!check_fsp_open(conn, req, fsp)) {
2958 144 : return;
2959 : }
2960 :
2961 3473 : smb_fname = fsp->fsp_name;
2962 :
2963 3473 : if(fsp->fake_file_handle) {
2964 : /*
2965 : * This is actually for the QUOTA_FAKE_FILE --metze
2966 : */
2967 :
2968 : /* We know this name is ok, it's already passed the checks. */
2969 :
2970 3473 : } else if(fsp_get_pathref_fd(fsp) == -1) {
2971 : /*
2972 : * This is actually a QFILEINFO on a directory
2973 : * handle (returned from an NT SMB). NT5.0 seems
2974 : * to do this call. JRA.
2975 : */
2976 0 : ret = vfs_stat(conn, smb_fname);
2977 0 : if (ret != 0) {
2978 0 : DBG_NOTICE("vfs_stat of %s failed (%s)\n",
2979 : smb_fname_str_dbg(smb_fname),
2980 : strerror(errno));
2981 0 : reply_nterror(req,
2982 : map_nt_error_from_unix(errno));
2983 0 : return;
2984 : }
2985 :
2986 0 : if (fsp_getinfo_ask_sharemode(fsp)) {
2987 0 : fileid = vfs_file_id_from_sbuf(
2988 0 : conn, &smb_fname->st);
2989 0 : get_file_infos(fileid, fsp->name_hash,
2990 : &delete_pending,
2991 : &write_time_ts);
2992 : }
2993 : } else {
2994 : /*
2995 : * Original code - this is an open file.
2996 : */
2997 3473 : status = vfs_stat_fsp(fsp);
2998 3473 : if (!NT_STATUS_IS_OK(status)) {
2999 0 : DEBUG(3, ("fstat of %s failed (%s)\n",
3000 : fsp_fnum_dbg(fsp), nt_errstr(status)));
3001 0 : reply_nterror(req, status);
3002 0 : return;
3003 : }
3004 3473 : if (fsp_getinfo_ask_sharemode(fsp)) {
3005 3473 : fileid = vfs_file_id_from_sbuf(
3006 3473 : conn, &smb_fname->st);
3007 3473 : get_file_infos(fileid, fsp->name_hash,
3008 : &delete_pending,
3009 : &write_time_ts);
3010 : }
3011 : }
3012 :
3013 3473 : info_level_handled = true; /* Untouched in switch cases below */
3014 :
3015 3473 : switch (info_level) {
3016 :
3017 3284 : default:
3018 3284 : info_level_handled = false;
3019 3284 : break;
3020 :
3021 0 : case SMB_QUERY_POSIX_LOCK:
3022 0 : status = smb_q_posix_lock(conn, req, fsp, ppdata, &total_data);
3023 0 : break;
3024 :
3025 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3026 0 : status = smb_q_unix_basic(
3027 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3028 0 : break;
3029 :
3030 4 : case SMB_QUERY_FILE_UNIX_INFO2:
3031 4 : status = smb_q_unix_info2(
3032 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3033 4 : break;
3034 :
3035 0 : case SMB_QUERY_POSIX_ACL:
3036 0 : status = smb_q_posix_acl(
3037 : conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3038 0 : break;
3039 : }
3040 :
3041 3288 : if (info_level_handled) {
3042 4 : handle_trans2qfilepathinfo_result(
3043 : conn,
3044 : req,
3045 : info_level,
3046 : status,
3047 : *ppdata,
3048 : total_data,
3049 : total_data,
3050 : max_data_bytes);
3051 4 : return;
3052 : }
3053 :
3054 3469 : call_trans2qfilepathinfo(
3055 : conn,
3056 : req,
3057 : TRANSACT2_QFILEINFO,
3058 : info_level,
3059 : smb_fname,
3060 : fsp,
3061 : delete_pending,
3062 : write_time_ts,
3063 : pparams,
3064 : total_params,
3065 : ppdata,
3066 : total_data,
3067 : max_data_bytes);
3068 : }
3069 :
3070 5607 : static void handle_trans2setfilepathinfo_result(
3071 : connection_struct *conn,
3072 : struct smb_request *req,
3073 : uint16_t info_level,
3074 : NTSTATUS status,
3075 : char *pdata,
3076 : int data_return_size,
3077 : unsigned int max_data_bytes)
3078 : {
3079 5607 : char params[2] = { 0, 0, };
3080 :
3081 5607 : if (NT_STATUS_IS_OK(status)) {
3082 4680 : send_trans2_replies(
3083 : conn,
3084 : req,
3085 4680 : NT_STATUS_OK,
3086 : params,
3087 : 2,
3088 : pdata,
3089 : data_return_size,
3090 : max_data_bytes);
3091 4680 : return;
3092 : }
3093 :
3094 927 : if (open_was_deferred(req->xconn, req->mid)) {
3095 : /* We have re-scheduled this call. */
3096 6 : return;
3097 : }
3098 :
3099 921 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3100 32 : bool ok = defer_smb1_sharing_violation(req);
3101 32 : if (ok) {
3102 16 : return;
3103 : }
3104 : }
3105 :
3106 905 : if (NT_STATUS_EQUAL(status, NT_STATUS_EVENT_PENDING)) {
3107 : /* We have re-scheduled this call. */
3108 28 : return;
3109 : }
3110 :
3111 877 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3112 0 : reply_botherror(
3113 : req,
3114 : NT_STATUS_PATH_NOT_COVERED,
3115 : ERRSRV,
3116 : ERRbadpath);
3117 0 : return;
3118 : }
3119 :
3120 877 : if (info_level == SMB_POSIX_PATH_OPEN) {
3121 12 : reply_openerror(req, status);
3122 12 : return;
3123 : }
3124 :
3125 865 : if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
3126 : /*
3127 : * Invalid EA name needs to return 2 param bytes,
3128 : * not a zero-length error packet.
3129 : */
3130 :
3131 235 : send_trans2_replies(
3132 : conn,
3133 : req,
3134 : status,
3135 : params,
3136 : 2,
3137 : NULL,
3138 : 0,
3139 : max_data_bytes);
3140 235 : return;
3141 : }
3142 :
3143 630 : reply_nterror(req, status);
3144 : }
3145 :
3146 : /****************************************************************************
3147 : Create a directory with POSIX semantics.
3148 : ****************************************************************************/
3149 :
3150 48 : static NTSTATUS smb_posix_mkdir(connection_struct *conn,
3151 : struct smb_request *req,
3152 : char **ppdata,
3153 : int total_data,
3154 : struct smb_filename *smb_fname,
3155 : int *pdata_return_size)
3156 : {
3157 48 : NTSTATUS status = NT_STATUS_OK;
3158 48 : uint32_t raw_unixmode = 0;
3159 48 : mode_t unixmode = (mode_t)0;
3160 48 : files_struct *fsp = NULL;
3161 48 : uint16_t info_level_return = 0;
3162 0 : int info;
3163 48 : char *pdata = *ppdata;
3164 48 : struct smb2_create_blobs *posx = NULL;
3165 :
3166 48 : if (total_data < 18) {
3167 0 : return NT_STATUS_INVALID_PARAMETER;
3168 : }
3169 :
3170 48 : raw_unixmode = IVAL(pdata,8);
3171 : /* Next 4 bytes are not yet defined. */
3172 :
3173 48 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3174 : PERM_NEW_DIR, &unixmode);
3175 48 : if (!NT_STATUS_IS_OK(status)) {
3176 0 : return status;
3177 : }
3178 :
3179 48 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3180 48 : if (!NT_STATUS_IS_OK(status)) {
3181 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3182 : nt_errstr(status));
3183 0 : return status;
3184 : }
3185 :
3186 48 : DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
3187 : smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
3188 :
3189 48 : status = SMB_VFS_CREATE_FILE(
3190 : conn, /* conn */
3191 : req, /* req */
3192 : NULL, /* dirfsp */
3193 : smb_fname, /* fname */
3194 : FILE_READ_ATTRIBUTES, /* access_mask */
3195 : FILE_SHARE_NONE, /* share_access */
3196 : FILE_CREATE, /* create_disposition*/
3197 : FILE_DIRECTORY_FILE, /* create_options */
3198 : 0, /* file_attributes */
3199 : 0, /* oplock_request */
3200 : NULL, /* lease */
3201 : 0, /* allocation_size */
3202 : 0, /* private_flags */
3203 : NULL, /* sd */
3204 : NULL, /* ea_list */
3205 : &fsp, /* result */
3206 : &info, /* pinfo */
3207 : posx, /* in_context_blobs */
3208 : NULL); /* out_context_blobs */
3209 :
3210 48 : TALLOC_FREE(posx);
3211 :
3212 48 : if (NT_STATUS_IS_OK(status)) {
3213 48 : close_file_free(req, &fsp, NORMAL_CLOSE);
3214 : }
3215 :
3216 48 : info_level_return = SVAL(pdata,16);
3217 :
3218 48 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3219 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3220 48 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3221 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3222 : } else {
3223 48 : *pdata_return_size = 12;
3224 : }
3225 :
3226 : /* Realloc the data size */
3227 48 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3228 48 : if (*ppdata == NULL) {
3229 0 : *pdata_return_size = 0;
3230 0 : return NT_STATUS_NO_MEMORY;
3231 : }
3232 48 : pdata = *ppdata;
3233 :
3234 48 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
3235 48 : SSVAL(pdata,2,0); /* No fnum. */
3236 48 : SIVAL(pdata,4,info); /* Was directory created. */
3237 :
3238 48 : switch (info_level_return) {
3239 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3240 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3241 0 : SSVAL(pdata,10,0); /* Padding. */
3242 0 : store_file_unix_basic(conn, pdata + 12, fsp,
3243 0 : &smb_fname->st);
3244 0 : break;
3245 0 : case SMB_QUERY_FILE_UNIX_INFO2:
3246 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3247 0 : SSVAL(pdata,10,0); /* Padding. */
3248 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
3249 0 : &smb_fname->st);
3250 0 : break;
3251 48 : default:
3252 48 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3253 48 : SSVAL(pdata,10,0); /* Padding. */
3254 48 : break;
3255 : }
3256 :
3257 48 : return status;
3258 : }
3259 :
3260 : /****************************************************************************
3261 : Open/Create a file with POSIX semantics.
3262 : ****************************************************************************/
3263 :
3264 : #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
3265 : #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
3266 :
3267 174 : static NTSTATUS smb_posix_open(connection_struct *conn,
3268 : struct smb_request *req,
3269 : char **ppdata,
3270 : int total_data,
3271 : struct files_struct *dirfsp,
3272 : struct smb_filename *smb_fname,
3273 : int *pdata_return_size)
3274 : {
3275 174 : bool extended_oplock_granted = False;
3276 174 : char *pdata = *ppdata;
3277 174 : uint32_t flags = 0;
3278 174 : uint32_t wire_open_mode = 0;
3279 174 : uint32_t raw_unixmode = 0;
3280 174 : uint32_t attributes = 0;
3281 174 : uint32_t create_disp = 0;
3282 174 : uint32_t access_mask = 0;
3283 174 : uint32_t create_options = FILE_NON_DIRECTORY_FILE;
3284 174 : NTSTATUS status = NT_STATUS_OK;
3285 174 : mode_t unixmode = (mode_t)0;
3286 174 : files_struct *fsp = NULL;
3287 174 : int oplock_request = 0;
3288 174 : int info = 0;
3289 174 : uint16_t info_level_return = 0;
3290 174 : struct smb2_create_blobs *posx = NULL;
3291 :
3292 174 : if (total_data < 18) {
3293 0 : return NT_STATUS_INVALID_PARAMETER;
3294 : }
3295 :
3296 174 : flags = IVAL(pdata,0);
3297 174 : oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
3298 174 : if (oplock_request) {
3299 0 : oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
3300 : }
3301 :
3302 174 : wire_open_mode = IVAL(pdata,4);
3303 :
3304 174 : if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
3305 48 : return smb_posix_mkdir(conn, req,
3306 : ppdata,
3307 : total_data,
3308 : smb_fname,
3309 : pdata_return_size);
3310 : }
3311 :
3312 126 : switch (wire_open_mode & SMB_ACCMODE) {
3313 28 : case SMB_O_RDONLY:
3314 28 : access_mask = SMB_O_RDONLY_MAPPING;
3315 28 : break;
3316 4 : case SMB_O_WRONLY:
3317 4 : access_mask = SMB_O_WRONLY_MAPPING;
3318 4 : break;
3319 94 : case SMB_O_RDWR:
3320 94 : access_mask = (SMB_O_RDONLY_MAPPING|
3321 : SMB_O_WRONLY_MAPPING);
3322 94 : break;
3323 0 : default:
3324 0 : DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
3325 : (unsigned int)wire_open_mode ));
3326 0 : return NT_STATUS_INVALID_PARAMETER;
3327 : }
3328 :
3329 126 : wire_open_mode &= ~SMB_ACCMODE;
3330 :
3331 : /* First take care of O_CREAT|O_EXCL interactions. */
3332 126 : switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
3333 38 : case (SMB_O_CREAT | SMB_O_EXCL):
3334 : /* File exists fail. File not exist create. */
3335 38 : create_disp = FILE_CREATE;
3336 38 : break;
3337 40 : case SMB_O_CREAT:
3338 : /* File exists open. File not exist create. */
3339 40 : create_disp = FILE_OPEN_IF;
3340 40 : break;
3341 48 : case SMB_O_EXCL:
3342 : /* O_EXCL on its own without O_CREAT is undefined.
3343 : We deliberately ignore it as some versions of
3344 : Linux CIFSFS can send a bare O_EXCL on the
3345 : wire which other filesystems in the kernel
3346 : ignore. See bug 9519 for details. */
3347 :
3348 : /* Fallthrough. */
3349 :
3350 : case 0:
3351 : /* File exists open. File not exist fail. */
3352 48 : create_disp = FILE_OPEN;
3353 48 : break;
3354 0 : default:
3355 0 : DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
3356 : (unsigned int)wire_open_mode ));
3357 0 : return NT_STATUS_INVALID_PARAMETER;
3358 : }
3359 :
3360 : /* Next factor in the effects of O_TRUNC. */
3361 126 : wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
3362 :
3363 126 : if (wire_open_mode & SMB_O_TRUNC) {
3364 4 : switch (create_disp) {
3365 0 : case FILE_CREATE:
3366 : /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
3367 : /* Leave create_disp alone as
3368 : (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
3369 : */
3370 : /* File exists fail. File not exist create. */
3371 4 : break;
3372 0 : case FILE_OPEN_IF:
3373 : /* SMB_O_CREAT | SMB_O_TRUNC */
3374 : /* File exists overwrite. File not exist create. */
3375 0 : create_disp = FILE_OVERWRITE_IF;
3376 0 : break;
3377 4 : case FILE_OPEN:
3378 : /* SMB_O_TRUNC */
3379 : /* File exists overwrite. File not exist fail. */
3380 4 : create_disp = FILE_OVERWRITE;
3381 4 : break;
3382 0 : default:
3383 : /* Cannot get here. */
3384 0 : smb_panic("smb_posix_open: logic error");
3385 : return NT_STATUS_INVALID_PARAMETER;
3386 : }
3387 : }
3388 :
3389 126 : raw_unixmode = IVAL(pdata,8);
3390 : /* Next 4 bytes are not yet defined. */
3391 :
3392 126 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3393 126 : (VALID_STAT(smb_fname->st) ?
3394 : PERM_EXISTING_FILE : PERM_NEW_FILE),
3395 : &unixmode);
3396 :
3397 126 : if (!NT_STATUS_IS_OK(status)) {
3398 0 : return status;
3399 : }
3400 :
3401 126 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3402 126 : if (!NT_STATUS_IS_OK(status)) {
3403 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3404 : nt_errstr(status));
3405 0 : return status;
3406 : }
3407 :
3408 126 : if (wire_open_mode & SMB_O_SYNC) {
3409 0 : create_options |= FILE_WRITE_THROUGH;
3410 : }
3411 126 : if (wire_open_mode & SMB_O_APPEND) {
3412 0 : access_mask |= FILE_APPEND_DATA;
3413 : }
3414 126 : if (wire_open_mode & SMB_O_DIRECT) {
3415 : /*
3416 : * BUG: this doesn't work anymore since
3417 : * e0814dc5082dd4ecca8a155e0ce24b073158fd92. But since
3418 : * FILE_FLAG_NO_BUFFERING isn't used at all in the IO codepath,
3419 : * it doesn't really matter.
3420 : */
3421 0 : attributes |= FILE_FLAG_NO_BUFFERING;
3422 : }
3423 :
3424 126 : if ((wire_open_mode & SMB_O_DIRECTORY) ||
3425 126 : VALID_STAT_OF_DIR(smb_fname->st)) {
3426 8 : if (access_mask != SMB_O_RDONLY_MAPPING) {
3427 4 : return NT_STATUS_FILE_IS_A_DIRECTORY;
3428 : }
3429 4 : create_options &= ~FILE_NON_DIRECTORY_FILE;
3430 4 : create_options |= FILE_DIRECTORY_FILE;
3431 : }
3432 :
3433 122 : DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
3434 : smb_fname_str_dbg(smb_fname),
3435 : (unsigned int)wire_open_mode,
3436 : (unsigned int)unixmode ));
3437 :
3438 122 : status = SMB_VFS_CREATE_FILE(
3439 : conn, /* conn */
3440 : req, /* req */
3441 : dirfsp, /* dirfsp */
3442 : smb_fname, /* fname */
3443 : access_mask, /* access_mask */
3444 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3445 : FILE_SHARE_DELETE),
3446 : create_disp, /* create_disposition*/
3447 : create_options, /* create_options */
3448 : attributes, /* file_attributes */
3449 : oplock_request, /* oplock_request */
3450 : NULL, /* lease */
3451 : 0, /* allocation_size */
3452 : 0, /* private_flags */
3453 : NULL, /* sd */
3454 : NULL, /* ea_list */
3455 : &fsp, /* result */
3456 : &info, /* pinfo */
3457 : posx, /* in_context_blobs */
3458 : NULL); /* out_context_blobs */
3459 :
3460 122 : TALLOC_FREE(posx);
3461 :
3462 122 : if (!NT_STATUS_IS_OK(status)) {
3463 8 : return status;
3464 : }
3465 :
3466 114 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3467 0 : extended_oplock_granted = True;
3468 : }
3469 :
3470 114 : if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3471 0 : extended_oplock_granted = True;
3472 : }
3473 :
3474 114 : info_level_return = SVAL(pdata,16);
3475 :
3476 : /* Allocate the correct return size. */
3477 :
3478 114 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3479 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3480 114 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3481 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3482 : } else {
3483 114 : *pdata_return_size = 12;
3484 : }
3485 :
3486 : /* Realloc the data size */
3487 114 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3488 114 : if (*ppdata == NULL) {
3489 0 : close_file_free(req, &fsp, ERROR_CLOSE);
3490 0 : *pdata_return_size = 0;
3491 0 : return NT_STATUS_NO_MEMORY;
3492 : }
3493 114 : pdata = *ppdata;
3494 :
3495 114 : if (extended_oplock_granted) {
3496 0 : if (flags & REQUEST_BATCH_OPLOCK) {
3497 0 : SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
3498 : } else {
3499 0 : SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
3500 : }
3501 114 : } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
3502 0 : SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
3503 : } else {
3504 114 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
3505 : }
3506 :
3507 114 : SSVAL(pdata,2,fsp->fnum);
3508 114 : SIVAL(pdata,4,info); /* Was file created etc. */
3509 :
3510 114 : switch (info_level_return) {
3511 0 : case SMB_QUERY_FILE_UNIX_BASIC:
3512 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3513 0 : SSVAL(pdata,10,0); /* padding. */
3514 0 : store_file_unix_basic(conn, pdata + 12, fsp,
3515 0 : &smb_fname->st);
3516 0 : break;
3517 0 : case SMB_QUERY_FILE_UNIX_INFO2:
3518 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3519 0 : SSVAL(pdata,10,0); /* padding. */
3520 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
3521 0 : &smb_fname->st);
3522 0 : break;
3523 114 : default:
3524 114 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3525 114 : SSVAL(pdata,10,0); /* padding. */
3526 114 : break;
3527 : }
3528 114 : return NT_STATUS_OK;
3529 : }
3530 :
3531 : /****************************************************************************
3532 : Delete a file with POSIX semantics.
3533 : ****************************************************************************/
3534 :
3535 : struct smb_posix_unlink_state {
3536 : struct smb_filename *smb_fname;
3537 : struct files_struct *fsp;
3538 : NTSTATUS status;
3539 : };
3540 :
3541 248 : static void smb_posix_unlink_locked(struct share_mode_lock *lck,
3542 : void *private_data)
3543 : {
3544 248 : struct smb_posix_unlink_state *state = private_data;
3545 248 : char del = 1;
3546 0 : bool other_nonposix_opens;
3547 :
3548 248 : other_nonposix_opens = has_other_nonposix_opens(lck, state->fsp);
3549 248 : if (other_nonposix_opens) {
3550 : /* Fail with sharing violation. */
3551 8 : state->status = NT_STATUS_SHARING_VIOLATION;
3552 8 : return;
3553 : }
3554 :
3555 : /*
3556 : * Set the delete on close.
3557 : */
3558 240 : state->status = smb_set_file_disposition_info(state->fsp->conn,
3559 : &del,
3560 : 1,
3561 240 : state->fsp,
3562 : state->smb_fname);
3563 : }
3564 :
3565 532 : static NTSTATUS smb_posix_unlink(connection_struct *conn,
3566 : struct smb_request *req,
3567 : const char *pdata,
3568 : int total_data,
3569 : struct files_struct *dirfsp,
3570 : struct smb_filename *smb_fname)
3571 : {
3572 532 : struct smb_posix_unlink_state state = {};
3573 532 : NTSTATUS status = NT_STATUS_OK;
3574 532 : files_struct *fsp = NULL;
3575 532 : uint16_t flags = 0;
3576 532 : int info = 0;
3577 532 : int create_options = FILE_OPEN_REPARSE_POINT;
3578 532 : struct smb2_create_blobs *posx = NULL;
3579 :
3580 532 : if (!CAN_WRITE(conn)) {
3581 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3582 : }
3583 :
3584 532 : if (total_data < 2) {
3585 0 : return NT_STATUS_INVALID_PARAMETER;
3586 : }
3587 :
3588 532 : flags = SVAL(pdata,0);
3589 :
3590 532 : if (!VALID_STAT(smb_fname->st)) {
3591 276 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3592 : }
3593 :
3594 256 : if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
3595 40 : !VALID_STAT_OF_DIR(smb_fname->st)) {
3596 0 : return NT_STATUS_NOT_A_DIRECTORY;
3597 : }
3598 :
3599 256 : DEBUG(10,("smb_posix_unlink: %s %s\n",
3600 : (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
3601 : smb_fname_str_dbg(smb_fname)));
3602 :
3603 256 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
3604 44 : create_options |= FILE_DIRECTORY_FILE;
3605 : }
3606 :
3607 256 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
3608 256 : if (!NT_STATUS_IS_OK(status)) {
3609 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3610 : nt_errstr(status));
3611 0 : return status;
3612 : }
3613 :
3614 256 : status = SMB_VFS_CREATE_FILE(
3615 : conn, /* conn */
3616 : req, /* req */
3617 : dirfsp, /* dirfsp */
3618 : smb_fname, /* fname */
3619 : DELETE_ACCESS, /* access_mask */
3620 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3621 : FILE_SHARE_DELETE),
3622 : FILE_OPEN, /* create_disposition*/
3623 : create_options, /* create_options */
3624 : 0, /* file_attributes */
3625 : 0, /* oplock_request */
3626 : NULL, /* lease */
3627 : 0, /* allocation_size */
3628 : 0, /* private_flags */
3629 : NULL, /* sd */
3630 : NULL, /* ea_list */
3631 : &fsp, /* result */
3632 : &info, /* pinfo */
3633 : posx, /* in_context_blobs */
3634 : NULL); /* out_context_blobs */
3635 :
3636 256 : TALLOC_FREE(posx);
3637 :
3638 256 : if (!NT_STATUS_IS_OK(status)) {
3639 8 : return status;
3640 : }
3641 :
3642 : /*
3643 : * Don't lie to client. If we can't really delete due to
3644 : * non-POSIX opens return SHARING_VIOLATION.
3645 : */
3646 :
3647 248 : state = (struct smb_posix_unlink_state) {
3648 : .smb_fname = smb_fname,
3649 : .fsp = fsp,
3650 : };
3651 :
3652 248 : status = share_mode_do_locked_vfs_allowed(fsp->file_id,
3653 : smb_posix_unlink_locked,
3654 : &state);
3655 248 : if (!NT_STATUS_IS_OK(status)) {
3656 0 : DBG_ERR("share_mode_do_locked_vfs_allowed(%s) failed - %s\n",
3657 : fsp_str_dbg(fsp), nt_errstr(status));
3658 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
3659 0 : return NT_STATUS_INVALID_PARAMETER;
3660 : }
3661 :
3662 248 : status = state.status;
3663 248 : if (!NT_STATUS_IS_OK(status)) {
3664 8 : close_file_free(req, &fsp, NORMAL_CLOSE);
3665 8 : return status;
3666 : }
3667 240 : return close_file_free(req, &fsp, NORMAL_CLOSE);
3668 : }
3669 :
3670 : /****************************************************************************
3671 : Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
3672 : ****************************************************************************/
3673 :
3674 128 : static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
3675 : struct smb_request *req,
3676 : const char *pdata,
3677 : int total_data,
3678 : struct files_struct *dirfsp,
3679 : struct smb_filename *new_smb_fname)
3680 : {
3681 128 : char *link_target = NULL;
3682 0 : struct smb_filename target_fname;
3683 128 : TALLOC_CTX *ctx = talloc_tos();
3684 128 : struct smb_filename new_smb_fname_rel = {};
3685 128 : char *slash = NULL;
3686 0 : NTSTATUS status;
3687 0 : int ret;
3688 :
3689 128 : if (!CAN_WRITE(conn)) {
3690 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3691 : }
3692 :
3693 : /* Set a symbolic link. */
3694 : /* Don't allow this if follow links is false. */
3695 :
3696 128 : if (total_data == 0) {
3697 0 : return NT_STATUS_INVALID_PARAMETER;
3698 : }
3699 :
3700 128 : if (!lp_follow_symlinks(SNUM(conn))) {
3701 0 : return NT_STATUS_ACCESS_DENIED;
3702 : }
3703 :
3704 128 : srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
3705 : total_data, STR_TERMINATE);
3706 :
3707 128 : if (!link_target) {
3708 0 : return NT_STATUS_INVALID_PARAMETER;
3709 : }
3710 :
3711 128 : target_fname = (struct smb_filename) {
3712 : .base_name = link_target,
3713 : };
3714 :
3715 : /* Removes @GMT tokens if any */
3716 128 : status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
3717 128 : if (!NT_STATUS_IS_OK(status)) {
3718 0 : return status;
3719 : }
3720 :
3721 128 : DBG_DEBUG("SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
3722 : new_smb_fname->base_name, link_target);
3723 :
3724 128 : new_smb_fname_rel = *new_smb_fname;
3725 128 : slash = strrchr_m(new_smb_fname_rel.base_name, '/');
3726 128 : if (slash != NULL) {
3727 6 : new_smb_fname_rel.base_name = slash + 1;
3728 : }
3729 :
3730 128 : ret = SMB_VFS_SYMLINKAT(conn,
3731 : &target_fname,
3732 : dirfsp,
3733 : &new_smb_fname_rel);
3734 128 : if (ret != 0) {
3735 8 : return map_nt_error_from_unix(errno);
3736 : }
3737 :
3738 120 : return NT_STATUS_OK;
3739 : }
3740 :
3741 : /****************************************************************************
3742 : Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
3743 : ****************************************************************************/
3744 :
3745 16 : static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
3746 : struct smb_request *req,
3747 : const char *pdata, int total_data,
3748 : struct smb_filename *smb_fname_new)
3749 : {
3750 16 : char *oldname = NULL;
3751 16 : struct files_struct *src_dirfsp = NULL;
3752 16 : struct smb_filename *smb_fname_old = NULL;
3753 16 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
3754 16 : NTTIME old_twrp = 0;
3755 16 : TALLOC_CTX *ctx = talloc_tos();
3756 16 : NTSTATUS status = NT_STATUS_OK;
3757 :
3758 16 : if (!CAN_WRITE(conn)) {
3759 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3760 : }
3761 :
3762 : /* Set a hard link. */
3763 16 : if (total_data == 0) {
3764 0 : return NT_STATUS_INVALID_PARAMETER;
3765 : }
3766 :
3767 16 : if (req->posix_pathnames) {
3768 16 : srvstr_get_path_posix(ctx,
3769 : pdata,
3770 16 : req->flags2,
3771 : &oldname,
3772 : pdata,
3773 : total_data,
3774 : STR_TERMINATE,
3775 : &status);
3776 : } else {
3777 0 : srvstr_get_path(ctx,
3778 : pdata,
3779 0 : req->flags2,
3780 : &oldname,
3781 : pdata,
3782 : total_data,
3783 : STR_TERMINATE,
3784 : &status);
3785 : }
3786 16 : if (!NT_STATUS_IS_OK(status)) {
3787 0 : return status;
3788 : }
3789 :
3790 16 : DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
3791 : smb_fname_str_dbg(smb_fname_new), oldname));
3792 :
3793 16 : if (ucf_flags & UCF_GMT_PATHNAME) {
3794 0 : extract_snapshot_token(oldname, &old_twrp);
3795 : }
3796 16 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &oldname);
3797 16 : if (!NT_STATUS_IS_OK(status)) {
3798 0 : return status;
3799 : }
3800 16 : status = filename_convert_dirfsp(ctx,
3801 : conn,
3802 : oldname,
3803 : ucf_flags,
3804 : old_twrp,
3805 : &src_dirfsp,
3806 : &smb_fname_old);
3807 16 : if (!NT_STATUS_IS_OK(status)) {
3808 0 : return status;
3809 : }
3810 :
3811 16 : return hardlink_internals(ctx,
3812 : conn,
3813 : req,
3814 : false,
3815 : smb_fname_old,
3816 : smb_fname_new);
3817 : }
3818 :
3819 : /****************************************************************************
3820 : Allow a UNIX info mknod.
3821 : ****************************************************************************/
3822 :
3823 2 : static NTSTATUS smb_unix_mknod(connection_struct *conn,
3824 : const char *pdata,
3825 : int total_data,
3826 : struct files_struct *dirfsp,
3827 : const struct smb_filename *smb_fname)
3828 : {
3829 2 : uint32_t file_type = IVAL(pdata,56);
3830 : #if defined(HAVE_MAKEDEV)
3831 2 : uint32_t dev_major = IVAL(pdata,60);
3832 2 : uint32_t dev_minor = IVAL(pdata,68);
3833 : #endif
3834 2 : SMB_DEV_T dev = (SMB_DEV_T)0;
3835 2 : uint32_t raw_unixmode = IVAL(pdata,84);
3836 0 : NTSTATUS status;
3837 0 : mode_t unixmode;
3838 0 : int ret;
3839 2 : struct smb_filename *parent_fname = NULL;
3840 2 : struct smb_filename *atname = NULL;
3841 :
3842 2 : if (total_data < 100) {
3843 0 : return NT_STATUS_INVALID_PARAMETER;
3844 : }
3845 :
3846 2 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3847 : PERM_NEW_FILE, &unixmode);
3848 2 : if (!NT_STATUS_IS_OK(status)) {
3849 0 : return status;
3850 : }
3851 :
3852 : #if defined(HAVE_MAKEDEV)
3853 2 : dev = makedev(dev_major, dev_minor);
3854 : #endif
3855 :
3856 2 : switch (file_type) {
3857 : /* We can't create other objects here. */
3858 0 : case UNIX_TYPE_FILE:
3859 : case UNIX_TYPE_DIR:
3860 : case UNIX_TYPE_SYMLINK:
3861 0 : return NT_STATUS_ACCESS_DENIED;
3862 : #if defined(S_IFIFO)
3863 1 : case UNIX_TYPE_FIFO:
3864 1 : unixmode |= S_IFIFO;
3865 1 : break;
3866 : #endif
3867 : #if defined(S_IFSOCK)
3868 1 : case UNIX_TYPE_SOCKET:
3869 1 : unixmode |= S_IFSOCK;
3870 1 : break;
3871 : #endif
3872 : #if defined(S_IFCHR)
3873 0 : case UNIX_TYPE_CHARDEV:
3874 : /* This is only allowed for root. */
3875 0 : if (get_current_uid(conn) != sec_initial_uid()) {
3876 0 : return NT_STATUS_ACCESS_DENIED;
3877 : }
3878 0 : unixmode |= S_IFCHR;
3879 0 : break;
3880 : #endif
3881 : #if defined(S_IFBLK)
3882 0 : case UNIX_TYPE_BLKDEV:
3883 0 : if (get_current_uid(conn) != sec_initial_uid()) {
3884 0 : return NT_STATUS_ACCESS_DENIED;
3885 : }
3886 0 : unixmode |= S_IFBLK;
3887 0 : break;
3888 : #endif
3889 0 : default:
3890 0 : return NT_STATUS_INVALID_PARAMETER;
3891 : }
3892 :
3893 2 : DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
3894 : "%.0f mode 0%o for file %s\n", (double)dev,
3895 : (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
3896 :
3897 2 : status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
3898 : talloc_tos(),
3899 : smb_fname,
3900 : &parent_fname,
3901 : &atname);
3902 2 : if (!NT_STATUS_IS_OK(status)) {
3903 0 : return status;
3904 : }
3905 :
3906 : /* Ok - do the mknod. */
3907 2 : ret = SMB_VFS_MKNODAT(conn,
3908 : dirfsp,
3909 : atname,
3910 : unixmode,
3911 : dev);
3912 :
3913 2 : if (ret != 0) {
3914 0 : TALLOC_FREE(parent_fname);
3915 0 : return map_nt_error_from_unix(errno);
3916 : }
3917 :
3918 : /* If any of the other "set" calls fail we
3919 : * don't want to end up with a half-constructed mknod.
3920 : */
3921 :
3922 2 : if (lp_inherit_permissions(SNUM(conn))) {
3923 0 : inherit_access_posix_acl(conn,
3924 : dirfsp,
3925 : smb_fname,
3926 : unixmode);
3927 : }
3928 2 : TALLOC_FREE(parent_fname);
3929 :
3930 2 : return NT_STATUS_OK;
3931 : }
3932 :
3933 : /****************************************************************************
3934 : Deal with SMB_SET_FILE_UNIX_BASIC.
3935 : ****************************************************************************/
3936 :
3937 172 : static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
3938 : struct smb_request *req,
3939 : const char *pdata,
3940 : int total_data,
3941 : struct files_struct *dirfsp,
3942 : files_struct *fsp,
3943 : struct smb_filename *smb_fname)
3944 : {
3945 0 : struct smb_file_time ft;
3946 0 : uint32_t raw_unixmode;
3947 0 : mode_t unixmode;
3948 172 : off_t size = 0;
3949 172 : uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
3950 172 : gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
3951 172 : NTSTATUS status = NT_STATUS_OK;
3952 0 : enum perm_type ptype;
3953 172 : files_struct *all_fsps = NULL;
3954 172 : bool modify_mtime = true;
3955 0 : struct file_id id;
3956 0 : SMB_STRUCT_STAT sbuf;
3957 :
3958 172 : if (!CAN_WRITE(conn)) {
3959 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
3960 : }
3961 :
3962 172 : init_smb_file_time(&ft);
3963 :
3964 172 : if (total_data < 100) {
3965 0 : return NT_STATUS_INVALID_PARAMETER;
3966 : }
3967 :
3968 172 : if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
3969 16 : IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
3970 16 : size=IVAL(pdata,0); /* first 8 Bytes are size */
3971 16 : size |= (((off_t)IVAL(pdata,4)) << 32);
3972 : }
3973 :
3974 172 : ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
3975 172 : ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
3976 172 : set_owner = (uid_t)IVAL(pdata,40);
3977 172 : set_grp = (gid_t)IVAL(pdata,48);
3978 172 : raw_unixmode = IVAL(pdata,84);
3979 :
3980 172 : if (VALID_STAT(smb_fname->st)) {
3981 170 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
3982 4 : ptype = PERM_EXISTING_DIR;
3983 : } else {
3984 166 : ptype = PERM_EXISTING_FILE;
3985 : }
3986 : } else {
3987 2 : ptype = PERM_NEW_FILE;
3988 : }
3989 :
3990 172 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3991 : ptype, &unixmode);
3992 172 : if (!NT_STATUS_IS_OK(status)) {
3993 0 : return status;
3994 : }
3995 :
3996 172 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
3997 : "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
3998 : smb_fname_str_dbg(smb_fname), (double)size,
3999 : (unsigned int)set_owner, (unsigned int)set_grp,
4000 : (int)raw_unixmode));
4001 :
4002 172 : sbuf = smb_fname->st;
4003 :
4004 172 : if (!VALID_STAT(sbuf)) {
4005 : /*
4006 : * The only valid use of this is to create character and block
4007 : * devices, and named pipes. This is deprecated (IMHO) and
4008 : * a new info level should be used for mknod. JRA.
4009 : */
4010 :
4011 2 : if (dirfsp == NULL) {
4012 0 : return NT_STATUS_INVALID_PARAMETER;
4013 : }
4014 :
4015 2 : return smb_unix_mknod(conn,
4016 : pdata,
4017 : total_data,
4018 : dirfsp,
4019 : smb_fname);
4020 : }
4021 :
4022 : #if 1
4023 : /* Horrible backwards compatibility hack as an old server bug
4024 : * allowed a CIFS client bug to remain unnoticed :-(. JRA.
4025 : * */
4026 :
4027 170 : if (!size) {
4028 170 : size = get_file_size_stat(&sbuf);
4029 : }
4030 : #endif
4031 :
4032 : /*
4033 : * Deal with the UNIX specific mode set.
4034 : */
4035 :
4036 170 : if (raw_unixmode != SMB_MODE_NO_CHANGE) {
4037 0 : int ret;
4038 :
4039 38 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4040 24 : DBG_WARNING("Can't set mode on symlink %s\n",
4041 : smb_fname_str_dbg(smb_fname));
4042 24 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4043 : }
4044 :
4045 14 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4046 : "setting mode 0%o for file %s\n",
4047 : (unsigned int)unixmode,
4048 : smb_fname_str_dbg(smb_fname)));
4049 14 : ret = SMB_VFS_FCHMOD(fsp, unixmode);
4050 14 : if (ret != 0) {
4051 2 : return map_nt_error_from_unix(errno);
4052 : }
4053 : }
4054 :
4055 : /*
4056 : * Deal with the UNIX specific uid set.
4057 : */
4058 :
4059 144 : if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
4060 0 : (sbuf.st_ex_uid != set_owner)) {
4061 0 : int ret;
4062 :
4063 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4064 : "changing owner %u for path %s\n",
4065 : (unsigned int)set_owner,
4066 : smb_fname_str_dbg(smb_fname)));
4067 :
4068 0 : if (fsp &&
4069 0 : !fsp->fsp_flags.is_pathref &&
4070 0 : fsp_get_io_fd(fsp) != -1)
4071 : {
4072 0 : ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
4073 : } else {
4074 : /*
4075 : * UNIX extensions calls must always operate
4076 : * on symlinks.
4077 : */
4078 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname,
4079 : set_owner, (gid_t)-1);
4080 : }
4081 :
4082 0 : if (ret != 0) {
4083 0 : status = map_nt_error_from_unix(errno);
4084 0 : return status;
4085 : }
4086 : }
4087 :
4088 : /*
4089 : * Deal with the UNIX specific gid set.
4090 : */
4091 :
4092 144 : if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
4093 0 : (sbuf.st_ex_gid != set_grp)) {
4094 0 : int ret;
4095 :
4096 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4097 : "changing group %u for file %s\n",
4098 : (unsigned int)set_grp,
4099 : smb_fname_str_dbg(smb_fname)));
4100 0 : if (fsp &&
4101 0 : !fsp->fsp_flags.is_pathref &&
4102 0 : fsp_get_io_fd(fsp) != -1)
4103 : {
4104 0 : ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
4105 : } else {
4106 : /*
4107 : * UNIX extensions calls must always operate
4108 : * on symlinks.
4109 : */
4110 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
4111 : set_grp);
4112 : }
4113 0 : if (ret != 0) {
4114 0 : status = map_nt_error_from_unix(errno);
4115 0 : return status;
4116 : }
4117 : }
4118 :
4119 : /* Deal with any size changes. */
4120 :
4121 144 : if (S_ISREG(sbuf.st_ex_mode)) {
4122 140 : status = smb_set_file_size(conn, req,
4123 : fsp,
4124 : smb_fname,
4125 : &sbuf,
4126 : size,
4127 : false);
4128 140 : if (!NT_STATUS_IS_OK(status)) {
4129 0 : return status;
4130 : }
4131 : }
4132 :
4133 : /* Deal with any time changes. */
4134 144 : if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
4135 : /* No change, don't cancel anything. */
4136 144 : return status;
4137 : }
4138 :
4139 0 : id = vfs_file_id_from_sbuf(conn, &sbuf);
4140 0 : for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
4141 0 : all_fsps = file_find_di_next(all_fsps, true)) {
4142 : /*
4143 : * We're setting the time explicitly for UNIX.
4144 : * Cancel any pending changes over all handles.
4145 : */
4146 0 : all_fsps->fsp_flags.update_write_time_on_close = false;
4147 0 : TALLOC_FREE(all_fsps->update_write_time_event);
4148 : }
4149 :
4150 : /*
4151 : * Override the "setting_write_time"
4152 : * parameter here as it almost does what
4153 : * we need. Just remember if we modified
4154 : * mtime and send the notify ourselves.
4155 : */
4156 0 : if (is_omit_timespec(&ft.mtime)) {
4157 0 : modify_mtime = false;
4158 : }
4159 :
4160 0 : status = smb_set_file_time(conn,
4161 : fsp,
4162 : smb_fname,
4163 : &ft,
4164 : false);
4165 0 : if (modify_mtime) {
4166 0 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
4167 0 : FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
4168 : }
4169 0 : return status;
4170 : }
4171 :
4172 : /****************************************************************************
4173 : Deal with SMB_SET_FILE_UNIX_INFO2.
4174 : ****************************************************************************/
4175 :
4176 140 : static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
4177 : struct smb_request *req,
4178 : const char *pdata,
4179 : int total_data,
4180 : struct files_struct *dirfsp,
4181 : files_struct *fsp,
4182 : struct smb_filename *smb_fname)
4183 : {
4184 0 : NTSTATUS status;
4185 0 : uint32_t smb_fflags;
4186 0 : uint32_t smb_fmask;
4187 :
4188 140 : if (!CAN_WRITE(conn)) {
4189 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
4190 : }
4191 :
4192 140 : if (total_data < 116) {
4193 0 : return NT_STATUS_INVALID_PARAMETER;
4194 : }
4195 :
4196 : /* Start by setting all the fields that are common between UNIX_BASIC
4197 : * and UNIX_INFO2.
4198 : */
4199 140 : status = smb_set_file_unix_basic(conn,
4200 : req,
4201 : pdata,
4202 : total_data,
4203 : dirfsp,
4204 : fsp,
4205 : smb_fname);
4206 140 : if (!NT_STATUS_IS_OK(status)) {
4207 8 : return status;
4208 : }
4209 :
4210 132 : smb_fflags = IVAL(pdata, 108);
4211 132 : smb_fmask = IVAL(pdata, 112);
4212 :
4213 : /* NB: We should only attempt to alter the file flags if the client
4214 : * sends a non-zero mask.
4215 : */
4216 132 : if (smb_fmask != 0) {
4217 128 : int stat_fflags = 0;
4218 :
4219 128 : if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
4220 : smb_fmask, &stat_fflags)) {
4221 : /* Client asked to alter a flag we don't understand. */
4222 128 : return NT_STATUS_INVALID_PARAMETER;
4223 : }
4224 :
4225 0 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4226 0 : DBG_WARNING("Can't change flags on symlink %s\n",
4227 : smb_fname_str_dbg(smb_fname));
4228 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4229 : }
4230 0 : if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
4231 0 : return map_nt_error_from_unix(errno);
4232 : }
4233 : }
4234 :
4235 : /* XXX: need to add support for changing the create_time here. You
4236 : * can do this for paths on Darwin with setattrlist(2). The right way
4237 : * to hook this up is probably by extending the VFS utimes interface.
4238 : */
4239 :
4240 4 : return NT_STATUS_OK;
4241 : }
4242 :
4243 : /****************************************************************************
4244 : Deal with SMB_SET_POSIX_ACL.
4245 : ****************************************************************************/
4246 :
4247 16 : static NTSTATUS smb_set_posix_acl(connection_struct *conn,
4248 : struct smb_request *req,
4249 : const char *pdata,
4250 : int total_data_in,
4251 : files_struct *fsp,
4252 : struct smb_filename *smb_fname)
4253 : {
4254 : #if !defined(HAVE_POSIX_ACLS)
4255 : return NT_STATUS_INVALID_LEVEL;
4256 : #else
4257 0 : uint16_t posix_acl_version;
4258 0 : uint16_t num_file_acls;
4259 0 : uint16_t num_def_acls;
4260 16 : bool valid_file_acls = true;
4261 16 : bool valid_def_acls = true;
4262 0 : NTSTATUS status;
4263 0 : unsigned int size_needed;
4264 0 : unsigned int total_data;
4265 16 : bool close_fsp = false;
4266 :
4267 16 : if (total_data_in < 0) {
4268 0 : status = NT_STATUS_INVALID_PARAMETER;
4269 0 : goto out;
4270 : }
4271 :
4272 16 : total_data = total_data_in;
4273 :
4274 16 : if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
4275 0 : status = NT_STATUS_INVALID_PARAMETER;
4276 0 : goto out;
4277 : }
4278 16 : posix_acl_version = SVAL(pdata,0);
4279 16 : num_file_acls = SVAL(pdata,2);
4280 16 : num_def_acls = SVAL(pdata,4);
4281 :
4282 16 : if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4283 4 : valid_file_acls = false;
4284 4 : num_file_acls = 0;
4285 : }
4286 :
4287 16 : if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4288 0 : valid_def_acls = false;
4289 0 : num_def_acls = 0;
4290 : }
4291 :
4292 16 : if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
4293 8 : status = NT_STATUS_INVALID_PARAMETER;
4294 8 : goto out;
4295 : }
4296 :
4297 : /* Wrap checks. */
4298 0 : if (num_file_acls + num_def_acls < num_file_acls) {
4299 : status = NT_STATUS_INVALID_PARAMETER;
4300 : goto out;
4301 : }
4302 :
4303 8 : size_needed = num_file_acls + num_def_acls;
4304 :
4305 : /*
4306 : * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
4307 : * than UINT_MAX, so check by division.
4308 : */
4309 8 : if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
4310 0 : status = NT_STATUS_INVALID_PARAMETER;
4311 0 : goto out;
4312 : }
4313 :
4314 8 : size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
4315 8 : if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
4316 0 : status = NT_STATUS_INVALID_PARAMETER;
4317 0 : goto out;
4318 : }
4319 8 : size_needed += SMB_POSIX_ACL_HEADER_SIZE;
4320 :
4321 8 : if (total_data < size_needed) {
4322 0 : status = NT_STATUS_INVALID_PARAMETER;
4323 0 : goto out;
4324 : }
4325 :
4326 : /*
4327 : * Ensure we always operate on a file descriptor, not just
4328 : * the filename.
4329 : */
4330 8 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
4331 8 : uint32_t access_mask = SEC_STD_WRITE_OWNER|
4332 : SEC_STD_WRITE_DAC|
4333 : SEC_STD_READ_CONTROL|
4334 : FILE_READ_ATTRIBUTES|
4335 : FILE_WRITE_ATTRIBUTES;
4336 :
4337 8 : status = get_posix_fsp(conn,
4338 : req,
4339 : smb_fname,
4340 : access_mask,
4341 : &fsp);
4342 :
4343 8 : if (!NT_STATUS_IS_OK(status)) {
4344 4 : goto out;
4345 : }
4346 4 : close_fsp = true;
4347 : }
4348 :
4349 : /* Here we know fsp != NULL */
4350 4 : SMB_ASSERT(fsp != NULL);
4351 :
4352 4 : status = refuse_symlink_fsp(fsp);
4353 4 : if (!NT_STATUS_IS_OK(status)) {
4354 0 : goto out;
4355 : }
4356 :
4357 : /* If we have a default acl, this *must* be a directory. */
4358 4 : if (valid_def_acls && !fsp->fsp_flags.is_directory) {
4359 0 : DBG_INFO("Can't set default acls on "
4360 : "non-directory %s\n",
4361 : fsp_str_dbg(fsp));
4362 0 : return NT_STATUS_INVALID_HANDLE;
4363 : }
4364 :
4365 4 : DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
4366 : "num_def_acls = %"PRIu16"\n",
4367 : fsp_str_dbg(fsp),
4368 : num_file_acls,
4369 : num_def_acls);
4370 :
4371 : /* Move pdata to the start of the file ACL entries. */
4372 4 : pdata += SMB_POSIX_ACL_HEADER_SIZE;
4373 :
4374 4 : if (valid_file_acls) {
4375 0 : status = set_unix_posix_acl(conn,
4376 : fsp,
4377 : num_file_acls,
4378 : pdata);
4379 0 : if (!NT_STATUS_IS_OK(status)) {
4380 0 : goto out;
4381 : }
4382 : }
4383 :
4384 : /* Move pdata to the start of the default ACL entries. */
4385 4 : pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
4386 :
4387 4 : if (valid_def_acls) {
4388 4 : status = set_unix_posix_default_acl(conn,
4389 : fsp,
4390 : num_def_acls,
4391 : pdata);
4392 4 : if (!NT_STATUS_IS_OK(status)) {
4393 0 : goto out;
4394 : }
4395 : }
4396 :
4397 4 : status = NT_STATUS_OK;
4398 :
4399 16 : out:
4400 :
4401 16 : if (close_fsp) {
4402 4 : (void)close_file_free(req, &fsp, NORMAL_CLOSE);
4403 : }
4404 16 : return status;
4405 : #endif
4406 : }
4407 :
4408 1410 : static void call_trans2setpathinfo(
4409 : connection_struct *conn,
4410 : struct smb_request *req,
4411 : char **pparams,
4412 : int total_params,
4413 : char **ppdata,
4414 : int total_data,
4415 : unsigned int max_data_bytes)
4416 : {
4417 12 : uint16_t info_level;
4418 1410 : struct smb_filename *smb_fname = NULL;
4419 1410 : struct files_struct *dirfsp = NULL;
4420 1410 : struct files_struct *fsp = NULL;
4421 1410 : char *params = *pparams;
4422 1410 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4423 1410 : NTTIME twrp = 0;
4424 1410 : char *fname = NULL;
4425 12 : bool info_level_handled;
4426 1410 : int data_return_size = 0;
4427 12 : NTSTATUS status;
4428 :
4429 1410 : if (params == NULL) {
4430 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4431 0 : return;
4432 : }
4433 :
4434 : /* set path info */
4435 1410 : if (total_params < 7) {
4436 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4437 0 : return;
4438 : }
4439 :
4440 1410 : info_level = SVAL(params,0);
4441 :
4442 1410 : if (INFO_LEVEL_IS_UNIX(info_level)) {
4443 1112 : if (!lp_smb1_unix_extensions()) {
4444 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4445 0 : return;
4446 : }
4447 1112 : if (!req->posix_pathnames) {
4448 6 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4449 6 : return;
4450 : }
4451 : }
4452 :
4453 1404 : if (req->posix_pathnames) {
4454 1210 : srvstr_get_path_posix(req,
4455 : params,
4456 1210 : req->flags2,
4457 : &fname,
4458 1210 : ¶ms[6],
4459 1210 : total_params - 6,
4460 : STR_TERMINATE,
4461 : &status);
4462 : } else {
4463 194 : srvstr_get_path(req,
4464 : params,
4465 194 : req->flags2,
4466 : &fname,
4467 194 : ¶ms[6],
4468 194 : total_params - 6,
4469 : STR_TERMINATE,
4470 : &status);
4471 : }
4472 1404 : if (!NT_STATUS_IS_OK(status)) {
4473 0 : reply_nterror(req, status);
4474 0 : return;
4475 : }
4476 :
4477 1404 : DBG_NOTICE("fname=%s info_level=%d totdata=%d\n",
4478 : fname,
4479 : info_level,
4480 : total_data);
4481 :
4482 1404 : if (ucf_flags & UCF_GMT_PATHNAME) {
4483 0 : extract_snapshot_token(fname, &twrp);
4484 : }
4485 1404 : status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
4486 1404 : if (!NT_STATUS_IS_OK(status)) {
4487 0 : reply_nterror(req, status);
4488 0 : return;
4489 : }
4490 1404 : status = filename_convert_dirfsp(req,
4491 : conn,
4492 : fname,
4493 : ucf_flags,
4494 : twrp,
4495 : &dirfsp,
4496 : &smb_fname);
4497 1404 : if (!NT_STATUS_IS_OK(status)) {
4498 60 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4499 0 : reply_botherror(req,
4500 : NT_STATUS_PATH_NOT_COVERED,
4501 : ERRSRV, ERRbadpath);
4502 0 : return;
4503 : }
4504 60 : reply_nterror(req, status);
4505 60 : return;
4506 : }
4507 :
4508 1344 : info_level_handled = true; /* Untouched in switch cases below */
4509 :
4510 1344 : switch (info_level) {
4511 :
4512 294 : default:
4513 294 : info_level_handled = false;
4514 294 : break;
4515 :
4516 174 : case SMB_POSIX_PATH_OPEN:
4517 174 : status = smb_posix_open(conn,
4518 : req,
4519 : ppdata,
4520 : total_data,
4521 : dirfsp,
4522 : smb_fname,
4523 : &data_return_size);
4524 174 : break;
4525 :
4526 532 : case SMB_POSIX_PATH_UNLINK:
4527 532 : status = smb_posix_unlink(conn,
4528 : req,
4529 : *ppdata,
4530 : total_data,
4531 : dirfsp,
4532 : smb_fname);
4533 532 : break;
4534 :
4535 128 : case SMB_SET_FILE_UNIX_LINK:
4536 128 : status = smb_set_file_unix_link(
4537 : conn, req, *ppdata, total_data, dirfsp, smb_fname);
4538 128 : break;
4539 :
4540 16 : case SMB_SET_FILE_UNIX_HLINK:
4541 16 : status = smb_set_file_unix_hlink(
4542 : conn, req, *ppdata, total_data, smb_fname);
4543 16 : break;
4544 :
4545 32 : case SMB_SET_FILE_UNIX_BASIC:
4546 32 : status = smb_set_file_unix_basic(conn,
4547 : req,
4548 : *ppdata,
4549 : total_data,
4550 : dirfsp,
4551 32 : smb_fname->fsp,
4552 : smb_fname);
4553 32 : break;
4554 :
4555 140 : case SMB_SET_FILE_UNIX_INFO2:
4556 140 : status = smb_set_file_unix_info2(conn,
4557 : req,
4558 : *ppdata,
4559 : total_data,
4560 : dirfsp,
4561 140 : smb_fname->fsp,
4562 : smb_fname);
4563 140 : break;
4564 16 : case SMB_SET_POSIX_ACL:
4565 16 : status = smb_set_posix_acl(
4566 : conn, req, *ppdata, total_data, NULL, smb_fname);
4567 16 : break;
4568 : }
4569 :
4570 1332 : if (info_level_handled) {
4571 1038 : handle_trans2setfilepathinfo_result(
4572 : conn,
4573 : req,
4574 : info_level,
4575 : status,
4576 : *ppdata,
4577 : data_return_size,
4578 : max_data_bytes);
4579 1038 : return;
4580 : }
4581 :
4582 : /*
4583 : * smb_fname->fsp may be NULL if smb_fname points at a symlink
4584 : * and we're in POSIX context, so be careful when using fsp
4585 : * below, it can still be NULL.
4586 : */
4587 306 : fsp = smb_fname->fsp;
4588 :
4589 306 : status = smbd_do_setfilepathinfo(
4590 : conn,
4591 : req,
4592 : req,
4593 : info_level,
4594 : fsp,
4595 : smb_fname,
4596 : ppdata,
4597 : total_data,
4598 : &data_return_size);
4599 :
4600 306 : handle_trans2setfilepathinfo_result(
4601 : conn,
4602 : req,
4603 : info_level,
4604 : status,
4605 : *ppdata,
4606 : data_return_size,
4607 : max_data_bytes);
4608 : }
4609 :
4610 4265 : static void call_trans2setfileinfo(
4611 : connection_struct *conn,
4612 : struct smb_request *req,
4613 : char **pparams,
4614 : int total_params,
4615 : char **ppdata,
4616 : int total_data,
4617 : unsigned int max_data_bytes)
4618 : {
4619 4265 : char *pdata = *ppdata;
4620 537 : uint16_t info_level;
4621 4265 : struct smb_filename *smb_fname = NULL;
4622 4265 : struct files_struct *fsp = NULL;
4623 4265 : char *params = *pparams;
4624 4265 : int data_return_size = 0;
4625 537 : bool info_level_handled;
4626 537 : NTSTATUS status;
4627 537 : int ret;
4628 :
4629 4265 : if (params == NULL) {
4630 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4631 0 : return;
4632 : }
4633 4265 : if (total_params < 4) {
4634 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4635 0 : return;
4636 : }
4637 :
4638 4265 : fsp = file_fsp(req, SVAL(params,0));
4639 : /* Basic check for non-null fsp. */
4640 4265 : if (!check_fsp_open(conn, req, fsp)) {
4641 0 : return;
4642 : }
4643 4265 : info_level = SVAL(params,2);
4644 :
4645 4265 : if (INFO_LEVEL_IS_UNIX(info_level)) {
4646 36 : if (!lp_smb1_unix_extensions()) {
4647 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4648 0 : return;
4649 : }
4650 36 : if (!req->posix_pathnames) {
4651 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4652 0 : return;
4653 : }
4654 : }
4655 :
4656 4265 : smb_fname = fsp->fsp_name;
4657 :
4658 4265 : DBG_NOTICE("fnum=%s fname=%s info_level=%d totdata=%d\n",
4659 : fsp_fnum_dbg(fsp),
4660 : fsp_str_dbg(fsp),
4661 : info_level,
4662 : total_data);
4663 :
4664 4265 : if (fsp_get_pathref_fd(fsp) == -1) {
4665 : /*
4666 : * This is actually a SETFILEINFO on a directory
4667 : * handle (returned from an NT SMB). NT5.0 seems
4668 : * to do this call. JRA.
4669 : */
4670 0 : ret = vfs_stat(conn, smb_fname);
4671 0 : if (ret != 0) {
4672 0 : DBG_NOTICE("vfs_stat of %s failed (%s)\n",
4673 : smb_fname_str_dbg(smb_fname),
4674 : strerror(errno));
4675 0 : reply_nterror(req, map_nt_error_from_unix(errno));
4676 0 : return;
4677 : }
4678 4265 : } else if (fsp->print_file) {
4679 : /*
4680 : * Doing a DELETE_ON_CLOSE should cancel a print job.
4681 : */
4682 2 : if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) &&
4683 2 : CVAL(pdata,0)) {
4684 :
4685 2 : fsp->fsp_flags.delete_on_close = true;
4686 :
4687 2 : DBG_NOTICE("Cancelling print job (%s)\n",
4688 : fsp_str_dbg(fsp));
4689 :
4690 2 : SSVAL(params,0,0);
4691 2 : send_trans2_replies(
4692 : conn,
4693 : req,
4694 2 : NT_STATUS_OK,
4695 : params,
4696 : 2,
4697 : *ppdata, 0,
4698 : max_data_bytes);
4699 2 : return;
4700 : } else {
4701 0 : reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
4702 0 : return;
4703 : }
4704 : } else {
4705 : /*
4706 : * Original code - this is an open file.
4707 : */
4708 4263 : status = vfs_stat_fsp(fsp);
4709 4263 : if (!NT_STATUS_IS_OK(status)) {
4710 0 : DBG_NOTICE("fstat of %s failed (%s)\n",
4711 : fsp_fnum_dbg(fsp),
4712 : nt_errstr(status));
4713 0 : reply_nterror(req, status);
4714 0 : return;
4715 : }
4716 : }
4717 :
4718 4263 : info_level_handled = true; /* Untouched in switch cases below */
4719 :
4720 4263 : switch (info_level) {
4721 :
4722 3690 : default:
4723 3690 : info_level_handled = false;
4724 3690 : break;
4725 :
4726 0 : case SMB_SET_FILE_UNIX_BASIC:
4727 0 : status = smb_set_file_unix_basic(conn,
4728 : req,
4729 : pdata,
4730 : total_data,
4731 : NULL,
4732 : fsp,
4733 : smb_fname);
4734 0 : break;
4735 :
4736 0 : case SMB_SET_FILE_UNIX_INFO2:
4737 0 : status = smb_set_file_unix_info2(conn,
4738 : req,
4739 : pdata,
4740 : total_data,
4741 : NULL,
4742 : fsp,
4743 : smb_fname);
4744 0 : break;
4745 :
4746 36 : case SMB_SET_POSIX_LOCK:
4747 36 : status = smb_set_posix_lock(
4748 : conn, req, *ppdata, total_data, fsp);
4749 36 : break;
4750 : }
4751 :
4752 3726 : if (info_level_handled) {
4753 36 : handle_trans2setfilepathinfo_result(
4754 : conn,
4755 : req,
4756 : info_level,
4757 : status,
4758 : *ppdata,
4759 : data_return_size,
4760 : max_data_bytes);
4761 36 : return;
4762 : }
4763 :
4764 4227 : status = smbd_do_setfilepathinfo(
4765 : conn,
4766 : req,
4767 : req,
4768 : info_level,
4769 : fsp,
4770 : smb_fname,
4771 : ppdata,
4772 : total_data,
4773 : &data_return_size);
4774 :
4775 4227 : handle_trans2setfilepathinfo_result(
4776 : conn,
4777 : req,
4778 : info_level,
4779 : status,
4780 : *ppdata,
4781 : data_return_size,
4782 : max_data_bytes);
4783 : }
4784 :
4785 : /****************************************************************************
4786 : Reply to a TRANS2_MKDIR (make directory with extended attributes).
4787 : ****************************************************************************/
4788 :
4789 23 : static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
4790 : char **pparams, int total_params,
4791 : char **ppdata, int total_data,
4792 : unsigned int max_data_bytes)
4793 : {
4794 23 : struct files_struct *dirfsp = NULL;
4795 23 : struct files_struct *fsp = NULL;
4796 23 : struct smb_filename *smb_dname = NULL;
4797 23 : char *params = *pparams;
4798 23 : char *pdata = *ppdata;
4799 23 : char *directory = NULL;
4800 23 : NTSTATUS status = NT_STATUS_OK;
4801 23 : struct ea_list *ea_list = NULL;
4802 23 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4803 23 : NTTIME twrp = 0;
4804 23 : TALLOC_CTX *ctx = talloc_tos();
4805 :
4806 23 : if (!CAN_WRITE(conn)) {
4807 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4808 0 : return;
4809 : }
4810 :
4811 23 : if (total_params < 5) {
4812 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4813 0 : return;
4814 : }
4815 :
4816 23 : if (req->posix_pathnames) {
4817 0 : srvstr_get_path_posix(ctx,
4818 : params,
4819 0 : req->flags2,
4820 : &directory,
4821 0 : ¶ms[4],
4822 0 : total_params - 4,
4823 : STR_TERMINATE,
4824 : &status);
4825 : } else {
4826 23 : srvstr_get_path(ctx,
4827 : params,
4828 23 : req->flags2,
4829 : &directory,
4830 23 : ¶ms[4],
4831 23 : total_params - 4,
4832 : STR_TERMINATE,
4833 : &status);
4834 : }
4835 23 : if (!NT_STATUS_IS_OK(status)) {
4836 0 : reply_nterror(req, status);
4837 0 : return;
4838 : }
4839 :
4840 23 : DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
4841 :
4842 23 : if (ucf_flags & UCF_GMT_PATHNAME) {
4843 0 : extract_snapshot_token(directory, &twrp);
4844 : }
4845 23 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &directory);
4846 23 : if (!NT_STATUS_IS_OK(status)) {
4847 0 : reply_nterror(req, status);
4848 0 : goto out;
4849 : }
4850 23 : status = filename_convert_dirfsp(ctx,
4851 : conn,
4852 : directory,
4853 : ucf_flags,
4854 : twrp,
4855 : &dirfsp,
4856 : &smb_dname);
4857 23 : if (!NT_STATUS_IS_OK(status)) {
4858 5 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4859 0 : reply_botherror(req,
4860 : NT_STATUS_PATH_NOT_COVERED,
4861 : ERRSRV, ERRbadpath);
4862 0 : return;
4863 : }
4864 5 : reply_nterror(req, status);
4865 5 : return;
4866 : }
4867 :
4868 : /*
4869 : * OS/2 workplace shell seems to send SET_EA requests of "null"
4870 : * length (4 bytes containing IVAL 4).
4871 : * They seem to have no effect. Bug #3212. JRA.
4872 : */
4873 :
4874 18 : if (total_data && (total_data != 4)) {
4875 : /* Any data in this call is an EA list. */
4876 5 : if (total_data < 10) {
4877 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4878 0 : goto out;
4879 : }
4880 :
4881 5 : if (IVAL(pdata,0) > total_data) {
4882 0 : DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
4883 : IVAL(pdata,0), (unsigned int)total_data));
4884 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4885 0 : goto out;
4886 : }
4887 :
4888 5 : ea_list = read_ea_list(talloc_tos(), pdata + 4,
4889 5 : total_data - 4);
4890 5 : if (!ea_list) {
4891 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4892 0 : goto out;
4893 : }
4894 :
4895 5 : if (!lp_ea_support(SNUM(conn))) {
4896 0 : reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
4897 0 : goto out;
4898 : }
4899 : }
4900 : /* If total_data == 4 Windows doesn't care what values
4901 : * are placed in that field, it just ignores them.
4902 : * The System i QNTC IBM SMB client puts bad values here,
4903 : * so ignore them. */
4904 :
4905 18 : status = SMB_VFS_CREATE_FILE(
4906 : conn, /* conn */
4907 : req, /* req */
4908 : dirfsp, /* dirfsp */
4909 : smb_dname, /* fname */
4910 : MAXIMUM_ALLOWED_ACCESS, /* access_mask */
4911 : FILE_SHARE_NONE, /* share_access */
4912 : FILE_CREATE, /* create_disposition*/
4913 : FILE_DIRECTORY_FILE, /* create_options */
4914 : FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
4915 : 0, /* oplock_request */
4916 : NULL, /* lease */
4917 : 0, /* allocation_size */
4918 : 0, /* private_flags */
4919 : NULL, /* sd */
4920 : NULL, /* ea_list */
4921 : &fsp, /* result */
4922 : NULL, /* pinfo */
4923 : NULL, NULL); /* create context */
4924 18 : if (!NT_STATUS_IS_OK(status)) {
4925 8 : reply_nterror(req, status);
4926 8 : goto out;
4927 : }
4928 :
4929 : /* Try and set any given EA. */
4930 10 : if (ea_list) {
4931 5 : status = set_ea(conn, fsp, ea_list);
4932 5 : if (!NT_STATUS_IS_OK(status)) {
4933 0 : reply_nterror(req, status);
4934 0 : goto out;
4935 : }
4936 : }
4937 :
4938 : /* Realloc the parameter and data sizes */
4939 10 : *pparams = (char *)SMB_REALLOC(*pparams,2);
4940 10 : if(*pparams == NULL) {
4941 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4942 0 : goto out;
4943 : }
4944 10 : params = *pparams;
4945 :
4946 10 : SSVAL(params,0,0);
4947 :
4948 10 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
4949 :
4950 18 : out:
4951 18 : if (fsp != NULL) {
4952 10 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
4953 : }
4954 18 : TALLOC_FREE(smb_dname);
4955 : }
4956 :
4957 : /****************************************************************************
4958 : Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
4959 : We don't actually do this - we just send a null response.
4960 : ****************************************************************************/
4961 :
4962 0 : static void call_trans2findnotifyfirst(connection_struct *conn,
4963 : struct smb_request *req,
4964 : char **pparams, int total_params,
4965 : char **ppdata, int total_data,
4966 : unsigned int max_data_bytes)
4967 : {
4968 0 : char *params = *pparams;
4969 0 : uint16_t info_level;
4970 :
4971 0 : if (total_params < 6) {
4972 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4973 0 : return;
4974 : }
4975 :
4976 0 : info_level = SVAL(params,4);
4977 0 : DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
4978 :
4979 0 : switch (info_level) {
4980 0 : case 1:
4981 : case 2:
4982 0 : break;
4983 0 : default:
4984 0 : reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4985 0 : return;
4986 : }
4987 :
4988 : /* Realloc the parameter and data sizes */
4989 0 : *pparams = (char *)SMB_REALLOC(*pparams,6);
4990 0 : if (*pparams == NULL) {
4991 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4992 0 : return;
4993 : }
4994 0 : params = *pparams;
4995 :
4996 0 : SSVAL(params,0,fnf_handle);
4997 0 : SSVAL(params,2,0); /* No changes */
4998 0 : SSVAL(params,4,0); /* No EA errors */
4999 :
5000 0 : fnf_handle++;
5001 :
5002 0 : if(fnf_handle == 0)
5003 0 : fnf_handle = 257;
5004 :
5005 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
5006 : }
5007 :
5008 : /****************************************************************************
5009 : Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
5010 : changes). Currently this does nothing.
5011 : ****************************************************************************/
5012 :
5013 0 : static void call_trans2findnotifynext(connection_struct *conn,
5014 : struct smb_request *req,
5015 : char **pparams, int total_params,
5016 : char **ppdata, int total_data,
5017 : unsigned int max_data_bytes)
5018 : {
5019 0 : char *params = *pparams;
5020 :
5021 0 : DEBUG(3,("call_trans2findnotifynext\n"));
5022 :
5023 : /* Realloc the parameter and data sizes */
5024 0 : *pparams = (char *)SMB_REALLOC(*pparams,4);
5025 0 : if (*pparams == NULL) {
5026 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5027 0 : return;
5028 : }
5029 0 : params = *pparams;
5030 :
5031 0 : SSVAL(params,0,0); /* No changes */
5032 0 : SSVAL(params,2,0); /* No EA errors */
5033 :
5034 0 : send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
5035 : }
5036 :
5037 : /****************************************************************************
5038 : Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
5039 : ****************************************************************************/
5040 :
5041 4382 : static void call_trans2getdfsreferral(connection_struct *conn,
5042 : struct smb_request *req,
5043 : char **pparams, int total_params,
5044 : char **ppdata, int total_data,
5045 : unsigned int max_data_bytes)
5046 : {
5047 4382 : char *params = *pparams;
5048 4382 : char *pathname = NULL;
5049 4382 : int reply_size = 0;
5050 0 : int max_referral_level;
5051 4382 : NTSTATUS status = NT_STATUS_OK;
5052 4382 : TALLOC_CTX *ctx = talloc_tos();
5053 :
5054 4382 : DEBUG(10,("call_trans2getdfsreferral\n"));
5055 :
5056 4382 : if (!IS_IPC(conn)) {
5057 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5058 0 : return;
5059 : }
5060 :
5061 4382 : if (total_params < 3) {
5062 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5063 0 : return;
5064 : }
5065 :
5066 4382 : max_referral_level = SVAL(params,0);
5067 :
5068 4382 : if(!lp_host_msdfs()) {
5069 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5070 0 : return;
5071 : }
5072 :
5073 4382 : srvstr_pull_talloc(ctx, params, req->flags2, &pathname, ¶ms[2],
5074 : total_params - 2, STR_TERMINATE);
5075 4382 : if (!pathname) {
5076 0 : reply_nterror(req, NT_STATUS_NOT_FOUND);
5077 0 : return;
5078 : }
5079 4382 : reply_size = setup_dfs_referral(
5080 : conn, pathname, max_referral_level, ppdata, &status);
5081 4382 : if (reply_size < 0) {
5082 3072 : reply_nterror(req, status);
5083 3072 : return;
5084 : }
5085 :
5086 1310 : SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
5087 : SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
5088 1310 : send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
5089 : }
5090 :
5091 : #define LMCAT_SPL 0x53
5092 : #define LMFUNC_GETJOBID 0x60
5093 :
5094 : /****************************************************************************
5095 : Reply to a TRANS2_IOCTL - used for OS/2 printing.
5096 : ****************************************************************************/
5097 :
5098 0 : static void call_trans2ioctl(connection_struct *conn,
5099 : struct smb_request *req,
5100 : char **pparams, int total_params,
5101 : char **ppdata, int total_data,
5102 : unsigned int max_data_bytes)
5103 : {
5104 0 : const struct loadparm_substitution *lp_sub =
5105 0 : loadparm_s3_global_substitution();
5106 0 : char *pdata = *ppdata;
5107 0 : files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
5108 0 : NTSTATUS status;
5109 0 : size_t len = 0;
5110 :
5111 : /* check for an invalid fid before proceeding */
5112 :
5113 0 : if (!fsp) {
5114 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5115 0 : return;
5116 : }
5117 :
5118 0 : if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
5119 0 : && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5120 0 : *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
5121 0 : if (*ppdata == NULL) {
5122 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5123 0 : return;
5124 : }
5125 0 : pdata = *ppdata;
5126 :
5127 : /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
5128 : CAN ACCEPT THIS IN UNICODE. JRA. */
5129 :
5130 : /* Job number */
5131 0 : SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));
5132 :
5133 0 : status = srvstr_push(pdata, req->flags2, pdata + 2,
5134 : lp_netbios_name(), 15,
5135 : STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
5136 0 : if (!NT_STATUS_IS_OK(status)) {
5137 0 : reply_nterror(req, status);
5138 0 : return;
5139 : }
5140 0 : status = srvstr_push(pdata, req->flags2, pdata+18,
5141 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13,
5142 : STR_ASCII|STR_TERMINATE, &len); /* Service name */
5143 0 : if (!NT_STATUS_IS_OK(status)) {
5144 0 : reply_nterror(req, status);
5145 0 : return;
5146 : }
5147 0 : send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
5148 : max_data_bytes);
5149 0 : return;
5150 : }
5151 :
5152 0 : DEBUG(2,("Unknown TRANS2_IOCTL\n"));
5153 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5154 : }
5155 :
5156 37831 : static void handle_trans2(connection_struct *conn, struct smb_request *req,
5157 : struct trans_state *state)
5158 : {
5159 37831 : struct smbXsrv_connection *xconn = req->xconn;
5160 :
5161 37831 : if (xconn->protocol >= PROTOCOL_NT1) {
5162 37829 : req->flags2 |= 0x40; /* IS_LONG_NAME */
5163 37829 : SSVAL((discard_const_p(uint8_t, req->inbuf)),smb_flg2,req->flags2);
5164 : }
5165 :
5166 37831 : if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
5167 0 : if (state->call != TRANSACT2_QFSINFO &&
5168 0 : state->call != TRANSACT2_SETFSINFO) {
5169 0 : DEBUG(0,("handle_trans2: encryption required "
5170 : "with call 0x%x\n",
5171 : (unsigned int)state->call));
5172 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5173 0 : return;
5174 : }
5175 : }
5176 :
5177 : /* Now we must call the relevant TRANS2 function */
5178 37831 : switch(state->call) {
5179 98 : case TRANSACT2_OPEN:
5180 : {
5181 98 : START_PROFILE(Trans2_open);
5182 98 : call_trans2open(conn, req,
5183 98 : &state->param, state->total_param,
5184 98 : &state->data, state->total_data,
5185 : state->max_data_return);
5186 98 : END_PROFILE(Trans2_open);
5187 80 : break;
5188 : }
5189 :
5190 8740 : case TRANSACT2_FINDFIRST:
5191 : {
5192 8740 : START_PROFILE(Trans2_findfirst);
5193 8740 : call_trans2findfirst(conn, req,
5194 8740 : &state->param, state->total_param,
5195 8740 : &state->data, state->total_data,
5196 : state->max_data_return);
5197 8740 : END_PROFILE(Trans2_findfirst);
5198 8565 : break;
5199 : }
5200 :
5201 1724 : case TRANSACT2_FINDNEXT:
5202 : {
5203 1724 : START_PROFILE(Trans2_findnext);
5204 1724 : call_trans2findnext(conn, req,
5205 1724 : &state->param, state->total_param,
5206 1724 : &state->data, state->total_data,
5207 : state->max_data_return);
5208 1724 : END_PROFILE(Trans2_findnext);
5209 1724 : break;
5210 : }
5211 :
5212 1377 : case TRANSACT2_QFSINFO:
5213 : {
5214 1377 : START_PROFILE(Trans2_qfsinfo);
5215 1377 : call_trans2qfsinfo(conn, req,
5216 1377 : &state->param, state->total_param,
5217 1377 : &state->data, state->total_data,
5218 : state->max_data_return);
5219 1377 : END_PROFILE(Trans2_qfsinfo);
5220 1377 : break;
5221 : }
5222 :
5223 1370 : case TRANSACT2_SETFSINFO:
5224 : {
5225 1370 : START_PROFILE(Trans2_setfsinfo);
5226 1370 : call_trans2setfsinfo(conn, req,
5227 1370 : &state->param, state->total_param,
5228 1370 : &state->data, state->total_data,
5229 : state->max_data_return);
5230 1370 : END_PROFILE(Trans2_setfsinfo);
5231 1370 : break;
5232 : }
5233 :
5234 10825 : case TRANSACT2_QPATHINFO:
5235 : {
5236 10825 : START_PROFILE(Trans2_qpathinfo);
5237 10825 : call_trans2qpathinfo(
5238 : conn,
5239 : req,
5240 : &state->param,
5241 10825 : state->total_param,
5242 : &state->data,
5243 10825 : state->total_data,
5244 : state->max_data_return);
5245 10825 : END_PROFILE(Trans2_qpathinfo);
5246 10536 : break;
5247 : }
5248 :
5249 3617 : case TRANSACT2_QFILEINFO:
5250 : {
5251 3617 : START_PROFILE(Trans2_qfileinfo);
5252 3617 : call_trans2qfileinfo(
5253 : conn,
5254 : req,
5255 : &state->param,
5256 3617 : state->total_param,
5257 : &state->data,
5258 3617 : state->total_data,
5259 : state->max_data_return);
5260 3617 : END_PROFILE(Trans2_qfileinfo);
5261 3432 : break;
5262 : }
5263 :
5264 1410 : case TRANSACT2_SETPATHINFO:
5265 : {
5266 1410 : START_PROFILE(Trans2_setpathinfo);
5267 1410 : call_trans2setpathinfo(
5268 : conn,
5269 : req,
5270 : &state->param,
5271 1410 : state->total_param,
5272 : &state->data,
5273 1410 : state->total_data,
5274 : state->max_data_return);
5275 1410 : END_PROFILE(Trans2_setpathinfo);
5276 1398 : break;
5277 : }
5278 :
5279 4265 : case TRANSACT2_SETFILEINFO:
5280 : {
5281 4265 : START_PROFILE(Trans2_setfileinfo);
5282 4265 : call_trans2setfileinfo(
5283 : conn,
5284 : req,
5285 : &state->param,
5286 4265 : state->total_param,
5287 : &state->data,
5288 4265 : state->total_data,
5289 : state->max_data_return);
5290 4265 : END_PROFILE(Trans2_setfileinfo);
5291 3728 : break;
5292 : }
5293 :
5294 0 : case TRANSACT2_FINDNOTIFYFIRST:
5295 : {
5296 0 : START_PROFILE(Trans2_findnotifyfirst);
5297 0 : call_trans2findnotifyfirst(conn, req,
5298 0 : &state->param, state->total_param,
5299 0 : &state->data, state->total_data,
5300 : state->max_data_return);
5301 0 : END_PROFILE(Trans2_findnotifyfirst);
5302 0 : break;
5303 : }
5304 :
5305 0 : case TRANSACT2_FINDNOTIFYNEXT:
5306 : {
5307 0 : START_PROFILE(Trans2_findnotifynext);
5308 0 : call_trans2findnotifynext(conn, req,
5309 0 : &state->param, state->total_param,
5310 0 : &state->data, state->total_data,
5311 : state->max_data_return);
5312 0 : END_PROFILE(Trans2_findnotifynext);
5313 0 : break;
5314 : }
5315 :
5316 23 : case TRANSACT2_MKDIR:
5317 : {
5318 23 : START_PROFILE(Trans2_mkdir);
5319 23 : call_trans2mkdir(conn, req,
5320 23 : &state->param, state->total_param,
5321 23 : &state->data, state->total_data,
5322 : state->max_data_return);
5323 23 : END_PROFILE(Trans2_mkdir);
5324 20 : break;
5325 : }
5326 :
5327 4382 : case TRANSACT2_GET_DFS_REFERRAL:
5328 : {
5329 4382 : START_PROFILE(Trans2_get_dfs_referral);
5330 4382 : call_trans2getdfsreferral(conn, req,
5331 4382 : &state->param, state->total_param,
5332 4382 : &state->data, state->total_data,
5333 : state->max_data_return);
5334 4382 : END_PROFILE(Trans2_get_dfs_referral);
5335 4382 : break;
5336 : }
5337 :
5338 0 : case TRANSACT2_IOCTL:
5339 : {
5340 0 : START_PROFILE(Trans2_ioctl);
5341 0 : call_trans2ioctl(conn, req,
5342 0 : &state->param, state->total_param,
5343 0 : &state->data, state->total_data,
5344 : state->max_data_return);
5345 0 : END_PROFILE(Trans2_ioctl);
5346 0 : break;
5347 : }
5348 :
5349 0 : default:
5350 : /* Error in request */
5351 0 : DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
5352 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5353 : }
5354 : }
5355 :
5356 : /****************************************************************************
5357 : Reply to a SMBtrans2.
5358 : ****************************************************************************/
5359 :
5360 37831 : void reply_trans2(struct smb_request *req)
5361 : {
5362 37831 : connection_struct *conn = req->conn;
5363 1219 : unsigned int dsoff;
5364 1219 : unsigned int dscnt;
5365 1219 : unsigned int psoff;
5366 1219 : unsigned int pscnt;
5367 1219 : unsigned int tran_call;
5368 1219 : struct trans_state *state;
5369 1219 : NTSTATUS result;
5370 :
5371 37831 : START_PROFILE(SMBtrans2);
5372 :
5373 37831 : if (req->wct < 14) {
5374 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5375 0 : END_PROFILE(SMBtrans2);
5376 0 : return;
5377 : }
5378 :
5379 37831 : dsoff = SVAL(req->vwv+12, 0);
5380 37831 : dscnt = SVAL(req->vwv+11, 0);
5381 37831 : psoff = SVAL(req->vwv+10, 0);
5382 37831 : pscnt = SVAL(req->vwv+9, 0);
5383 37831 : tran_call = SVAL(req->vwv+14, 0);
5384 :
5385 37831 : result = allow_new_trans(conn->pending_trans, req->mid);
5386 37831 : if (!NT_STATUS_IS_OK(result)) {
5387 0 : DEBUG(2, ("Got invalid trans2 request: %s\n",
5388 : nt_errstr(result)));
5389 0 : reply_nterror(req, result);
5390 0 : END_PROFILE(SMBtrans2);
5391 0 : return;
5392 : }
5393 :
5394 37831 : if (IS_IPC(conn)) {
5395 5108 : switch (tran_call) {
5396 : /* List the allowed trans2 calls on IPC$ */
5397 5108 : case TRANSACT2_OPEN:
5398 : case TRANSACT2_GET_DFS_REFERRAL:
5399 : case TRANSACT2_QFILEINFO:
5400 : case TRANSACT2_QFSINFO:
5401 : case TRANSACT2_SETFSINFO:
5402 5108 : break;
5403 0 : default:
5404 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5405 0 : END_PROFILE(SMBtrans2);
5406 0 : return;
5407 : }
5408 : }
5409 :
5410 37831 : if ((state = talloc(conn, struct trans_state)) == NULL) {
5411 0 : DEBUG(0, ("talloc failed\n"));
5412 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5413 0 : END_PROFILE(SMBtrans2);
5414 0 : return;
5415 : }
5416 :
5417 37831 : state->cmd = SMBtrans2;
5418 :
5419 37831 : state->mid = req->mid;
5420 37831 : state->vuid = req->vuid;
5421 37831 : state->setup_count = SVAL(req->vwv+13, 0);
5422 37831 : state->setup = NULL;
5423 37831 : state->total_param = SVAL(req->vwv+0, 0);
5424 37831 : state->param = NULL;
5425 37831 : state->total_data = SVAL(req->vwv+1, 0);
5426 37831 : state->data = NULL;
5427 37831 : state->max_param_return = SVAL(req->vwv+2, 0);
5428 37831 : state->max_data_return = SVAL(req->vwv+3, 0);
5429 37831 : state->max_setup_return = SVAL(req->vwv+4, 0);
5430 37831 : state->close_on_completion = BITSETW(req->vwv+5, 0);
5431 37831 : state->one_way = BITSETW(req->vwv+5, 1);
5432 :
5433 37831 : state->call = tran_call;
5434 :
5435 : /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
5436 : is so as a sanity check */
5437 37831 : if (state->setup_count != 1) {
5438 : /*
5439 : * Need to have rc=0 for ioctl to get job id for OS/2.
5440 : * Network printing will fail if function is not successful.
5441 : * Similar function in reply.c will be used if protocol
5442 : * is LANMAN1.0 instead of LM1.2X002.
5443 : * Until DosPrintSetJobInfo with PRJINFO3 is supported,
5444 : * outbuf doesn't have to be set(only job id is used).
5445 : */
5446 0 : if ( (state->setup_count == 4)
5447 0 : && (tran_call == TRANSACT2_IOCTL)
5448 0 : && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
5449 0 : && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5450 0 : DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
5451 : } else {
5452 0 : DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
5453 0 : DEBUG(2,("Transaction is %d\n",tran_call));
5454 0 : TALLOC_FREE(state);
5455 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5456 0 : END_PROFILE(SMBtrans2);
5457 0 : return;
5458 : }
5459 : }
5460 :
5461 37831 : if ((dscnt > state->total_data) || (pscnt > state->total_param))
5462 0 : goto bad_param;
5463 :
5464 37831 : if (state->total_data) {
5465 :
5466 7330 : if (smb_buffer_oob(state->total_data, 0, dscnt)
5467 7330 : || smb_buffer_oob(smb_len(req->inbuf), dsoff, dscnt)) {
5468 0 : goto bad_param;
5469 : }
5470 :
5471 : /* Can't use talloc here, the core routines do realloc on the
5472 : * params and data. */
5473 7330 : state->data = (char *)SMB_MALLOC(state->total_data);
5474 7330 : if (state->data == NULL) {
5475 0 : DEBUG(0,("reply_trans2: data malloc fail for %u "
5476 : "bytes !\n", (unsigned int)state->total_data));
5477 0 : TALLOC_FREE(state);
5478 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5479 0 : END_PROFILE(SMBtrans2);
5480 0 : return;
5481 : }
5482 :
5483 7330 : memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
5484 : }
5485 :
5486 37831 : if (state->total_param) {
5487 :
5488 37831 : if (smb_buffer_oob(state->total_param, 0, pscnt)
5489 37831 : || smb_buffer_oob(smb_len(req->inbuf), psoff, pscnt)) {
5490 0 : goto bad_param;
5491 : }
5492 :
5493 : /* Can't use talloc here, the core routines do realloc on the
5494 : * params and data. */
5495 37831 : state->param = (char *)SMB_MALLOC(state->total_param);
5496 37831 : if (state->param == NULL) {
5497 0 : DEBUG(0,("reply_trans: param malloc fail for %u "
5498 : "bytes !\n", (unsigned int)state->total_param));
5499 0 : SAFE_FREE(state->data);
5500 0 : TALLOC_FREE(state);
5501 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5502 0 : END_PROFILE(SMBtrans2);
5503 0 : return;
5504 : }
5505 :
5506 37831 : memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
5507 : }
5508 :
5509 37831 : state->received_data = dscnt;
5510 37831 : state->received_param = pscnt;
5511 :
5512 37831 : if ((state->received_param == state->total_param) &&
5513 37831 : (state->received_data == state->total_data)) {
5514 :
5515 37831 : handle_trans2(conn, req, state);
5516 :
5517 37831 : SAFE_FREE(state->data);
5518 37831 : SAFE_FREE(state->param);
5519 37831 : TALLOC_FREE(state);
5520 37831 : END_PROFILE(SMBtrans2);
5521 37831 : return;
5522 : }
5523 :
5524 0 : DLIST_ADD(conn->pending_trans, state);
5525 :
5526 : /* We need to send an interim response then receive the rest
5527 : of the parameter/data bytes */
5528 0 : reply_smb1_outbuf(req, 0, 0);
5529 0 : show_msg((char *)req->outbuf);
5530 0 : END_PROFILE(SMBtrans2);
5531 0 : return;
5532 :
5533 0 : bad_param:
5534 :
5535 0 : DEBUG(0,("reply_trans2: invalid trans parameters\n"));
5536 0 : SAFE_FREE(state->data);
5537 0 : SAFE_FREE(state->param);
5538 0 : TALLOC_FREE(state);
5539 0 : END_PROFILE(SMBtrans2);
5540 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5541 : }
5542 :
5543 : /****************************************************************************
5544 : Reply to a SMBtranss2
5545 : ****************************************************************************/
5546 :
5547 0 : void reply_transs2(struct smb_request *req)
5548 : {
5549 0 : connection_struct *conn = req->conn;
5550 0 : unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
5551 0 : struct trans_state *state;
5552 :
5553 0 : START_PROFILE(SMBtranss2);
5554 :
5555 0 : show_msg((const char *)req->inbuf);
5556 :
5557 : /* Windows clients expect all replies to
5558 : a transact secondary (SMBtranss2 0x33)
5559 : to have a command code of transact
5560 : (SMBtrans2 0x32). See bug #8989
5561 : and also [MS-CIFS] section 2.2.4.47.2
5562 : for details.
5563 : */
5564 0 : req->cmd = SMBtrans2;
5565 :
5566 0 : if (req->wct < 8) {
5567 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5568 0 : END_PROFILE(SMBtranss2);
5569 0 : return;
5570 : }
5571 :
5572 0 : for (state = conn->pending_trans; state != NULL;
5573 0 : state = state->next) {
5574 0 : if (state->mid == req->mid) {
5575 0 : break;
5576 : }
5577 : }
5578 :
5579 0 : if ((state == NULL) || (state->cmd != SMBtrans2)) {
5580 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5581 0 : END_PROFILE(SMBtranss2);
5582 0 : return;
5583 : }
5584 :
5585 : /* Revise state->total_param and state->total_data in case they have
5586 : changed downwards */
5587 :
5588 0 : if (SVAL(req->vwv+0, 0) < state->total_param)
5589 0 : state->total_param = SVAL(req->vwv+0, 0);
5590 0 : if (SVAL(req->vwv+1, 0) < state->total_data)
5591 0 : state->total_data = SVAL(req->vwv+1, 0);
5592 :
5593 0 : pcnt = SVAL(req->vwv+2, 0);
5594 0 : poff = SVAL(req->vwv+3, 0);
5595 0 : pdisp = SVAL(req->vwv+4, 0);
5596 :
5597 0 : dcnt = SVAL(req->vwv+5, 0);
5598 0 : doff = SVAL(req->vwv+6, 0);
5599 0 : ddisp = SVAL(req->vwv+7, 0);
5600 :
5601 0 : state->received_param += pcnt;
5602 0 : state->received_data += dcnt;
5603 :
5604 0 : if ((state->received_data > state->total_data) ||
5605 0 : (state->received_param > state->total_param))
5606 0 : goto bad_param;
5607 :
5608 0 : if (pcnt) {
5609 0 : if (smb_buffer_oob(state->total_param, pdisp, pcnt)
5610 0 : || smb_buffer_oob(smb_len(req->inbuf), poff, pcnt)) {
5611 0 : goto bad_param;
5612 : }
5613 0 : memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
5614 : }
5615 :
5616 0 : if (dcnt) {
5617 0 : if (smb_buffer_oob(state->total_data, ddisp, dcnt)
5618 0 : || smb_buffer_oob(smb_len(req->inbuf), doff, dcnt)) {
5619 0 : goto bad_param;
5620 : }
5621 0 : memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
5622 : }
5623 :
5624 0 : if ((state->received_param < state->total_param) ||
5625 0 : (state->received_data < state->total_data)) {
5626 0 : END_PROFILE(SMBtranss2);
5627 0 : return;
5628 : }
5629 :
5630 0 : handle_trans2(conn, req, state);
5631 :
5632 0 : DLIST_REMOVE(conn->pending_trans, state);
5633 0 : SAFE_FREE(state->data);
5634 0 : SAFE_FREE(state->param);
5635 0 : TALLOC_FREE(state);
5636 :
5637 0 : END_PROFILE(SMBtranss2);
5638 0 : return;
5639 :
5640 0 : bad_param:
5641 :
5642 0 : DEBUG(0,("reply_transs2: invalid trans parameters\n"));
5643 0 : DLIST_REMOVE(conn->pending_trans, state);
5644 0 : SAFE_FREE(state->data);
5645 0 : SAFE_FREE(state->param);
5646 0 : TALLOC_FREE(state);
5647 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5648 0 : END_PROFILE(SMBtranss2);
5649 : }
|