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