Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Main SMB reply routines
4 : Copyright (C) Andrew Tridgell 1992-1998
5 : Copyright (C) Andrew Bartlett 2001
6 : Copyright (C) Jeremy Allison 1992-2007.
7 : Copyright (C) Volker Lendecke 2007
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 : /*
23 : This file handles most of the reply_ calls that the server
24 : makes to handle specific protocols
25 : */
26 :
27 : #include "includes.h"
28 : #include "libsmb/namequery.h"
29 : #include "system/filesys.h"
30 : #include "printing.h"
31 : #include "locking/share_mode_lock.h"
32 : #include "smbd/smbd.h"
33 : #include "smbd/globals.h"
34 : #include "smbd/smbXsrv_open.h"
35 : #include "fake_file.h"
36 : #include "rpc_client/rpc_client.h"
37 : #include "../librpc/gen_ndr/ndr_spoolss_c.h"
38 : #include "rpc_client/cli_spoolss.h"
39 : #include "rpc_client/init_spoolss.h"
40 : #include "rpc_server/rpc_ncacn_np.h"
41 : #include "libcli/security/security.h"
42 : #include "libsmb/nmblib.h"
43 : #include "auth.h"
44 : #include "smbprofile.h"
45 : #include "../lib/tsocket/tsocket.h"
46 : #include "lib/util/tevent_ntstatus.h"
47 : #include "libcli/smb/smb_signing.h"
48 : #include "lib/util/sys_rw_data.h"
49 : #include "librpc/gen_ndr/open_files.h"
50 : #include "libcli/smb/smb2_posix.h"
51 : #include "lib/util/string_wrappers.h"
52 : #include "source3/printing/rap_jobid.h"
53 : #include "source3/lib/substitute.h"
54 : #include "source3/smbd/dir.h"
55 :
56 : /****************************************************************************
57 : Check if we have a correct fsp pointing to a file. Basic check for open fsp.
58 : ****************************************************************************/
59 :
60 194352 : bool check_fsp_open(connection_struct *conn, struct smb_request *req,
61 : files_struct *fsp)
62 : {
63 194352 : if ((fsp == NULL) || (conn == NULL)) {
64 2720 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
65 2720 : return false;
66 : }
67 191632 : if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
68 39 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
69 39 : return false;
70 : }
71 190392 : return true;
72 : }
73 :
74 : /****************************************************************************
75 : SMB1 version of smb2_strip_dfs_path()
76 : Differs from SMB2 in that all Windows path separator '\' characters
77 : have already been converted to '/' by check_path_syntax().
78 : ****************************************************************************/
79 :
80 154959 : NTSTATUS smb1_strip_dfs_path(TALLOC_CTX *mem_ctx,
81 : uint32_t *_ucf_flags,
82 : char **in_path)
83 : {
84 154959 : uint32_t ucf_flags = *_ucf_flags;
85 154959 : char *path = *in_path;
86 154959 : char *return_path = NULL;
87 :
88 154959 : if (!(ucf_flags & UCF_DFS_PATHNAME)) {
89 153377 : return NT_STATUS_OK;
90 : }
91 :
92 : /* Strip any leading '/' characters - MacOSX client behavior. */
93 3096 : while (*path == '/') {
94 1514 : path++;
95 : }
96 :
97 : /* We should now be pointing at the server name. Go past it. */
98 0 : for (;;) {
99 28738 : if (*path == '\0') {
100 : /* End of complete path. Exit OK. */
101 46 : goto done;
102 : }
103 28692 : if (*path == '/') {
104 : /* End of server name. Go past and break. */
105 1536 : path++;
106 1536 : break;
107 : }
108 27156 : path++; /* Continue looking for end of server name or string. */
109 : }
110 :
111 : /* We should now be pointing at the share name. Go past it. */
112 0 : for (;;) {
113 18268 : if (*path == '\0') {
114 : /* End of complete path. Exit OK. */
115 34 : goto done;
116 : }
117 18234 : if (*path == '/') {
118 : /* End of share name. Go past and break. */
119 1502 : path++;
120 1502 : break;
121 : }
122 16732 : if (*path == ':') {
123 : /* Only invalid character in sharename. */
124 0 : return NT_STATUS_OBJECT_NAME_INVALID;
125 : }
126 16732 : path++; /* Continue looking for end of share name or string. */
127 : }
128 :
129 1582 : done:
130 : /* path now points at the start of the real filename (if any). */
131 : /* Duplicate it first. */
132 1582 : return_path = talloc_strdup(mem_ctx, path);
133 1582 : if (return_path == NULL) {
134 0 : return NT_STATUS_NO_MEMORY;
135 : }
136 :
137 : /* Now we can free the original (path points to part of this). */
138 1582 : TALLOC_FREE(*in_path);
139 :
140 1582 : *in_path = return_path;
141 1582 : ucf_flags &= ~UCF_DFS_PATHNAME;
142 1582 : *_ucf_flags = ucf_flags;
143 1582 : return NT_STATUS_OK;
144 : }
145 :
146 : /****************************************************************************
147 : Check if we have a correct fsp pointing to a file.
148 : ****************************************************************************/
149 :
150 148956 : bool check_fsp(connection_struct *conn, struct smb_request *req,
151 : files_struct *fsp)
152 : {
153 148956 : if (!check_fsp_open(conn, req, fsp)) {
154 96 : return false;
155 : }
156 148846 : if (fsp->fsp_flags.is_directory) {
157 6 : reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
158 6 : return false;
159 : }
160 148840 : if (fsp_get_pathref_fd(fsp) == -1) {
161 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
162 0 : return false;
163 : }
164 148840 : fsp->num_smb_operations++;
165 148840 : return true;
166 : }
167 :
168 : /****************************************************************************
169 : Reply to a tcon.
170 : conn POINTER CAN BE NULL HERE !
171 : ****************************************************************************/
172 :
173 2 : void reply_tcon(struct smb_request *req)
174 : {
175 2 : connection_struct *conn = req->conn;
176 0 : const char *service;
177 2 : char *service_buf = NULL;
178 2 : char *password = NULL;
179 2 : char *dev = NULL;
180 2 : int pwlen=0;
181 0 : NTSTATUS nt_status;
182 0 : const uint8_t *p;
183 0 : const char *p2;
184 2 : TALLOC_CTX *ctx = talloc_tos();
185 2 : struct smbXsrv_connection *xconn = req->xconn;
186 2 : NTTIME now = timeval_to_nttime(&req->request_time);
187 :
188 2 : START_PROFILE(SMBtcon);
189 :
190 2 : if (req->buflen < 4) {
191 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
192 0 : END_PROFILE(SMBtcon);
193 0 : return;
194 : }
195 :
196 2 : p = req->buf + 1;
197 2 : p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
198 2 : p += 1;
199 2 : pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
200 2 : p += pwlen+1;
201 2 : p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
202 2 : p += 1;
203 :
204 2 : if (service_buf == NULL || password == NULL || dev == NULL) {
205 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
206 0 : END_PROFILE(SMBtcon);
207 0 : return;
208 : }
209 2 : p2 = strrchr_m(service_buf,'\\');
210 2 : if (p2) {
211 0 : service = p2+1;
212 : } else {
213 2 : service = service_buf;
214 : }
215 :
216 2 : conn = make_connection(req, now, service, dev,
217 : req->vuid,&nt_status);
218 2 : req->conn = conn;
219 :
220 2 : if (!conn) {
221 2 : reply_nterror(req, nt_status);
222 2 : END_PROFILE(SMBtcon);
223 2 : return;
224 : }
225 :
226 0 : reply_smb1_outbuf(req, 2, 0);
227 0 : SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
228 0 : SSVAL(req->outbuf,smb_vwv1,conn->cnum);
229 0 : SSVAL(req->outbuf,smb_tid,conn->cnum);
230 :
231 0 : DEBUG(3,("tcon service=%s cnum=%d\n",
232 : service, conn->cnum));
233 :
234 0 : END_PROFILE(SMBtcon);
235 0 : return;
236 : }
237 :
238 : /****************************************************************************
239 : Reply to a tcon and X.
240 : conn POINTER CAN BE NULL HERE !
241 : ****************************************************************************/
242 :
243 9005 : void reply_tcon_and_X(struct smb_request *req)
244 : {
245 144 : const struct loadparm_substitution *lp_sub =
246 9005 : loadparm_s3_global_substitution();
247 9005 : connection_struct *conn = req->conn;
248 9005 : const char *service = NULL;
249 9005 : TALLOC_CTX *ctx = talloc_tos();
250 : /* what the client thinks the device is */
251 9005 : char *client_devicetype = NULL;
252 : /* what the server tells the client the share represents */
253 144 : const char *server_devicetype;
254 144 : NTSTATUS nt_status;
255 144 : int passlen;
256 9005 : char *path = NULL;
257 144 : const uint8_t *p;
258 144 : const char *q;
259 144 : uint16_t tcon_flags;
260 9005 : struct smbXsrv_session *session = NULL;
261 9005 : NTTIME now = timeval_to_nttime(&req->request_time);
262 9005 : bool session_key_updated = false;
263 9005 : uint16_t optional_support = 0;
264 9005 : struct smbXsrv_connection *xconn = req->xconn;
265 :
266 9005 : START_PROFILE(SMBtconX);
267 :
268 9005 : if (req->wct < 4) {
269 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
270 0 : END_PROFILE(SMBtconX);
271 0 : return;
272 : }
273 :
274 9005 : passlen = SVAL(req->vwv+3, 0);
275 9005 : tcon_flags = SVAL(req->vwv+2, 0);
276 :
277 : /* we might have to close an old one */
278 9005 : if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
279 0 : struct smbXsrv_tcon *tcon;
280 0 : NTSTATUS status;
281 :
282 0 : tcon = conn->tcon;
283 0 : req->conn = NULL;
284 0 : conn = NULL;
285 :
286 : /*
287 : * TODO: cancel all outstanding requests on the tcon
288 : */
289 0 : status = smbXsrv_tcon_disconnect(tcon, req->vuid);
290 0 : if (!NT_STATUS_IS_OK(status)) {
291 0 : DEBUG(0, ("reply_tcon_and_X: "
292 : "smbXsrv_tcon_disconnect() failed: %s\n",
293 : nt_errstr(status)));
294 : /*
295 : * If we hit this case, there is something completely
296 : * wrong, so we better disconnect the transport connection.
297 : */
298 0 : END_PROFILE(SMBtconX);
299 0 : exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
300 : return;
301 : }
302 :
303 0 : TALLOC_FREE(tcon);
304 : /*
305 : * This tree id is gone. Make sure we can't re-use it
306 : * by accident.
307 : */
308 0 : req->tid = 0;
309 : }
310 :
311 9005 : if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
312 0 : reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
313 0 : END_PROFILE(SMBtconX);
314 0 : return;
315 : }
316 :
317 9005 : if (xconn->smb1.negprot.encrypted_passwords) {
318 9005 : p = req->buf + passlen;
319 : } else {
320 0 : p = req->buf + passlen + 1;
321 : }
322 :
323 9005 : p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
324 :
325 9005 : if (path == NULL) {
326 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
327 0 : END_PROFILE(SMBtconX);
328 0 : return;
329 : }
330 :
331 : /*
332 : * the service name can be either: \\server\share
333 : * or share directly like on the DELL PowerVault 705
334 : */
335 9005 : if (*path=='\\') {
336 8844 : q = strchr_m(path+2,'\\');
337 8844 : if (!q) {
338 0 : reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
339 0 : END_PROFILE(SMBtconX);
340 0 : return;
341 : }
342 8844 : service = q+1;
343 : } else {
344 150 : service = path;
345 : }
346 :
347 9005 : p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
348 : &client_devicetype, p,
349 : MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
350 :
351 9005 : if (client_devicetype == NULL) {
352 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
353 0 : END_PROFILE(SMBtconX);
354 0 : return;
355 : }
356 :
357 9005 : DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
358 :
359 9005 : nt_status = smb1srv_session_lookup(xconn,
360 9005 : req->vuid, now, &session);
361 9005 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
362 0 : reply_force_doserror(req, ERRSRV, ERRbaduid);
363 0 : END_PROFILE(SMBtconX);
364 0 : return;
365 : }
366 9005 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
367 0 : reply_nterror(req, nt_status);
368 0 : END_PROFILE(SMBtconX);
369 0 : return;
370 : }
371 9005 : if (!NT_STATUS_IS_OK(nt_status)) {
372 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
373 0 : END_PROFILE(SMBtconX);
374 0 : return;
375 : }
376 :
377 9005 : if (session->global->auth_session_info == NULL) {
378 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
379 0 : END_PROFILE(SMBtconX);
380 0 : return;
381 : }
382 :
383 : /*
384 : * If there is no application key defined yet
385 : * we create one.
386 : *
387 : * This means we setup the application key on the
388 : * first tcon that happens via the given session.
389 : *
390 : * Once the application key is defined, it does not
391 : * change any more.
392 : */
393 14571 : if (session->global->application_key_blob.length == 0 &&
394 5566 : smb2_signing_key_valid(session->global->signing_key))
395 : {
396 5485 : struct smbXsrv_session *x = session;
397 5485 : struct auth_session_info *session_info =
398 5485 : session->global->auth_session_info;
399 133 : uint8_t session_key[16];
400 :
401 5485 : ZERO_STRUCT(session_key);
402 5485 : memcpy(session_key, x->global->signing_key->blob.data,
403 5485 : MIN(x->global->signing_key->blob.length, sizeof(session_key)));
404 :
405 : /*
406 : * The application key is truncated/padded to 16 bytes
407 : */
408 5485 : x->global->application_key_blob = data_blob_talloc(x->global,
409 : session_key,
410 : sizeof(session_key));
411 5485 : ZERO_STRUCT(session_key);
412 5485 : if (x->global->application_key_blob.data == NULL) {
413 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
414 0 : END_PROFILE(SMBtconX);
415 0 : return;
416 : }
417 5485 : talloc_keep_secret(x->global->application_key_blob.data);
418 :
419 5485 : if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
420 133 : NTSTATUS status;
421 :
422 5483 : status = smb1_key_derivation(x->global->application_key_blob.data,
423 5350 : x->global->application_key_blob.length,
424 5483 : x->global->application_key_blob.data);
425 5483 : if (!NT_STATUS_IS_OK(status)) {
426 0 : DBG_ERR("smb1_key_derivation failed: %s\n",
427 : nt_errstr(status));
428 0 : END_PROFILE(SMBtconX);
429 0 : return;
430 : }
431 5483 : optional_support |= SMB_EXTENDED_SIGNATURES;
432 : }
433 :
434 : /*
435 : * Place the application key into the session_info
436 : */
437 5485 : data_blob_clear_free(&session_info->session_key);
438 5485 : session_info->session_key = data_blob_dup_talloc(session_info,
439 : x->global->application_key_blob);
440 5485 : if (session_info->session_key.data == NULL) {
441 0 : data_blob_clear_free(&x->global->application_key_blob);
442 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
443 0 : END_PROFILE(SMBtconX);
444 0 : return;
445 : }
446 5485 : talloc_keep_secret(session_info->session_key.data);
447 5485 : session_key_updated = true;
448 : }
449 :
450 9005 : conn = make_connection(req, now, service, client_devicetype,
451 : req->vuid, &nt_status);
452 9005 : req->conn =conn;
453 :
454 9005 : if (!conn) {
455 66 : if (session_key_updated) {
456 4 : struct smbXsrv_session *x = session;
457 4 : struct auth_session_info *session_info =
458 4 : session->global->auth_session_info;
459 4 : data_blob_clear_free(&x->global->application_key_blob);
460 4 : data_blob_clear_free(&session_info->session_key);
461 : }
462 66 : reply_nterror(req, nt_status);
463 66 : END_PROFILE(SMBtconX);
464 66 : return;
465 : }
466 :
467 8939 : if ( IS_IPC(conn) )
468 3556 : server_devicetype = "IPC";
469 5373 : else if ( IS_PRINT(conn) )
470 2 : server_devicetype = "LPT1:";
471 : else
472 5371 : server_devicetype = "A:";
473 :
474 8939 : if (xconn->protocol < PROTOCOL_NT1) {
475 24 : reply_smb1_outbuf(req, 2, 0);
476 24 : if (message_push_string(&req->outbuf, server_devicetype,
477 : STR_TERMINATE|STR_ASCII) == -1) {
478 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
479 0 : END_PROFILE(SMBtconX);
480 0 : return;
481 : }
482 : } else {
483 : /* NT sets the fstype of IPC$ to the null string */
484 8915 : const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
485 :
486 8915 : if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
487 : /* Return permissions. */
488 8915 : uint32_t perm1 = 0;
489 8915 : uint32_t perm2 = 0;
490 :
491 8915 : reply_smb1_outbuf(req, 7, 0);
492 :
493 8915 : if (IS_IPC(conn)) {
494 3556 : perm1 = FILE_ALL_ACCESS;
495 3556 : perm2 = FILE_ALL_ACCESS;
496 : } else {
497 5349 : perm1 = conn->share_access;
498 : }
499 :
500 8915 : SIVAL(req->outbuf, smb_vwv3, perm1);
501 8915 : SIVAL(req->outbuf, smb_vwv5, perm2);
502 : } else {
503 0 : reply_smb1_outbuf(req, 3, 0);
504 : }
505 :
506 8915 : if ((message_push_string(&req->outbuf, server_devicetype,
507 : STR_TERMINATE|STR_ASCII) == -1)
508 8915 : || (message_push_string(&req->outbuf, fstype,
509 : STR_TERMINATE) == -1)) {
510 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
511 0 : END_PROFILE(SMBtconX);
512 0 : return;
513 : }
514 :
515 : /* what does setting this bit do? It is set by NT4 and
516 : may affect the ability to autorun mounted cdroms */
517 8915 : optional_support |= SMB_SUPPORT_SEARCH_BITS;
518 9053 : optional_support |=
519 8915 : (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
520 :
521 8915 : if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
522 76 : DEBUG(2,("Serving %s as a Dfs root\n",
523 : lp_servicename(ctx, lp_sub, SNUM(conn)) ));
524 76 : optional_support |= SMB_SHARE_IN_DFS;
525 : }
526 :
527 8915 : SSVAL(req->outbuf, smb_vwv2, optional_support);
528 : }
529 :
530 8939 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
531 8939 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
532 :
533 8939 : DEBUG(3,("tconX service=%s \n",
534 : service));
535 :
536 : /* set the incoming and outgoing tid to the just created one */
537 8939 : SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
538 8939 : SSVAL(req->outbuf,smb_tid,conn->cnum);
539 :
540 8939 : END_PROFILE(SMBtconX);
541 :
542 8939 : req->tid = conn->cnum;
543 : }
544 :
545 : /****************************************************************************
546 : Reply to an unknown type.
547 : ****************************************************************************/
548 :
549 0 : void reply_unknown_new(struct smb_request *req, uint8_t type)
550 : {
551 0 : DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
552 : smb_fn_name(type), type, type));
553 0 : reply_force_doserror(req, ERRSRV, ERRunknownsmb);
554 0 : return;
555 : }
556 :
557 : /****************************************************************************
558 : Reply to an ioctl.
559 : conn POINTER CAN BE NULL HERE !
560 : ****************************************************************************/
561 :
562 262152 : void reply_ioctl(struct smb_request *req)
563 : {
564 0 : const struct loadparm_substitution *lp_sub =
565 262152 : loadparm_s3_global_substitution();
566 262152 : connection_struct *conn = req->conn;
567 0 : uint16_t device;
568 0 : uint16_t function;
569 0 : uint32_t ioctl_code;
570 0 : int replysize;
571 0 : char *p;
572 :
573 262152 : START_PROFILE(SMBioctl);
574 :
575 262152 : if (req->wct < 3) {
576 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
577 0 : END_PROFILE(SMBioctl);
578 0 : return;
579 : }
580 :
581 262152 : device = SVAL(req->vwv+1, 0);
582 262152 : function = SVAL(req->vwv+2, 0);
583 262152 : ioctl_code = (device << 16) + function;
584 :
585 262152 : DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
586 :
587 262152 : switch (ioctl_code) {
588 8 : case IOCTL_QUERY_JOB_INFO:
589 8 : replysize = 32;
590 8 : break;
591 262144 : default:
592 262144 : reply_force_doserror(req, ERRSRV, ERRnosupport);
593 262144 : END_PROFILE(SMBioctl);
594 262144 : return;
595 : }
596 :
597 8 : reply_smb1_outbuf(req, 8, replysize+1);
598 8 : SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
599 8 : SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
600 8 : SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
601 8 : p = smb_buf(req->outbuf);
602 8 : memset(p, '\0', replysize+1); /* valgrind-safe. */
603 8 : p += 1; /* Allow for alignment */
604 :
605 8 : switch (ioctl_code) {
606 8 : case IOCTL_QUERY_JOB_INFO:
607 : {
608 0 : NTSTATUS status;
609 8 : size_t len = 0;
610 8 : files_struct *fsp = file_fsp(
611 8 : req, SVAL(req->vwv+0, 0));
612 8 : if (!fsp) {
613 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
614 0 : END_PROFILE(SMBioctl);
615 0 : return;
616 : }
617 : /* Job number */
618 8 : SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
619 :
620 8 : status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
621 : lp_netbios_name(), 15,
622 : STR_TERMINATE|STR_ASCII, &len);
623 8 : if (!NT_STATUS_IS_OK(status)) {
624 0 : reply_nterror(req, status);
625 0 : END_PROFILE(SMBioctl);
626 0 : return;
627 : }
628 8 : if (conn) {
629 8 : status = srvstr_push((char *)req->outbuf, req->flags2,
630 : p+18,
631 : lp_servicename(talloc_tos(),
632 : lp_sub,
633 : SNUM(conn)),
634 : 13, STR_TERMINATE|STR_ASCII, &len);
635 8 : if (!NT_STATUS_IS_OK(status)) {
636 0 : reply_nterror(req, status);
637 0 : END_PROFILE(SMBioctl);
638 0 : return;
639 : }
640 : } else {
641 0 : memset(p+18, 0, 13);
642 : }
643 8 : break;
644 : }
645 : }
646 :
647 8 : END_PROFILE(SMBioctl);
648 8 : return;
649 : }
650 :
651 : /****************************************************************************
652 : Strange checkpath NTSTATUS mapping.
653 : ****************************************************************************/
654 :
655 1074 : static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
656 : {
657 : /* Strange DOS error code semantics only for checkpath... */
658 1074 : if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
659 32 : if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
660 : /* We need to map to ERRbadpath */
661 20 : return NT_STATUS_OBJECT_PATH_NOT_FOUND;
662 : }
663 : }
664 1054 : return status;
665 : }
666 :
667 : /****************************************************************************
668 : Reply to a checkpath.
669 : ****************************************************************************/
670 :
671 1087 : void reply_checkpath(struct smb_request *req)
672 : {
673 1087 : connection_struct *conn = req->conn;
674 1087 : struct smb_filename *smb_fname = NULL;
675 1087 : char *name = NULL;
676 5 : NTSTATUS status;
677 1087 : struct files_struct *dirfsp = NULL;
678 1087 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
679 1087 : NTTIME twrp = 0;
680 1087 : TALLOC_CTX *ctx = talloc_tos();
681 :
682 1087 : START_PROFILE(SMBcheckpath);
683 :
684 1087 : srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
685 : STR_TERMINATE, &status);
686 :
687 1087 : if (!NT_STATUS_IS_OK(status)) {
688 24 : status = map_checkpath_error(req->flags2, status);
689 24 : reply_nterror(req, status);
690 24 : END_PROFILE(SMBcheckpath);
691 24 : return;
692 : }
693 :
694 1063 : DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
695 :
696 1063 : if (ucf_flags & UCF_GMT_PATHNAME) {
697 2 : extract_snapshot_token(name, &twrp);
698 : }
699 1063 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &name);
700 1063 : if (!NT_STATUS_IS_OK(status)) {
701 0 : reply_nterror(req, status);
702 0 : goto out;
703 : }
704 :
705 1063 : status = filename_convert_dirfsp(ctx,
706 : conn,
707 : name,
708 : ucf_flags,
709 : twrp,
710 : &dirfsp,
711 : &smb_fname);
712 1063 : if (!NT_STATUS_IS_OK(status)) {
713 37 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
714 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
715 : ERRSRV, ERRbadpath);
716 0 : END_PROFILE(SMBcheckpath);
717 0 : return;
718 : }
719 37 : goto path_err;
720 : }
721 :
722 1039 : if (!VALID_STAT(smb_fname->st) &&
723 13 : (SMB_VFS_STAT(conn, smb_fname) != 0)) {
724 13 : DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
725 : smb_fname_str_dbg(smb_fname), strerror(errno)));
726 13 : status = map_nt_error_from_unix(errno);
727 13 : goto path_err;
728 : }
729 :
730 1013 : if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
731 13 : reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
732 : ERRDOS, ERRbadpath);
733 13 : goto out;
734 : }
735 :
736 1000 : reply_smb1_outbuf(req, 0, 0);
737 :
738 1050 : path_err:
739 : /* We special case this - as when a Windows machine
740 : is parsing a path is steps through the components
741 : one at a time - if a component fails it expects
742 : ERRbadpath, not ERRbadfile.
743 : */
744 1050 : status = map_checkpath_error(req->flags2, status);
745 1050 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
746 : /*
747 : * Windows returns different error codes if
748 : * the parent directory is valid but not the
749 : * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
750 : * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
751 : * if the path is invalid.
752 : */
753 13 : reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
754 : ERRDOS, ERRbadpath);
755 13 : goto out;
756 : }
757 :
758 1037 : reply_nterror(req, status);
759 :
760 1063 : out:
761 1063 : TALLOC_FREE(smb_fname);
762 1063 : END_PROFILE(SMBcheckpath);
763 1058 : return;
764 : }
765 :
766 : /****************************************************************************
767 : Reply to a getatr.
768 : ****************************************************************************/
769 :
770 1412 : void reply_getatr(struct smb_request *req)
771 : {
772 1412 : struct smbXsrv_connection *xconn = req->xconn;
773 1412 : connection_struct *conn = req->conn;
774 1412 : struct smb_filename *smb_fname = NULL;
775 1412 : char *fname = NULL;
776 1412 : int mode=0;
777 1412 : off_t size=0;
778 1412 : time_t mtime=0;
779 48 : const char *p;
780 48 : NTSTATUS status;
781 1412 : TALLOC_CTX *ctx = talloc_tos();
782 :
783 1412 : START_PROFILE(SMBgetatr);
784 :
785 1412 : p = (const char *)req->buf + 1;
786 1412 : p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
787 1412 : if (!NT_STATUS_IS_OK(status)) {
788 24 : reply_nterror(req, status);
789 24 : goto out;
790 : }
791 :
792 : /*
793 : * dos sometimes asks for a stat of "" - it returns a "hidden
794 : * directory" under WfWg - weird!
795 : */
796 1388 : if (*fname == '\0') {
797 0 : mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
798 0 : if (!CAN_WRITE(conn)) {
799 0 : mode |= FILE_ATTRIBUTE_READONLY;
800 : }
801 0 : size = 0;
802 0 : mtime = 0;
803 : } else {
804 1388 : struct files_struct *dirfsp = NULL;
805 1388 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
806 1388 : NTTIME twrp = 0;
807 48 : bool ask_sharemode;
808 :
809 1388 : if (ucf_flags & UCF_GMT_PATHNAME) {
810 0 : extract_snapshot_token(fname, &twrp);
811 : }
812 1388 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
813 1388 : if (!NT_STATUS_IS_OK(status)) {
814 0 : reply_nterror(req, status);
815 96 : goto out;
816 : }
817 1388 : status = filename_convert_dirfsp(ctx,
818 : conn,
819 : fname,
820 : ucf_flags,
821 : twrp,
822 : &dirfsp,
823 : &smb_fname);
824 1388 : if (!NT_STATUS_IS_OK(status)) {
825 24 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
826 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
827 : ERRSRV, ERRbadpath);
828 0 : goto out;
829 : }
830 24 : reply_nterror(req, status);
831 24 : goto out;
832 : }
833 1436 : if (!VALID_STAT(smb_fname->st) &&
834 72 : (SMB_VFS_STAT(conn, smb_fname) != 0)) {
835 72 : DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
836 : smb_fname_str_dbg(smb_fname),
837 : strerror(errno)));
838 72 : reply_nterror(req, map_nt_error_from_unix(errno));
839 72 : goto out;
840 : }
841 :
842 1292 : mode = fdos_mode(smb_fname->fsp);
843 1292 : size = smb_fname->st.st_ex_size;
844 :
845 1292 : ask_sharemode = fsp_search_ask_sharemode(smb_fname->fsp);
846 1292 : if (ask_sharemode) {
847 40 : struct timespec write_time_ts;
848 40 : struct file_id fileid;
849 :
850 1292 : ZERO_STRUCT(write_time_ts);
851 1292 : fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
852 1292 : get_file_infos(fileid, 0, NULL, &write_time_ts);
853 1292 : if (!is_omit_timespec(&write_time_ts)) {
854 12 : update_stat_ex_mtime(&smb_fname->st, write_time_ts);
855 : }
856 : }
857 :
858 1292 : mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
859 1292 : if (mode & FILE_ATTRIBUTE_DIRECTORY) {
860 48 : size = 0;
861 : }
862 : }
863 :
864 1292 : reply_smb1_outbuf(req, 10, 0);
865 :
866 1292 : SSVAL(req->outbuf,smb_vwv0,mode);
867 1292 : if(lp_dos_filetime_resolution(SNUM(conn)) ) {
868 0 : srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
869 : } else {
870 1292 : srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
871 : }
872 1292 : SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
873 :
874 1292 : if (xconn->protocol >= PROTOCOL_NT1) {
875 1292 : SSVAL(req->outbuf, smb_flg2,
876 : SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
877 : }
878 :
879 1292 : DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
880 : smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
881 :
882 1412 : out:
883 1412 : TALLOC_FREE(smb_fname);
884 1412 : TALLOC_FREE(fname);
885 1412 : END_PROFILE(SMBgetatr);
886 1412 : return;
887 : }
888 :
889 : /****************************************************************************
890 : Reply to a setatr.
891 : ****************************************************************************/
892 :
893 2169 : void reply_setatr(struct smb_request *req)
894 : {
895 141 : struct smb_file_time ft;
896 2169 : connection_struct *conn = req->conn;
897 2169 : struct smb_filename *smb_fname = NULL;
898 2169 : struct files_struct *dirfsp = NULL;
899 2169 : char *fname = NULL;
900 141 : int mode;
901 141 : time_t mtime;
902 141 : const char *p;
903 141 : NTSTATUS status;
904 2169 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
905 2169 : NTTIME twrp = 0;
906 2169 : TALLOC_CTX *ctx = talloc_tos();
907 :
908 2169 : START_PROFILE(SMBsetatr);
909 2169 : init_smb_file_time(&ft);
910 :
911 2169 : if (req->wct < 2) {
912 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
913 0 : goto out;
914 : }
915 :
916 2169 : p = (const char *)req->buf + 1;
917 2169 : p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
918 2169 : if (!NT_STATUS_IS_OK(status)) {
919 155 : reply_nterror(req, status);
920 155 : goto out;
921 : }
922 :
923 2014 : if (ucf_flags & UCF_GMT_PATHNAME) {
924 0 : extract_snapshot_token(fname, &twrp);
925 : }
926 2014 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
927 2014 : if (!NT_STATUS_IS_OK(status)) {
928 0 : reply_nterror(req, status);
929 0 : goto out;
930 : }
931 2014 : status = filename_convert_dirfsp(ctx,
932 : conn,
933 : fname,
934 : ucf_flags,
935 : twrp,
936 : &dirfsp,
937 : &smb_fname);
938 2014 : if (!NT_STATUS_IS_OK(status)) {
939 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
940 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
941 : ERRSRV, ERRbadpath);
942 0 : goto out;
943 : }
944 0 : reply_nterror(req, status);
945 0 : goto out;
946 : }
947 :
948 2014 : if (ISDOT(smb_fname->base_name)) {
949 : /*
950 : * Not sure here is the right place to catch this
951 : * condition. Might be moved to somewhere else later -- vl
952 : */
953 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
954 0 : goto out;
955 : }
956 :
957 2014 : if (smb_fname->fsp == NULL) {
958 : /* Can't set access rights on a symlink. */
959 519 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
960 519 : goto out;
961 : }
962 :
963 1495 : mode = SVAL(req->vwv+0, 0);
964 1495 : mtime = srv_make_unix_date3(req->vwv+1);
965 :
966 1495 : if (mode != FILE_ATTRIBUTE_NORMAL) {
967 755 : if (VALID_STAT_OF_DIR(smb_fname->st))
968 34 : mode |= FILE_ATTRIBUTE_DIRECTORY;
969 : else
970 721 : mode &= ~FILE_ATTRIBUTE_DIRECTORY;
971 :
972 755 : status = smbd_check_access_rights_fsp(conn->cwd_fsp,
973 728 : smb_fname->fsp,
974 : false,
975 : FILE_WRITE_ATTRIBUTES);
976 755 : if (!NT_STATUS_IS_OK(status)) {
977 8 : reply_nterror(req, status);
978 8 : goto out;
979 : }
980 :
981 747 : if (file_set_dosmode(conn, smb_fname, mode, NULL,
982 : false) != 0) {
983 0 : reply_nterror(req, map_nt_error_from_unix(errno));
984 0 : goto out;
985 : }
986 : }
987 :
988 1487 : ft.mtime = time_t_to_full_timespec(mtime);
989 :
990 1487 : status = smb_set_file_time(conn, smb_fname->fsp, smb_fname, &ft, true);
991 1487 : if (!NT_STATUS_IS_OK(status)) {
992 0 : reply_nterror(req, status);
993 0 : goto out;
994 : }
995 :
996 1487 : reply_smb1_outbuf(req, 0, 0);
997 :
998 1487 : DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
999 : mode));
1000 2169 : out:
1001 2169 : TALLOC_FREE(smb_fname);
1002 2169 : END_PROFILE(SMBsetatr);
1003 2169 : return;
1004 : }
1005 :
1006 : /****************************************************************************
1007 : Reply to a dskattr.
1008 : ****************************************************************************/
1009 :
1010 0 : void reply_dskattr(struct smb_request *req)
1011 : {
1012 0 : struct smbXsrv_connection *xconn = req->xconn;
1013 0 : connection_struct *conn = req->conn;
1014 0 : uint64_t ret;
1015 0 : uint64_t dfree,dsize,bsize;
1016 0 : struct smb_filename smb_fname;
1017 0 : START_PROFILE(SMBdskattr);
1018 :
1019 0 : ZERO_STRUCT(smb_fname);
1020 0 : smb_fname.base_name = discard_const_p(char, ".");
1021 :
1022 0 : if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1023 0 : reply_nterror(req, map_nt_error_from_unix(errno));
1024 0 : DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1025 0 : END_PROFILE(SMBdskattr);
1026 0 : return;
1027 : }
1028 :
1029 0 : ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1030 0 : if (ret == (uint64_t)-1) {
1031 0 : reply_nterror(req, map_nt_error_from_unix(errno));
1032 0 : END_PROFILE(SMBdskattr);
1033 0 : return;
1034 : }
1035 :
1036 : /*
1037 : * Force max to fit in 16 bit fields.
1038 : */
1039 0 : while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1040 0 : dfree /= 2;
1041 0 : dsize /= 2;
1042 0 : bsize *= 2;
1043 0 : if (bsize > (WORDMAX*512)) {
1044 0 : bsize = (WORDMAX*512);
1045 0 : if (dsize > WORDMAX)
1046 0 : dsize = WORDMAX;
1047 0 : if (dfree > WORDMAX)
1048 0 : dfree = WORDMAX;
1049 0 : break;
1050 : }
1051 : }
1052 :
1053 0 : reply_smb1_outbuf(req, 5, 0);
1054 :
1055 0 : if (xconn->protocol <= PROTOCOL_LANMAN2) {
1056 0 : double total_space, free_space;
1057 : /* we need to scale this to a number that DOS6 can handle. We
1058 : use floating point so we can handle large drives on systems
1059 : that don't have 64 bit integers
1060 :
1061 : we end up displaying a maximum of 2G to DOS systems
1062 : */
1063 0 : total_space = dsize * (double)bsize;
1064 0 : free_space = dfree * (double)bsize;
1065 :
1066 0 : dsize = (uint64_t)((total_space+63*512) / (64*512));
1067 0 : dfree = (uint64_t)((free_space+63*512) / (64*512));
1068 :
1069 0 : if (dsize > 0xFFFF) dsize = 0xFFFF;
1070 0 : if (dfree > 0xFFFF) dfree = 0xFFFF;
1071 :
1072 0 : SSVAL(req->outbuf,smb_vwv0,dsize);
1073 0 : SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1074 0 : SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1075 0 : SSVAL(req->outbuf,smb_vwv3,dfree);
1076 : } else {
1077 0 : SSVAL(req->outbuf,smb_vwv0,dsize);
1078 0 : SSVAL(req->outbuf,smb_vwv1,bsize/512);
1079 0 : SSVAL(req->outbuf,smb_vwv2,512);
1080 0 : SSVAL(req->outbuf,smb_vwv3,dfree);
1081 : }
1082 :
1083 0 : DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1084 :
1085 0 : END_PROFILE(SMBdskattr);
1086 0 : return;
1087 : }
1088 :
1089 : /****************************************************************************
1090 : Make a dir struct.
1091 : ****************************************************************************/
1092 :
1093 20719 : static void make_dir_struct(TALLOC_CTX *ctx,
1094 : char *buf,
1095 : const char *mask,
1096 : const char *fname,
1097 : off_t size,
1098 : uint32_t mode,
1099 : time_t date,
1100 : bool uc)
1101 : {
1102 0 : char *p;
1103 :
1104 20719 : if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1105 8102 : size = 0;
1106 : }
1107 :
1108 20719 : memset(buf+1,' ',11);
1109 20719 : if ((p = strchr_m(mask, '.')) != NULL) {
1110 4578 : char name[p - mask + 1];
1111 4578 : strlcpy(name, mask, sizeof(name));
1112 4578 : push_ascii(buf + 1, name, 8, 0);
1113 4578 : push_ascii(buf+9,p+1,3, 0);
1114 : } else {
1115 16141 : push_ascii(buf + 1, mask, 11, 0);
1116 : }
1117 :
1118 20719 : memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1119 20719 : SCVAL(buf,21,mode);
1120 20719 : srv_put_dos_date(buf,22,date);
1121 20719 : SSVAL(buf,26,size & 0xFFFF);
1122 20719 : SSVAL(buf,28,(size >> 16)&0xFFFF);
1123 : /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1124 : Strange, but verified on W2K3. Needed for OS/2. JRA. */
1125 20719 : push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1126 20719 : DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1127 20719 : }
1128 :
1129 : /*******************************************************************
1130 : A wrapper that handles case sensitivity and the special handling
1131 : of the ".." name.
1132 : *******************************************************************/
1133 :
1134 25607 : static bool mask_match_search(const char *string,
1135 : const char *pattern,
1136 : bool is_case_sensitive)
1137 : {
1138 25607 : if (ISDOTDOT(string)) {
1139 494 : string = ".";
1140 : }
1141 25607 : if (ISDOT(pattern)) {
1142 0 : return False;
1143 : }
1144 :
1145 25607 : return ms_fnmatch(pattern, string, True, is_case_sensitive) == 0;
1146 : }
1147 :
1148 480 : static bool mangle_mask_match(connection_struct *conn,
1149 : const char *filename,
1150 : const char *mask)
1151 : {
1152 0 : char mname[13];
1153 :
1154 480 : if (!name_to_8_3(filename, mname, False, conn->params)) {
1155 0 : return False;
1156 : }
1157 480 : return mask_match_search(mname, mask, False);
1158 : }
1159 :
1160 : /****************************************************************************
1161 : Get an 8.3 directory entry.
1162 : ****************************************************************************/
1163 :
1164 29339 : static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1165 : void *private_data,
1166 : const char *dname,
1167 : const char *mask,
1168 : char **_fname)
1169 : {
1170 29339 : connection_struct *conn = (connection_struct *)private_data;
1171 :
1172 54466 : if ((strcmp(mask, "*.*") == 0) ||
1173 25607 : mask_match_search(dname, mask, false) ||
1174 480 : mangle_mask_match(conn, dname, mask)) {
1175 0 : char mname[13];
1176 0 : const char *fname;
1177 : /*
1178 : * Ensure we can push the original name as UCS2. If
1179 : * not, then just don't return this name.
1180 : */
1181 0 : NTSTATUS status;
1182 28859 : size_t ret_len = 0;
1183 28859 : size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1184 28859 : uint8_t *tmp = talloc_array(talloc_tos(), uint8_t, len);
1185 :
1186 28859 : status = srvstr_push(NULL,
1187 : FLAGS2_UNICODE_STRINGS,
1188 : tmp,
1189 : dname,
1190 : len,
1191 : STR_TERMINATE,
1192 : &ret_len);
1193 :
1194 28859 : TALLOC_FREE(tmp);
1195 :
1196 28859 : if (!NT_STATUS_IS_OK(status)) {
1197 0 : return false;
1198 : }
1199 :
1200 28859 : if (!mangle_is_8_3(dname, false, conn->params)) {
1201 0 : bool ok =
1202 80 : name_to_8_3(dname, mname, false, conn->params);
1203 80 : if (!ok) {
1204 0 : return false;
1205 : }
1206 80 : fname = mname;
1207 : } else {
1208 28779 : fname = dname;
1209 : }
1210 :
1211 28859 : *_fname = talloc_strdup(ctx, fname);
1212 28859 : if (*_fname == NULL) {
1213 0 : return false;
1214 : }
1215 :
1216 28859 : return true;
1217 : }
1218 :
1219 480 : return false;
1220 : }
1221 :
1222 20887 : static bool get_dir_entry(TALLOC_CTX *ctx,
1223 : connection_struct *conn,
1224 : struct dptr_struct *dirptr,
1225 : const char *mask,
1226 : uint32_t dirtype,
1227 : char **_fname,
1228 : off_t *_size,
1229 : uint32_t *_mode,
1230 : struct timespec *_date,
1231 : bool check_descend,
1232 : bool ask_sharemode)
1233 : {
1234 20887 : char *fname = NULL;
1235 20887 : struct smb_filename *smb_fname = NULL;
1236 20887 : uint32_t mode = 0;
1237 0 : bool ok;
1238 :
1239 20887 : again:
1240 20887 : ok = smbd_dirptr_get_entry(ctx,
1241 : dirptr,
1242 : mask,
1243 : dirtype,
1244 : check_descend,
1245 : ask_sharemode,
1246 : true,
1247 : smbd_dirptr_8_3_match_fn,
1248 : conn,
1249 : &fname,
1250 : &smb_fname,
1251 : &mode);
1252 20887 : if (!ok) {
1253 48 : return false;
1254 : }
1255 20839 : if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1256 : /* hide reparse points from ancient clients */
1257 0 : TALLOC_FREE(fname);
1258 0 : TALLOC_FREE(smb_fname);
1259 0 : goto again;
1260 : }
1261 :
1262 20839 : *_fname = talloc_move(ctx, &fname);
1263 20839 : *_size = smb_fname->st.st_ex_size;
1264 20839 : *_mode = mode;
1265 20839 : *_date = smb_fname->st.st_ex_mtime;
1266 20839 : TALLOC_FREE(smb_fname);
1267 20839 : return true;
1268 : }
1269 :
1270 : /****************************************************************************
1271 : Reply to a search.
1272 : Can be called from SMBsearch, SMBffirst or SMBfunique.
1273 : ****************************************************************************/
1274 :
1275 500 : void reply_search(struct smb_request *req)
1276 : {
1277 500 : connection_struct *conn = req->conn;
1278 500 : char *path = NULL;
1279 500 : char *mask = NULL;
1280 500 : char *directory = NULL;
1281 500 : struct smb_filename *smb_fname = NULL;
1282 500 : char *fname = NULL;
1283 0 : off_t size;
1284 0 : uint32_t mode;
1285 0 : struct timespec date;
1286 0 : uint32_t dirtype;
1287 500 : unsigned int numentries = 0;
1288 500 : unsigned int maxentries = 0;
1289 500 : bool finished = False;
1290 0 : const char *p;
1291 0 : int status_len;
1292 0 : char status[21];
1293 500 : int dptr_num= -1;
1294 500 : bool check_descend = False;
1295 500 : bool expect_close = False;
1296 0 : NTSTATUS nt_status;
1297 500 : bool mask_contains_wcard = False;
1298 500 : bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1299 500 : TALLOC_CTX *ctx = talloc_tos();
1300 500 : struct smbXsrv_connection *xconn = req->xconn;
1301 500 : struct smbd_server_connection *sconn = req->sconn;
1302 500 : files_struct *fsp = NULL;
1303 0 : const struct loadparm_substitution *lp_sub =
1304 500 : loadparm_s3_global_substitution();
1305 :
1306 500 : START_PROFILE(SMBsearch);
1307 :
1308 500 : if (req->wct < 2) {
1309 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1310 0 : goto out;
1311 : }
1312 :
1313 500 : if (req->posix_pathnames) {
1314 0 : reply_unknown_new(req, req->cmd);
1315 0 : goto out;
1316 : }
1317 :
1318 : /* If we were called as SMBffirst then we must expect close. */
1319 500 : if(req->cmd == SMBffirst) {
1320 12 : expect_close = True;
1321 : }
1322 :
1323 500 : reply_smb1_outbuf(req, 1, 3);
1324 500 : maxentries = SVAL(req->vwv+0, 0);
1325 500 : dirtype = SVAL(req->vwv+1, 0);
1326 500 : p = (const char *)req->buf + 1;
1327 500 : p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
1328 : &nt_status);
1329 500 : if (!NT_STATUS_IS_OK(nt_status)) {
1330 0 : reply_nterror(req, nt_status);
1331 0 : goto out;
1332 : }
1333 :
1334 500 : if (smbreq_bufrem(req, p) < 3) {
1335 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1336 0 : goto out;
1337 : }
1338 :
1339 500 : p++;
1340 500 : status_len = SVAL(p, 0);
1341 500 : p += 2;
1342 :
1343 : /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1344 :
1345 500 : if (status_len == 0) {
1346 0 : const char *dirpath;
1347 176 : struct files_struct *dirfsp = NULL;
1348 176 : struct smb_filename *smb_dname = NULL;
1349 176 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1350 :
1351 176 : nt_status = smb1_strip_dfs_path(ctx, &ucf_flags, &path);
1352 176 : if (!NT_STATUS_IS_OK(nt_status)) {
1353 0 : reply_nterror(req, nt_status);
1354 0 : goto out;
1355 : }
1356 :
1357 176 : nt_status = filename_convert_smb1_search_path(ctx,
1358 : conn,
1359 : path,
1360 : ucf_flags,
1361 : &dirfsp,
1362 : &smb_dname,
1363 : &mask);
1364 :
1365 176 : if (!NT_STATUS_IS_OK(nt_status)) {
1366 0 : if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1367 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1368 : ERRSRV, ERRbadpath);
1369 0 : goto out;
1370 : }
1371 0 : reply_nterror(req, nt_status);
1372 0 : goto out;
1373 : }
1374 :
1375 176 : memset((char *)status,'\0',21);
1376 176 : SCVAL(status,0,(dirtype & 0x1F));
1377 :
1378 : /*
1379 : * Open an fsp on this directory for the dptr.
1380 : */
1381 176 : nt_status = SMB_VFS_CREATE_FILE(
1382 : conn, /* conn */
1383 : req, /* req */
1384 : dirfsp, /* dirfsp */
1385 : smb_dname, /* dname */
1386 : FILE_LIST_DIRECTORY, /* access_mask */
1387 : FILE_SHARE_READ|
1388 : FILE_SHARE_WRITE, /* share_access */
1389 : FILE_OPEN, /* create_disposition*/
1390 : FILE_DIRECTORY_FILE, /* create_options */
1391 : FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
1392 : NO_OPLOCK, /* oplock_request */
1393 : NULL, /* lease */
1394 : 0, /* allocation_size */
1395 : 0, /* private_flags */
1396 : NULL, /* sd */
1397 : NULL, /* ea_list */
1398 : &fsp, /* result */
1399 : NULL, /* pinfo */
1400 : NULL, /* in_context */
1401 : NULL);/* out_context */
1402 :
1403 176 : if (!NT_STATUS_IS_OK(nt_status)) {
1404 0 : DBG_ERR("failed to open directory %s\n",
1405 : smb_fname_str_dbg(smb_dname));
1406 0 : reply_nterror(req, nt_status);
1407 0 : goto out;
1408 : }
1409 :
1410 176 : nt_status = dptr_create(conn,
1411 : NULL, /* req */
1412 : fsp, /* fsp */
1413 : True,
1414 : mask,
1415 : dirtype,
1416 176 : &fsp->dptr);
1417 :
1418 176 : TALLOC_FREE(smb_dname);
1419 :
1420 176 : if (!NT_STATUS_IS_OK(nt_status)) {
1421 : /*
1422 : * Use NULL here for the first parameter (req)
1423 : * as this is not a client visible handle so
1424 : * can't be part of an SMB1 chain.
1425 : */
1426 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1427 0 : reply_nterror(req, nt_status);
1428 0 : goto out;
1429 : }
1430 :
1431 176 : dptr_num = dptr_dnum(fsp->dptr);
1432 176 : dirpath = dptr_path(sconn, dptr_num);
1433 176 : directory = talloc_strdup(ctx, dirpath);
1434 176 : if (!directory) {
1435 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1436 0 : goto out;
1437 : }
1438 :
1439 : } else {
1440 0 : int status_dirtype;
1441 0 : const char *dirpath;
1442 0 : unsigned int dptr_filenum;
1443 0 : uint32_t resume_key_index;
1444 :
1445 324 : if (smbreq_bufrem(req, p) < 21) {
1446 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1447 0 : goto out;
1448 : }
1449 :
1450 324 : memcpy(status,p,21);
1451 324 : status_dirtype = CVAL(status,0) & 0x1F;
1452 324 : if (status_dirtype != (dirtype & 0x1F)) {
1453 0 : dirtype = status_dirtype;
1454 : }
1455 :
1456 324 : dptr_num = CVAL(status, 12);
1457 324 : fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
1458 324 : if (fsp == NULL) {
1459 0 : goto SearchEmpty;
1460 : }
1461 :
1462 324 : resume_key_index = PULL_LE_U32(status, 13);
1463 324 : dptr_filenum = dptr_FileNumber(fsp->dptr);
1464 :
1465 324 : if (resume_key_index > dptr_filenum) {
1466 : /*
1467 : * Haven't seen this resume key yet. Just stop
1468 : * the search.
1469 : */
1470 0 : goto SearchEmpty;
1471 : }
1472 :
1473 324 : if (resume_key_index < dptr_filenum) {
1474 : /*
1475 : * The resume key was not the last one we
1476 : * sent, rewind and skip to what the client
1477 : * sent.
1478 : */
1479 120 : dptr_RewindDir(fsp->dptr);
1480 :
1481 120 : dptr_filenum = dptr_FileNumber(fsp->dptr);
1482 120 : SMB_ASSERT(dptr_filenum == 0);
1483 :
1484 240 : while (dptr_filenum < resume_key_index) {
1485 120 : bool ok = get_dir_entry(
1486 : ctx,
1487 : conn,
1488 120 : fsp->dptr,
1489 : dptr_wcard(sconn, dptr_num),
1490 : dirtype,
1491 : &fname,
1492 : &size,
1493 : &mode,
1494 : &date,
1495 : check_descend,
1496 : false);
1497 120 : TALLOC_FREE(fname);
1498 120 : if (!ok) {
1499 0 : goto SearchEmpty;
1500 : }
1501 :
1502 120 : dptr_filenum = dptr_FileNumber(fsp->dptr);
1503 : }
1504 : }
1505 :
1506 324 : dirpath = dptr_path(sconn, dptr_num);
1507 324 : directory = talloc_strdup(ctx, dirpath);
1508 324 : if (!directory) {
1509 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1510 0 : goto out;
1511 : }
1512 :
1513 324 : mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1514 324 : if (!mask) {
1515 0 : goto SearchEmpty;
1516 : }
1517 324 : dirtype = dptr_attr(sconn, dptr_num);
1518 : }
1519 :
1520 500 : mask_contains_wcard = dptr_has_wild(fsp->dptr);
1521 :
1522 500 : DEBUG(4,("dptr_num is %d\n",dptr_num));
1523 :
1524 500 : if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1525 0 : char buf[DIR_STRUCT_SIZE];
1526 0 : memcpy(buf,status,21);
1527 0 : make_dir_struct(ctx,
1528 : buf,
1529 : "???????????",
1530 0 : volume_label(ctx, SNUM(conn)),
1531 : 0,
1532 : FILE_ATTRIBUTE_VOLUME,
1533 : 0,
1534 0 : !allow_long_path_components);
1535 0 : SCVAL(buf, 12, dptr_num);
1536 0 : numentries = 1;
1537 0 : if (message_push_blob(&req->outbuf,
1538 : data_blob_const(buf, sizeof(buf)))
1539 : == -1) {
1540 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1541 0 : goto out;
1542 : }
1543 : } else {
1544 0 : unsigned int i;
1545 500 : size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1546 500 : size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1547 0 : bool ask_sharemode;
1548 :
1549 500 : maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1550 :
1551 500 : DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1552 : directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
1553 500 : if (in_list(directory, lp_dont_descend(ctx, lp_sub, SNUM(conn)),True)) {
1554 0 : check_descend = True;
1555 : }
1556 :
1557 500 : ask_sharemode = fsp_search_ask_sharemode(fsp);
1558 :
1559 21267 : for (i=numentries;(i<maxentries) && !finished;i++) {
1560 41534 : finished = !get_dir_entry(ctx,
1561 : conn,
1562 20767 : fsp->dptr,
1563 : mask,
1564 : dirtype,
1565 : &fname,
1566 : &size,
1567 : &mode,
1568 : &date,
1569 : check_descend,
1570 20767 : ask_sharemode);
1571 20767 : if (!finished) {
1572 0 : char buf[DIR_STRUCT_SIZE];
1573 20719 : memcpy(buf,status,21);
1574 20719 : make_dir_struct(
1575 : ctx,
1576 : buf,
1577 : mask,
1578 : fname,
1579 : size,
1580 : mode,
1581 : convert_timespec_to_time_t(date),
1582 20719 : !allow_long_path_components);
1583 20719 : SCVAL(buf, 12, dptr_num);
1584 20719 : PUSH_LE_U32(buf,
1585 : 13,
1586 : dptr_FileNumber(fsp->dptr));
1587 20719 : if (message_push_blob(&req->outbuf,
1588 : data_blob_const(buf, sizeof(buf)))
1589 : == -1) {
1590 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1591 0 : goto out;
1592 : }
1593 20719 : numentries++;
1594 : }
1595 20767 : TALLOC_FREE(fname);
1596 : }
1597 : }
1598 :
1599 500 : SearchEmpty:
1600 :
1601 : /* If we were called as SMBffirst with smb_search_id == NULL
1602 : and no entries were found then return error and close fsp->dptr
1603 : (X/Open spec) */
1604 :
1605 500 : if (numentries == 0) {
1606 38 : dptr_num = -1;
1607 38 : if (fsp != NULL) {
1608 38 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1609 : }
1610 462 : } else if(expect_close && status_len == 0) {
1611 : /* Close the dptr - we know it's gone */
1612 6 : dptr_num = -1;
1613 6 : if (fsp != NULL) {
1614 6 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1615 : }
1616 : }
1617 :
1618 : /* If we were called as SMBfunique, then we can close the fsp->dptr now ! */
1619 500 : if(dptr_num >= 0 && req->cmd == SMBfunique) {
1620 6 : dptr_num = -1;
1621 : /* fsp may have been closed above. */
1622 6 : if (fsp != NULL) {
1623 6 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1624 : }
1625 : }
1626 :
1627 500 : if ((numentries == 0) && !mask_contains_wcard) {
1628 18 : reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1629 18 : goto out;
1630 : }
1631 :
1632 482 : SSVAL(req->outbuf,smb_vwv0,numentries);
1633 482 : SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1634 482 : SCVAL(smb_buf(req->outbuf),0,5);
1635 482 : SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1636 :
1637 : /* The replies here are never long name. */
1638 482 : SSVAL(req->outbuf, smb_flg2,
1639 : SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1640 482 : if (!allow_long_path_components) {
1641 4 : SSVAL(req->outbuf, smb_flg2,
1642 : SVAL(req->outbuf, smb_flg2)
1643 : & (~FLAGS2_LONG_PATH_COMPONENTS));
1644 : }
1645 :
1646 : /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1647 482 : SSVAL(req->outbuf, smb_flg2,
1648 : (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1649 :
1650 482 : DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1651 : smb_fn_name(req->cmd),
1652 : mask,
1653 : directory,
1654 : dirtype,
1655 : numentries,
1656 : maxentries ));
1657 500 : out:
1658 500 : TALLOC_FREE(directory);
1659 500 : TALLOC_FREE(mask);
1660 500 : TALLOC_FREE(smb_fname);
1661 500 : END_PROFILE(SMBsearch);
1662 500 : return;
1663 : }
1664 :
1665 : /****************************************************************************
1666 : Reply to a fclose (stop directory search).
1667 : ****************************************************************************/
1668 :
1669 8 : void reply_fclose(struct smb_request *req)
1670 : {
1671 0 : int status_len;
1672 8 : int dptr_num= -2;
1673 0 : const char *p;
1674 8 : char *path = NULL;
1675 0 : NTSTATUS err;
1676 8 : TALLOC_CTX *ctx = talloc_tos();
1677 8 : struct smbd_server_connection *sconn = req->sconn;
1678 8 : files_struct *fsp = NULL;
1679 :
1680 8 : START_PROFILE(SMBfclose);
1681 :
1682 8 : if (req->posix_pathnames) {
1683 0 : reply_unknown_new(req, req->cmd);
1684 0 : END_PROFILE(SMBfclose);
1685 0 : return;
1686 : }
1687 :
1688 8 : p = (const char *)req->buf + 1;
1689 8 : p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
1690 : &err);
1691 8 : if (!NT_STATUS_IS_OK(err)) {
1692 0 : reply_nterror(req, err);
1693 0 : END_PROFILE(SMBfclose);
1694 0 : return;
1695 : }
1696 :
1697 8 : if (smbreq_bufrem(req, p) < 3) {
1698 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1699 0 : END_PROFILE(SMBfclose);
1700 0 : return;
1701 : }
1702 :
1703 8 : p++;
1704 8 : status_len = SVAL(p,0);
1705 8 : p += 2;
1706 :
1707 8 : if (status_len == 0) {
1708 0 : reply_force_doserror(req, ERRSRV, ERRsrverror);
1709 0 : END_PROFILE(SMBfclose);
1710 0 : return;
1711 : }
1712 :
1713 8 : if (smbreq_bufrem(req, p) < 21) {
1714 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1715 0 : END_PROFILE(SMBfclose);
1716 0 : return;
1717 : }
1718 :
1719 8 : dptr_num = CVAL(p, 12);
1720 :
1721 8 : fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
1722 8 : if(fsp != NULL) {
1723 : /* Close the file - we know it's gone */
1724 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1725 0 : dptr_num = -1;
1726 : }
1727 :
1728 8 : reply_smb1_outbuf(req, 1, 0);
1729 8 : SSVAL(req->outbuf,smb_vwv0,0);
1730 :
1731 8 : DEBUG(3,("search close\n"));
1732 :
1733 8 : END_PROFILE(SMBfclose);
1734 8 : return;
1735 : }
1736 :
1737 : /****************************************************************************
1738 : Reply to an open.
1739 : ****************************************************************************/
1740 :
1741 61 : void reply_open(struct smb_request *req)
1742 : {
1743 61 : connection_struct *conn = req->conn;
1744 61 : struct smb_filename *smb_fname = NULL;
1745 61 : char *fname = NULL;
1746 61 : uint32_t fattr=0;
1747 61 : off_t size = 0;
1748 61 : time_t mtime=0;
1749 11 : int info;
1750 61 : struct files_struct *dirfsp = NULL;
1751 11 : files_struct *fsp;
1752 11 : int oplock_request;
1753 11 : int deny_mode;
1754 11 : uint32_t dos_attr;
1755 11 : uint32_t access_mask;
1756 11 : uint32_t share_mode;
1757 11 : uint32_t create_disposition;
1758 61 : uint32_t create_options = 0;
1759 61 : uint32_t private_flags = 0;
1760 11 : NTSTATUS status;
1761 11 : uint32_t ucf_flags;
1762 61 : NTTIME twrp = 0;
1763 61 : TALLOC_CTX *ctx = talloc_tos();
1764 :
1765 61 : START_PROFILE(SMBopen);
1766 :
1767 61 : if (req->wct < 2) {
1768 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1769 0 : goto out;
1770 : }
1771 :
1772 61 : oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1773 61 : deny_mode = SVAL(req->vwv+0, 0);
1774 61 : dos_attr = SVAL(req->vwv+1, 0);
1775 :
1776 61 : srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1777 : STR_TERMINATE, &status);
1778 61 : if (!NT_STATUS_IS_OK(status)) {
1779 0 : reply_nterror(req, status);
1780 0 : goto out;
1781 : }
1782 :
1783 61 : if (!map_open_params_to_ntcreate(fname, deny_mode,
1784 : OPENX_FILE_EXISTS_OPEN, &access_mask,
1785 : &share_mode, &create_disposition,
1786 : &create_options, &private_flags)) {
1787 0 : reply_force_doserror(req, ERRDOS, ERRbadaccess);
1788 0 : goto out;
1789 : }
1790 :
1791 61 : ucf_flags = filename_create_ucf_flags(req, create_disposition);
1792 :
1793 61 : if (ucf_flags & UCF_GMT_PATHNAME) {
1794 0 : extract_snapshot_token(fname, &twrp);
1795 : }
1796 61 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
1797 61 : if (!NT_STATUS_IS_OK(status)) {
1798 0 : reply_nterror(req, status);
1799 0 : goto out;
1800 : }
1801 61 : status = filename_convert_dirfsp(ctx,
1802 : conn,
1803 : fname,
1804 : ucf_flags,
1805 : twrp,
1806 : &dirfsp,
1807 : &smb_fname);
1808 61 : if (!NT_STATUS_IS_OK(status)) {
1809 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1810 0 : reply_botherror(req,
1811 : NT_STATUS_PATH_NOT_COVERED,
1812 : ERRSRV, ERRbadpath);
1813 0 : goto out;
1814 : }
1815 0 : reply_nterror(req, status);
1816 0 : goto out;
1817 : }
1818 :
1819 61 : status = SMB_VFS_CREATE_FILE(
1820 : conn, /* conn */
1821 : req, /* req */
1822 : dirfsp, /* dirfsp */
1823 : smb_fname, /* fname */
1824 : access_mask, /* access_mask */
1825 : share_mode, /* share_access */
1826 : create_disposition, /* create_disposition*/
1827 : create_options, /* create_options */
1828 : dos_attr, /* file_attributes */
1829 : oplock_request, /* oplock_request */
1830 : NULL, /* lease */
1831 : 0, /* allocation_size */
1832 : private_flags,
1833 : NULL, /* sd */
1834 : NULL, /* ea_list */
1835 : &fsp, /* result */
1836 : &info, /* pinfo */
1837 : NULL, NULL); /* create context */
1838 :
1839 61 : if (!NT_STATUS_IS_OK(status)) {
1840 24 : if (open_was_deferred(req->xconn, req->mid)) {
1841 : /* We have re-scheduled this call. */
1842 0 : goto out;
1843 : }
1844 :
1845 24 : if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
1846 9 : reply_openerror(req, status);
1847 9 : goto out;
1848 : }
1849 :
1850 15 : fsp = fcb_or_dos_open(
1851 : req,
1852 : smb_fname,
1853 : access_mask,
1854 : create_options,
1855 : private_flags);
1856 15 : if (fsp == NULL) {
1857 10 : bool ok = defer_smb1_sharing_violation(req);
1858 10 : if (ok) {
1859 5 : goto out;
1860 : }
1861 5 : reply_openerror(req, status);
1862 5 : goto out;
1863 : }
1864 : }
1865 :
1866 : /* Ensure we're pointing at the correct stat struct. */
1867 42 : TALLOC_FREE(smb_fname);
1868 42 : smb_fname = fsp->fsp_name;
1869 :
1870 42 : size = smb_fname->st.st_ex_size;
1871 42 : fattr = fdos_mode(fsp);
1872 :
1873 42 : mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1874 :
1875 42 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1876 0 : DEBUG(3,("attempt to open a directory %s\n",
1877 : fsp_str_dbg(fsp)));
1878 0 : close_file_free(req, &fsp, ERROR_CLOSE);
1879 0 : reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1880 : ERRDOS, ERRnoaccess);
1881 0 : goto out;
1882 : }
1883 :
1884 42 : reply_smb1_outbuf(req, 7, 0);
1885 42 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1886 42 : SSVAL(req->outbuf,smb_vwv1,fattr);
1887 42 : if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1888 0 : srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1889 : } else {
1890 42 : srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1891 : }
1892 42 : SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
1893 42 : SSVAL(req->outbuf,smb_vwv6,deny_mode);
1894 :
1895 42 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1896 0 : SCVAL(req->outbuf,smb_flg,
1897 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1898 : }
1899 :
1900 42 : if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1901 0 : SCVAL(req->outbuf,smb_flg,
1902 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1903 : }
1904 42 : out:
1905 61 : END_PROFILE(SMBopen);
1906 61 : return;
1907 : }
1908 :
1909 : /****************************************************************************
1910 : Reply to an open and X.
1911 : ****************************************************************************/
1912 :
1913 23327 : void reply_open_and_X(struct smb_request *req)
1914 : {
1915 23327 : connection_struct *conn = req->conn;
1916 23327 : struct smb_filename *smb_fname = NULL;
1917 23327 : char *fname = NULL;
1918 95 : uint16_t open_flags;
1919 95 : int deny_mode;
1920 95 : uint32_t smb_attr;
1921 : /* Breakout the oplock request bits so we can set the
1922 : reply bits separately. */
1923 95 : int ex_oplock_request;
1924 95 : int core_oplock_request;
1925 95 : int oplock_request;
1926 : #if 0
1927 : int smb_sattr = SVAL(req->vwv+4, 0);
1928 : uint32_t smb_time = make_unix_date3(req->vwv+6);
1929 : #endif
1930 95 : int smb_ofun;
1931 23327 : uint32_t fattr=0;
1932 23327 : int mtime=0;
1933 23327 : int smb_action = 0;
1934 23327 : struct files_struct *dirfsp = NULL;
1935 95 : files_struct *fsp;
1936 95 : NTSTATUS status;
1937 95 : uint64_t allocation_size;
1938 23327 : ssize_t retval = -1;
1939 95 : uint32_t access_mask;
1940 95 : uint32_t share_mode;
1941 95 : uint32_t create_disposition;
1942 23327 : uint32_t create_options = 0;
1943 23327 : uint32_t private_flags = 0;
1944 95 : uint32_t ucf_flags;
1945 23327 : NTTIME twrp = 0;
1946 23327 : TALLOC_CTX *ctx = talloc_tos();
1947 :
1948 23327 : START_PROFILE(SMBopenX);
1949 :
1950 23327 : if (req->wct < 15) {
1951 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1952 0 : goto out;
1953 : }
1954 :
1955 23327 : open_flags = SVAL(req->vwv+2, 0);
1956 23327 : deny_mode = SVAL(req->vwv+3, 0);
1957 23327 : smb_attr = SVAL(req->vwv+5, 0);
1958 23327 : ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1959 23327 : core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1960 23327 : oplock_request = ex_oplock_request | core_oplock_request;
1961 23327 : smb_ofun = SVAL(req->vwv+8, 0);
1962 23327 : allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1963 :
1964 : /* If it's an IPC, pass off the pipe handler. */
1965 23327 : if (IS_IPC(conn)) {
1966 40 : if (lp_nt_pipe_support()) {
1967 40 : reply_open_pipe_and_X(conn, req);
1968 : } else {
1969 0 : reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1970 : }
1971 40 : goto out;
1972 : }
1973 :
1974 : /* XXXX we need to handle passed times, sattr and flags */
1975 23287 : srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1976 : STR_TERMINATE, &status);
1977 23287 : if (!NT_STATUS_IS_OK(status)) {
1978 32 : reply_nterror(req, status);
1979 32 : goto out;
1980 : }
1981 :
1982 23255 : if (!map_open_params_to_ntcreate(fname, deny_mode,
1983 : smb_ofun,
1984 : &access_mask, &share_mode,
1985 : &create_disposition,
1986 : &create_options,
1987 : &private_flags)) {
1988 18 : reply_force_doserror(req, ERRDOS, ERRbadaccess);
1989 18 : goto out;
1990 : }
1991 :
1992 23237 : ucf_flags = filename_create_ucf_flags(req, create_disposition);
1993 :
1994 23237 : if (ucf_flags & UCF_GMT_PATHNAME) {
1995 0 : extract_snapshot_token(fname, &twrp);
1996 : }
1997 23237 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
1998 23237 : if (!NT_STATUS_IS_OK(status)) {
1999 0 : reply_nterror(req, status);
2000 0 : goto out;
2001 : }
2002 :
2003 23237 : status = filename_convert_dirfsp(ctx,
2004 : conn,
2005 : fname,
2006 : ucf_flags,
2007 : twrp,
2008 : &dirfsp,
2009 : &smb_fname);
2010 23237 : if (!NT_STATUS_IS_OK(status)) {
2011 40 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2012 0 : reply_botherror(req,
2013 : NT_STATUS_PATH_NOT_COVERED,
2014 : ERRSRV, ERRbadpath);
2015 0 : goto out;
2016 : }
2017 40 : reply_nterror(req, status);
2018 40 : goto out;
2019 : }
2020 :
2021 23197 : status = SMB_VFS_CREATE_FILE(
2022 : conn, /* conn */
2023 : req, /* req */
2024 : dirfsp, /* dirfsp */
2025 : smb_fname, /* fname */
2026 : access_mask, /* access_mask */
2027 : share_mode, /* share_access */
2028 : create_disposition, /* create_disposition*/
2029 : create_options, /* create_options */
2030 : smb_attr, /* file_attributes */
2031 : oplock_request, /* oplock_request */
2032 : NULL, /* lease */
2033 : 0, /* allocation_size */
2034 : private_flags,
2035 : NULL, /* sd */
2036 : NULL, /* ea_list */
2037 : &fsp, /* result */
2038 : &smb_action, /* pinfo */
2039 : NULL, NULL); /* create context */
2040 :
2041 23197 : if (!NT_STATUS_IS_OK(status)) {
2042 4609 : if (open_was_deferred(req->xconn, req->mid)) {
2043 : /* We have re-scheduled this call. */
2044 20 : goto out;
2045 : }
2046 :
2047 4589 : if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2048 189 : reply_openerror(req, status);
2049 189 : goto out;
2050 : }
2051 :
2052 4400 : fsp = fcb_or_dos_open(
2053 : req,
2054 : smb_fname,
2055 : access_mask,
2056 : create_options,
2057 : private_flags);
2058 4400 : if (fsp == NULL) {
2059 4292 : bool ok = defer_smb1_sharing_violation(req);
2060 4292 : if (ok) {
2061 2146 : goto out;
2062 : }
2063 2146 : reply_openerror(req, status);
2064 2146 : goto out;
2065 : }
2066 :
2067 :
2068 108 : smb_action = FILE_WAS_OPENED;
2069 : }
2070 :
2071 : /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2072 : if the file is truncated or created. */
2073 18696 : if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2074 44 : fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2075 44 : if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2076 0 : close_file_free(req, &fsp, ERROR_CLOSE);
2077 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
2078 0 : goto out;
2079 : }
2080 44 : retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2081 44 : if (retval < 0) {
2082 0 : close_file_free(req, &fsp, ERROR_CLOSE);
2083 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
2084 0 : goto out;
2085 : }
2086 44 : status = vfs_stat_fsp(fsp);
2087 44 : if (!NT_STATUS_IS_OK(status)) {
2088 0 : close_file_free(req, &fsp, ERROR_CLOSE);
2089 0 : reply_nterror(req, status);
2090 0 : goto out;
2091 : }
2092 : }
2093 :
2094 18696 : fattr = fdos_mode(fsp);
2095 18696 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2096 0 : close_file_free(req, &fsp, ERROR_CLOSE);
2097 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2098 0 : goto out;
2099 : }
2100 18696 : mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2101 :
2102 : /* If the caller set the extended oplock request bit
2103 : and we granted one (by whatever means) - set the
2104 : correct bit for extended oplock reply.
2105 : */
2106 :
2107 18696 : if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2108 0 : smb_action |= EXTENDED_OPLOCK_GRANTED;
2109 : }
2110 :
2111 18696 : if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2112 16 : smb_action |= EXTENDED_OPLOCK_GRANTED;
2113 : }
2114 :
2115 : /* If the caller set the core oplock request bit
2116 : and we granted one (by whatever means) - set the
2117 : correct bit for core oplock reply.
2118 : */
2119 :
2120 18696 : if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2121 5 : reply_smb1_outbuf(req, 19, 0);
2122 : } else {
2123 18691 : reply_smb1_outbuf(req, 15, 0);
2124 : }
2125 :
2126 18696 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2127 18696 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2128 :
2129 18696 : if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2130 0 : SCVAL(req->outbuf, smb_flg,
2131 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2132 : }
2133 :
2134 18696 : if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2135 16 : SCVAL(req->outbuf, smb_flg,
2136 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2137 : }
2138 :
2139 18696 : SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2140 18696 : SSVAL(req->outbuf,smb_vwv3,fattr);
2141 18696 : if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2142 0 : srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2143 : } else {
2144 18696 : srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2145 : }
2146 18696 : SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2147 18696 : SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2148 18696 : SSVAL(req->outbuf,smb_vwv11,smb_action);
2149 :
2150 18696 : if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2151 5 : SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2152 : }
2153 :
2154 18691 : out:
2155 23327 : TALLOC_FREE(smb_fname);
2156 23327 : END_PROFILE(SMBopenX);
2157 23327 : return;
2158 : }
2159 :
2160 : /****************************************************************************
2161 : Reply to a SMBulogoffX.
2162 : ****************************************************************************/
2163 :
2164 : static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2165 : struct smbXsrv_session *session);
2166 : static void reply_ulogoffX_done(struct tevent_req *req);
2167 :
2168 12 : void reply_ulogoffX(struct smb_request *smb1req)
2169 : {
2170 12 : struct timeval now = timeval_current();
2171 12 : struct smbXsrv_session *session = NULL;
2172 0 : struct tevent_req *req;
2173 0 : NTSTATUS status;
2174 :
2175 : /*
2176 : * Don't setup the profile charge here, take
2177 : * it in reply_ulogoffX_done(). Not strictly correct
2178 : * but better than the other SMB1 async
2179 : * code that double-charges at the moment.
2180 : */
2181 :
2182 12 : status = smb1srv_session_lookup(smb1req->xconn,
2183 12 : smb1req->vuid,
2184 : timeval_to_nttime(&now),
2185 : &session);
2186 12 : if (!NT_STATUS_IS_OK(status)) {
2187 : /* Not going async, profile here. */
2188 0 : START_PROFILE(SMBulogoffX);
2189 0 : DBG_WARNING("ulogoff, vuser id %llu does not map to user.\n",
2190 : (unsigned long long)smb1req->vuid);
2191 :
2192 0 : smb1req->vuid = UID_FIELD_INVALID;
2193 0 : reply_force_doserror(smb1req, ERRSRV, ERRbaduid);
2194 0 : END_PROFILE(SMBulogoffX);
2195 0 : return;
2196 : }
2197 :
2198 12 : req = reply_ulogoffX_send(smb1req, session);
2199 12 : if (req == NULL) {
2200 : /* Not going async, profile here. */
2201 0 : START_PROFILE(SMBulogoffX);
2202 0 : reply_force_doserror(smb1req, ERRDOS, ERRnomem);
2203 0 : END_PROFILE(SMBulogoffX);
2204 0 : return;
2205 : }
2206 :
2207 : /* We're async. This will complete later. */
2208 12 : tevent_req_set_callback(req, reply_ulogoffX_done, smb1req);
2209 12 : return;
2210 : }
2211 :
2212 : struct reply_ulogoffX_state {
2213 : struct tevent_queue *wait_queue;
2214 : struct smbXsrv_session *session;
2215 : };
2216 :
2217 : static void reply_ulogoffX_wait_done(struct tevent_req *subreq);
2218 :
2219 : /****************************************************************************
2220 : Async SMB1 ulogoffX.
2221 : Note, on failure here we deallocate and return NULL to allow the caller to
2222 : SMB1 return an error of ERRnomem immediately.
2223 : ****************************************************************************/
2224 :
2225 12 : static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2226 : struct smbXsrv_session *session)
2227 : {
2228 0 : struct tevent_req *req;
2229 0 : struct reply_ulogoffX_state *state;
2230 0 : struct tevent_req *subreq;
2231 0 : files_struct *fsp;
2232 12 : struct smbd_server_connection *sconn = session->client->sconn;
2233 12 : uint64_t vuid = session->global->session_wire_id;
2234 :
2235 12 : req = tevent_req_create(smb1req, &state,
2236 : struct reply_ulogoffX_state);
2237 12 : if (req == NULL) {
2238 0 : return NULL;
2239 : }
2240 12 : state->wait_queue = tevent_queue_create(state,
2241 : "reply_ulogoffX_wait_queue");
2242 12 : if (tevent_req_nomem(state->wait_queue, req)) {
2243 0 : TALLOC_FREE(req);
2244 0 : return NULL;
2245 : }
2246 12 : state->session = session;
2247 :
2248 : /*
2249 : * Make sure that no new request will be able to use this session.
2250 : * This ensures that once all outstanding fsp->aio_requests
2251 : * on this session are done, we are safe to close it.
2252 : */
2253 12 : session->status = NT_STATUS_USER_SESSION_DELETED;
2254 :
2255 20 : for (fsp = sconn->files; fsp; fsp = fsp->next) {
2256 8 : if (fsp->vuid != vuid) {
2257 0 : continue;
2258 : }
2259 : /*
2260 : * Flag the file as close in progress.
2261 : * This will prevent any more IO being
2262 : * done on it.
2263 : */
2264 8 : fsp->fsp_flags.closing = true;
2265 :
2266 8 : if (fsp->num_aio_requests > 0) {
2267 : /*
2268 : * Now wait until all aio requests on this fsp are
2269 : * finished.
2270 : *
2271 : * We don't set a callback, as we just want to block the
2272 : * wait queue and the talloc_free() of fsp->aio_request
2273 : * will remove the item from the wait queue.
2274 : */
2275 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
2276 : sconn->ev_ctx,
2277 0 : state->wait_queue);
2278 0 : if (tevent_req_nomem(subreq, req)) {
2279 0 : TALLOC_FREE(req);
2280 0 : return NULL;
2281 : }
2282 : }
2283 : }
2284 :
2285 : /*
2286 : * Now we add our own waiter to the end of the queue,
2287 : * this way we get notified when all pending requests are finished
2288 : * and reply to the outstanding SMB1 request.
2289 : */
2290 12 : subreq = tevent_queue_wait_send(state,
2291 : sconn->ev_ctx,
2292 12 : state->wait_queue);
2293 12 : if (tevent_req_nomem(subreq, req)) {
2294 0 : TALLOC_FREE(req);
2295 0 : return NULL;
2296 : }
2297 :
2298 : /*
2299 : * We're really going async - move the SMB1 request from
2300 : * a talloc stackframe above us to the sconn talloc-context.
2301 : * We need this to stick around until the wait_done
2302 : * callback is invoked.
2303 : */
2304 12 : smb1req = talloc_move(sconn, &smb1req);
2305 :
2306 12 : tevent_req_set_callback(subreq, reply_ulogoffX_wait_done, req);
2307 :
2308 12 : return req;
2309 : }
2310 :
2311 12 : static void reply_ulogoffX_wait_done(struct tevent_req *subreq)
2312 : {
2313 12 : struct tevent_req *req = tevent_req_callback_data(
2314 : subreq, struct tevent_req);
2315 :
2316 12 : tevent_queue_wait_recv(subreq);
2317 12 : TALLOC_FREE(subreq);
2318 12 : tevent_req_done(req);
2319 12 : }
2320 :
2321 12 : static NTSTATUS reply_ulogoffX_recv(struct tevent_req *req)
2322 : {
2323 12 : return tevent_req_simple_recv_ntstatus(req);
2324 : }
2325 :
2326 12 : static void reply_ulogoffX_done(struct tevent_req *req)
2327 : {
2328 12 : struct smb_request *smb1req = tevent_req_callback_data(
2329 : req, struct smb_request);
2330 12 : struct reply_ulogoffX_state *state = tevent_req_data(req,
2331 : struct reply_ulogoffX_state);
2332 12 : struct smbXsrv_session *session = state->session;
2333 0 : NTSTATUS status;
2334 :
2335 : /*
2336 : * Take the profile charge here. Not strictly
2337 : * correct but better than the other SMB1 async
2338 : * code that double-charges at the moment.
2339 : */
2340 12 : START_PROFILE(SMBulogoffX);
2341 :
2342 12 : status = reply_ulogoffX_recv(req);
2343 12 : TALLOC_FREE(req);
2344 12 : if (!NT_STATUS_IS_OK(status)) {
2345 0 : TALLOC_FREE(smb1req);
2346 0 : END_PROFILE(SMBulogoffX);
2347 0 : exit_server(__location__ ": reply_ulogoffX_recv failed");
2348 : return;
2349 : }
2350 :
2351 12 : status = smbXsrv_session_logoff(session);
2352 12 : if (!NT_STATUS_IS_OK(status)) {
2353 0 : TALLOC_FREE(smb1req);
2354 0 : END_PROFILE(SMBulogoffX);
2355 0 : exit_server(__location__ ": smbXsrv_session_logoff failed");
2356 : return;
2357 : }
2358 :
2359 12 : TALLOC_FREE(session);
2360 :
2361 12 : reply_smb1_outbuf(smb1req, 2, 0);
2362 12 : SSVAL(smb1req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2363 12 : SSVAL(smb1req->outbuf, smb_vwv1, 0); /* no andx offset */
2364 :
2365 12 : DBG_NOTICE("ulogoffX vuid=%llu\n",
2366 : (unsigned long long)smb1req->vuid);
2367 :
2368 12 : smb1req->vuid = UID_FIELD_INVALID;
2369 : /*
2370 : * The following call is needed to push the
2371 : * reply data back out the socket after async
2372 : * return. Plus it frees smb1req.
2373 : */
2374 12 : smb_request_done(smb1req);
2375 12 : END_PROFILE(SMBulogoffX);
2376 : }
2377 :
2378 : /****************************************************************************
2379 : Reply to a mknew or a create.
2380 : ****************************************************************************/
2381 :
2382 42 : void reply_mknew(struct smb_request *req)
2383 : {
2384 42 : connection_struct *conn = req->conn;
2385 42 : struct smb_filename *smb_fname = NULL;
2386 42 : char *fname = NULL;
2387 42 : uint32_t fattr = 0;
2388 8 : struct smb_file_time ft;
2389 42 : struct files_struct *dirfsp = NULL;
2390 8 : files_struct *fsp;
2391 42 : int oplock_request = 0;
2392 8 : NTSTATUS status;
2393 42 : uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2394 42 : uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2395 8 : uint32_t create_disposition;
2396 42 : uint32_t create_options = 0;
2397 8 : uint32_t ucf_flags;
2398 42 : NTTIME twrp = 0;
2399 42 : TALLOC_CTX *ctx = talloc_tos();
2400 :
2401 42 : START_PROFILE(SMBcreate);
2402 42 : init_smb_file_time(&ft);
2403 :
2404 42 : if (req->wct < 3) {
2405 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2406 0 : goto out;
2407 : }
2408 :
2409 42 : fattr = SVAL(req->vwv+0, 0);
2410 42 : oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2411 :
2412 42 : if (req->cmd == SMBmknew) {
2413 : /* We should fail if file exists. */
2414 16 : create_disposition = FILE_CREATE;
2415 : } else {
2416 : /* Create if file doesn't exist, truncate if it does. */
2417 22 : create_disposition = FILE_OVERWRITE_IF;
2418 : }
2419 :
2420 : /* mtime. */
2421 42 : ft.mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+1));
2422 :
2423 42 : srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2424 : STR_TERMINATE, &status);
2425 42 : if (!NT_STATUS_IS_OK(status)) {
2426 0 : reply_nterror(req, status);
2427 0 : goto out;
2428 : }
2429 :
2430 42 : ucf_flags = filename_create_ucf_flags(req, create_disposition);
2431 42 : if (ucf_flags & UCF_GMT_PATHNAME) {
2432 0 : extract_snapshot_token(fname, &twrp);
2433 : }
2434 42 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
2435 42 : if (!NT_STATUS_IS_OK(status)) {
2436 0 : reply_nterror(req, status);
2437 0 : goto out;
2438 : }
2439 :
2440 42 : status = filename_convert_dirfsp(ctx,
2441 : conn,
2442 : fname,
2443 : ucf_flags,
2444 : twrp,
2445 : &dirfsp,
2446 : &smb_fname);
2447 42 : if (!NT_STATUS_IS_OK(status)) {
2448 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2449 0 : reply_botherror(req,
2450 : NT_STATUS_PATH_NOT_COVERED,
2451 : ERRSRV, ERRbadpath);
2452 0 : goto out;
2453 : }
2454 0 : reply_nterror(req, status);
2455 0 : goto out;
2456 : }
2457 :
2458 42 : if (fattr & FILE_ATTRIBUTE_VOLUME) {
2459 0 : DEBUG(0,("Attempt to create file (%s) with volid set - "
2460 : "please report this\n",
2461 : smb_fname_str_dbg(smb_fname)));
2462 : }
2463 :
2464 42 : status = SMB_VFS_CREATE_FILE(
2465 : conn, /* conn */
2466 : req, /* req */
2467 : dirfsp, /* dirfsp */
2468 : smb_fname, /* fname */
2469 : access_mask, /* access_mask */
2470 : share_mode, /* share_access */
2471 : create_disposition, /* create_disposition*/
2472 : create_options, /* create_options */
2473 : fattr, /* file_attributes */
2474 : oplock_request, /* oplock_request */
2475 : NULL, /* lease */
2476 : 0, /* allocation_size */
2477 : 0, /* private_flags */
2478 : NULL, /* sd */
2479 : NULL, /* ea_list */
2480 : &fsp, /* result */
2481 : NULL, /* pinfo */
2482 : NULL, NULL); /* create context */
2483 :
2484 42 : if (!NT_STATUS_IS_OK(status)) {
2485 7 : if (open_was_deferred(req->xconn, req->mid)) {
2486 : /* We have re-scheduled this call. */
2487 0 : goto out;
2488 : }
2489 7 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2490 0 : bool ok = defer_smb1_sharing_violation(req);
2491 0 : if (ok) {
2492 0 : goto out;
2493 : }
2494 : }
2495 7 : reply_openerror(req, status);
2496 7 : goto out;
2497 : }
2498 :
2499 35 : ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2500 35 : status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2501 35 : if (!NT_STATUS_IS_OK(status)) {
2502 0 : END_PROFILE(SMBcreate);
2503 0 : goto out;
2504 : }
2505 :
2506 35 : reply_smb1_outbuf(req, 1, 0);
2507 35 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2508 :
2509 35 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2510 0 : SCVAL(req->outbuf,smb_flg,
2511 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2512 : }
2513 :
2514 35 : if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2515 0 : SCVAL(req->outbuf,smb_flg,
2516 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2517 : }
2518 :
2519 35 : DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2520 35 : DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2521 : smb_fname_str_dbg(smb_fname), fsp_get_io_fd(fsp),
2522 : (unsigned int)fattr));
2523 :
2524 42 : out:
2525 42 : TALLOC_FREE(smb_fname);
2526 42 : END_PROFILE(SMBcreate);
2527 42 : return;
2528 : }
2529 :
2530 : /****************************************************************************
2531 : Reply to a create temporary file.
2532 : ****************************************************************************/
2533 :
2534 14 : void reply_ctemp(struct smb_request *req)
2535 : {
2536 14 : connection_struct *conn = req->conn;
2537 14 : struct smb_filename *smb_fname = NULL;
2538 14 : char *wire_name = NULL;
2539 14 : char *fname = NULL;
2540 2 : uint32_t fattr;
2541 14 : struct files_struct *dirfsp = NULL;
2542 2 : files_struct *fsp;
2543 2 : int oplock_request;
2544 2 : char *s;
2545 2 : NTSTATUS status;
2546 2 : int i;
2547 2 : uint32_t ucf_flags;
2548 14 : NTTIME twrp = 0;
2549 14 : TALLOC_CTX *ctx = talloc_tos();
2550 :
2551 14 : START_PROFILE(SMBctemp);
2552 :
2553 14 : if (req->wct < 3) {
2554 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2555 0 : goto out;
2556 : }
2557 :
2558 14 : fattr = SVAL(req->vwv+0, 0);
2559 14 : oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2560 :
2561 14 : srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2562 : STR_TERMINATE, &status);
2563 14 : if (!NT_STATUS_IS_OK(status)) {
2564 0 : reply_nterror(req, status);
2565 0 : goto out;
2566 : }
2567 :
2568 14 : for (i = 0; i < 10; i++) {
2569 14 : if (*wire_name) {
2570 5 : fname = talloc_asprintf(ctx,
2571 : "%s/TMP%s",
2572 : wire_name,
2573 : generate_random_str_list(ctx, 5, "0123456789"));
2574 : } else {
2575 9 : fname = talloc_asprintf(ctx,
2576 : "TMP%s",
2577 : generate_random_str_list(ctx, 5, "0123456789"));
2578 : }
2579 :
2580 14 : if (!fname) {
2581 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2582 0 : goto out;
2583 : }
2584 :
2585 14 : ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2586 14 : if (ucf_flags & UCF_GMT_PATHNAME) {
2587 0 : extract_snapshot_token(fname, &twrp);
2588 : }
2589 14 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
2590 14 : if (!NT_STATUS_IS_OK(status)) {
2591 0 : reply_nterror(req, status);
2592 0 : goto out;
2593 : }
2594 :
2595 14 : status = filename_convert_dirfsp(ctx,
2596 : conn,
2597 : fname,
2598 : ucf_flags,
2599 : twrp,
2600 : &dirfsp,
2601 : &smb_fname);
2602 14 : if (!NT_STATUS_IS_OK(status)) {
2603 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2604 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2605 : ERRSRV, ERRbadpath);
2606 0 : goto out;
2607 : }
2608 0 : reply_nterror(req, status);
2609 0 : goto out;
2610 : }
2611 :
2612 : /* Create the file. */
2613 14 : status = SMB_VFS_CREATE_FILE(
2614 : conn, /* conn */
2615 : req, /* req */
2616 : dirfsp, /* dirfsp */
2617 : smb_fname, /* fname */
2618 : FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2619 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2620 : FILE_CREATE, /* create_disposition*/
2621 : 0, /* create_options */
2622 : fattr, /* file_attributes */
2623 : oplock_request, /* oplock_request */
2624 : NULL, /* lease */
2625 : 0, /* allocation_size */
2626 : 0, /* private_flags */
2627 : NULL, /* sd */
2628 : NULL, /* ea_list */
2629 : &fsp, /* result */
2630 : NULL, /* pinfo */
2631 : NULL, NULL); /* create context */
2632 :
2633 14 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2634 0 : TALLOC_FREE(fname);
2635 0 : TALLOC_FREE(dirfsp);
2636 0 : TALLOC_FREE(smb_fname);
2637 0 : continue;
2638 : }
2639 :
2640 14 : if (!NT_STATUS_IS_OK(status)) {
2641 0 : if (open_was_deferred(req->xconn, req->mid)) {
2642 : /* We have re-scheduled this call. */
2643 0 : goto out;
2644 : }
2645 0 : if (NT_STATUS_EQUAL(
2646 : status, NT_STATUS_SHARING_VIOLATION)) {
2647 0 : bool ok = defer_smb1_sharing_violation(req);
2648 0 : if (ok) {
2649 0 : goto out;
2650 : }
2651 : }
2652 0 : reply_openerror(req, status);
2653 0 : goto out;
2654 : }
2655 :
2656 12 : break;
2657 : }
2658 :
2659 14 : if (i == 10) {
2660 : /* Collision after 10 times... */
2661 0 : reply_nterror(req, status);
2662 0 : goto out;
2663 : }
2664 :
2665 14 : reply_smb1_outbuf(req, 1, 0);
2666 14 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2667 :
2668 : /* the returned filename is relative to the directory */
2669 14 : s = strrchr_m(fsp->fsp_name->base_name, '/');
2670 14 : if (!s) {
2671 9 : s = fsp->fsp_name->base_name;
2672 : } else {
2673 5 : s++;
2674 : }
2675 :
2676 : #if 0
2677 : /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2678 : thing in the byte section. JRA */
2679 : SSVALS(p, 0, -1); /* what is this? not in spec */
2680 : #endif
2681 14 : if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2682 : == -1) {
2683 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2684 0 : goto out;
2685 : }
2686 :
2687 14 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2688 0 : SCVAL(req->outbuf, smb_flg,
2689 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2690 : }
2691 :
2692 14 : if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2693 0 : SCVAL(req->outbuf, smb_flg,
2694 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2695 : }
2696 :
2697 14 : DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2698 14 : DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2699 : fsp_get_io_fd(fsp), (unsigned int)smb_fname->st.st_ex_mode));
2700 14 : out:
2701 14 : TALLOC_FREE(smb_fname);
2702 14 : TALLOC_FREE(wire_name);
2703 14 : END_PROFILE(SMBctemp);
2704 14 : return;
2705 : }
2706 :
2707 : /****************************************************************************
2708 : Reply to a unlink
2709 : ****************************************************************************/
2710 :
2711 31492 : void reply_unlink(struct smb_request *req)
2712 : {
2713 31492 : connection_struct *conn = req->conn;
2714 31492 : char *name = NULL;
2715 31492 : struct files_struct *dirfsp = NULL;
2716 31492 : struct smb_filename *smb_fname = NULL;
2717 418 : uint32_t dirtype;
2718 418 : NTSTATUS status;
2719 31492 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
2720 31492 : NTTIME twrp = 0;
2721 31492 : TALLOC_CTX *ctx = talloc_tos();
2722 :
2723 31492 : START_PROFILE(SMBunlink);
2724 :
2725 31492 : if (req->wct < 1) {
2726 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2727 0 : goto out;
2728 : }
2729 :
2730 31492 : dirtype = SVAL(req->vwv+0, 0);
2731 :
2732 31492 : srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
2733 : STR_TERMINATE, &status);
2734 31492 : if (!NT_STATUS_IS_OK(status)) {
2735 167 : reply_nterror(req, status);
2736 167 : goto out;
2737 : }
2738 :
2739 31325 : if (ucf_flags & UCF_GMT_PATHNAME) {
2740 0 : extract_snapshot_token(name, &twrp);
2741 : }
2742 31325 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &name);
2743 31325 : if (!NT_STATUS_IS_OK(status)) {
2744 0 : reply_nterror(req, status);
2745 0 : goto out;
2746 : }
2747 31325 : status = filename_convert_dirfsp(ctx,
2748 : conn,
2749 : name,
2750 : ucf_flags | UCF_LCOMP_LNK_OK,
2751 : twrp,
2752 : &dirfsp,
2753 : &smb_fname);
2754 31325 : if (!NT_STATUS_IS_OK(status)) {
2755 4422 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2756 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2757 : ERRSRV, ERRbadpath);
2758 0 : goto out;
2759 : }
2760 4422 : reply_nterror(req, status);
2761 4422 : goto out;
2762 : }
2763 :
2764 26903 : DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2765 :
2766 26903 : status = unlink_internals(conn, req, dirtype, dirfsp, smb_fname);
2767 26903 : if (!NT_STATUS_IS_OK(status)) {
2768 3692 : if (open_was_deferred(req->xconn, req->mid)) {
2769 : /* We have re-scheduled this call. */
2770 14 : goto out;
2771 : }
2772 3678 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2773 182 : bool ok = defer_smb1_sharing_violation(req);
2774 182 : if (ok) {
2775 89 : goto out;
2776 : }
2777 : }
2778 3589 : reply_nterror(req, status);
2779 3589 : goto out;
2780 : }
2781 :
2782 23211 : reply_smb1_outbuf(req, 0, 0);
2783 31492 : out:
2784 31492 : TALLOC_FREE(smb_fname);
2785 31492 : END_PROFILE(SMBunlink);
2786 31492 : return;
2787 : }
2788 :
2789 : /****************************************************************************
2790 : Fail for readbraw.
2791 : ****************************************************************************/
2792 :
2793 0 : static void fail_readraw(void)
2794 : {
2795 0 : const char *errstr = talloc_asprintf(talloc_tos(),
2796 : "FAIL ! reply_readbraw: socket write fail (%s)",
2797 0 : strerror(errno));
2798 0 : if (!errstr) {
2799 0 : errstr = "";
2800 : }
2801 0 : exit_server_cleanly(errstr);
2802 : }
2803 :
2804 : /****************************************************************************
2805 : Return a readbraw error (4 bytes of zero).
2806 : ****************************************************************************/
2807 :
2808 16 : static void reply_readbraw_error(struct smbXsrv_connection *xconn)
2809 : {
2810 0 : char header[4];
2811 :
2812 16 : SIVAL(header,0,0);
2813 :
2814 16 : smbd_lock_socket(xconn);
2815 16 : if (write_data(xconn->transport.sock,header,4) != 4) {
2816 0 : int saved_errno = errno;
2817 : /*
2818 : * Try and give an error message saying what
2819 : * client failed.
2820 : */
2821 0 : DEBUG(0, ("write_data failed for client %s. "
2822 : "Error %s\n",
2823 : smbXsrv_connection_dbg(xconn),
2824 : strerror(saved_errno)));
2825 0 : errno = saved_errno;
2826 :
2827 0 : fail_readraw();
2828 : }
2829 16 : smbd_unlock_socket(xconn);
2830 16 : }
2831 :
2832 : /*******************************************************************
2833 : Ensure we don't use sendfile if server smb signing is active.
2834 : ********************************************************************/
2835 :
2836 47 : static bool lp_use_sendfile(struct smbXsrv_connection *xconn,
2837 : int snum,
2838 : struct smb1_signing_state *signing_state)
2839 : {
2840 47 : bool sign_active = false;
2841 :
2842 : /* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
2843 47 : if (xconn->protocol < PROTOCOL_NT1) {
2844 0 : return false;
2845 : }
2846 47 : if (signing_state) {
2847 47 : sign_active = smb1_signing_is_active(signing_state);
2848 : }
2849 47 : return (lp__use_sendfile(snum) &&
2850 47 : (get_remote_arch() != RA_WIN95) &&
2851 0 : !sign_active);
2852 : }
2853 : /****************************************************************************
2854 : Use sendfile in readbraw.
2855 : ****************************************************************************/
2856 :
2857 32 : static void send_file_readbraw(connection_struct *conn,
2858 : struct smb_request *req,
2859 : files_struct *fsp,
2860 : off_t startpos,
2861 : size_t nread,
2862 : ssize_t mincount)
2863 : {
2864 32 : struct smbXsrv_connection *xconn = req->xconn;
2865 32 : char *outbuf = NULL;
2866 32 : ssize_t ret=0;
2867 :
2868 : /*
2869 : * We can only use sendfile on a non-chained packet
2870 : * but we can use on a non-oplocked file. tridge proved this
2871 : * on a train in Germany :-). JRA.
2872 : * reply_readbraw has already checked the length.
2873 : */
2874 :
2875 32 : if ( !req_is_in_chain(req) &&
2876 20 : (nread > 0) &&
2877 40 : !fsp_is_alternate_stream(fsp) &&
2878 20 : lp_use_sendfile(xconn, SNUM(conn), xconn->smb1.signing_state) ) {
2879 0 : ssize_t sendfile_read = -1;
2880 0 : char header[4];
2881 0 : DATA_BLOB header_blob;
2882 :
2883 0 : _smb_setlen(header,nread);
2884 0 : header_blob = data_blob_const(header, 4);
2885 :
2886 0 : sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
2887 : &header_blob, startpos,
2888 : nread);
2889 0 : if (sendfile_read == -1) {
2890 : /* Returning ENOSYS means no data at all was sent.
2891 : * Do this as a normal read. */
2892 0 : if (errno == ENOSYS) {
2893 0 : goto normal_readbraw;
2894 : }
2895 :
2896 : /*
2897 : * Special hack for broken Linux with no working sendfile. If we
2898 : * return EINTR we sent the header but not the rest of the data.
2899 : * Fake this up by doing read/write calls.
2900 : */
2901 0 : if (errno == EINTR) {
2902 : /* Ensure we don't do this again. */
2903 0 : set_use_sendfile(SNUM(conn), False);
2904 0 : DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2905 :
2906 0 : if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
2907 0 : DEBUG(0,("send_file_readbraw: "
2908 : "fake_sendfile failed for "
2909 : "file %s (%s).\n",
2910 : fsp_str_dbg(fsp),
2911 : strerror(errno)));
2912 0 : exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2913 : }
2914 0 : return;
2915 : }
2916 :
2917 0 : DEBUG(0,("send_file_readbraw: sendfile failed for "
2918 : "file %s (%s). Terminating\n",
2919 : fsp_str_dbg(fsp), strerror(errno)));
2920 0 : exit_server_cleanly("send_file_readbraw sendfile failed");
2921 0 : } else if (sendfile_read == 0) {
2922 : /*
2923 : * Some sendfile implementations return 0 to indicate
2924 : * that there was a short read, but nothing was
2925 : * actually written to the socket. In this case,
2926 : * fallback to the normal read path so the header gets
2927 : * the correct byte count.
2928 : */
2929 0 : DEBUG(3, ("send_file_readbraw: sendfile sent zero "
2930 : "bytes falling back to the normal read: "
2931 : "%s\n", fsp_str_dbg(fsp)));
2932 0 : goto normal_readbraw;
2933 : }
2934 :
2935 : /* Deal with possible short send. */
2936 0 : if (sendfile_read != 4+nread) {
2937 0 : ret = sendfile_short_send(xconn, fsp,
2938 : sendfile_read, 4, nread);
2939 0 : if (ret == -1) {
2940 0 : fail_readraw();
2941 : }
2942 : }
2943 0 : return;
2944 : }
2945 :
2946 32 : normal_readbraw:
2947 :
2948 32 : outbuf = talloc_array(NULL, char, nread+4);
2949 32 : if (!outbuf) {
2950 0 : DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
2951 : (unsigned)(nread+4)));
2952 0 : reply_readbraw_error(xconn);
2953 0 : return;
2954 : }
2955 :
2956 32 : if (nread > 0) {
2957 20 : ret = read_file(fsp,outbuf+4,startpos,nread);
2958 : #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
2959 : if (ret < mincount)
2960 : ret = 0;
2961 : #else
2962 20 : if (ret < nread)
2963 0 : ret = 0;
2964 : #endif
2965 : }
2966 :
2967 32 : _smb_setlen(outbuf,ret);
2968 32 : if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
2969 0 : int saved_errno = errno;
2970 : /*
2971 : * Try and give an error message saying what
2972 : * client failed.
2973 : */
2974 0 : DEBUG(0, ("write_data failed for client %s. Error %s\n",
2975 : smbXsrv_connection_dbg(xconn),
2976 : strerror(saved_errno)));
2977 0 : errno = saved_errno;
2978 :
2979 0 : fail_readraw();
2980 : }
2981 :
2982 32 : TALLOC_FREE(outbuf);
2983 : }
2984 :
2985 : /****************************************************************************
2986 : Reply to a readbraw (core+ protocol).
2987 : ****************************************************************************/
2988 :
2989 48 : void reply_readbraw(struct smb_request *req)
2990 : {
2991 48 : connection_struct *conn = req->conn;
2992 48 : struct smbXsrv_connection *xconn = req->xconn;
2993 0 : ssize_t maxcount,mincount;
2994 48 : size_t nread = 0;
2995 0 : off_t startpos;
2996 0 : files_struct *fsp;
2997 0 : struct lock_struct lock;
2998 48 : off_t size = 0;
2999 0 : NTSTATUS status;
3000 :
3001 48 : START_PROFILE(SMBreadbraw);
3002 :
3003 48 : if (smb1_srv_is_signing_active(xconn) || req->encrypted) {
3004 0 : exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3005 : "raw reads/writes are disallowed.");
3006 : }
3007 :
3008 48 : if (req->wct < 8) {
3009 0 : reply_readbraw_error(xconn);
3010 0 : END_PROFILE(SMBreadbraw);
3011 0 : return;
3012 : }
3013 :
3014 48 : if (xconn->smb1.echo_handler.trusted_fde) {
3015 0 : DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3016 : "'async smb echo handler = yes'\n"));
3017 0 : reply_readbraw_error(xconn);
3018 0 : END_PROFILE(SMBreadbraw);
3019 0 : return;
3020 : }
3021 :
3022 : /*
3023 : * Special check if an oplock break has been issued
3024 : * and the readraw request croses on the wire, we must
3025 : * return a zero length response here.
3026 : */
3027 :
3028 48 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3029 :
3030 : /*
3031 : * We have to do a check_fsp by hand here, as
3032 : * we must always return 4 zero bytes on error,
3033 : * not a NTSTATUS.
3034 : */
3035 :
3036 48 : if (fsp == NULL ||
3037 44 : conn == NULL ||
3038 44 : conn != fsp->conn ||
3039 44 : req->vuid != fsp->vuid ||
3040 44 : fsp->fsp_flags.is_directory ||
3041 44 : fsp_get_io_fd(fsp) == -1)
3042 : {
3043 : /*
3044 : * fsp could be NULL here so use the value from the packet. JRA.
3045 : */
3046 4 : DEBUG(3,("reply_readbraw: fnum %d not valid "
3047 : "- cache prime?\n",
3048 : (int)SVAL(req->vwv+0, 0)));
3049 4 : reply_readbraw_error(xconn);
3050 4 : END_PROFILE(SMBreadbraw);
3051 4 : return;
3052 : }
3053 :
3054 : /* Do a "by hand" version of CHECK_READ. */
3055 44 : if (!(fsp->fsp_flags.can_read ||
3056 0 : ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3057 0 : (fsp->access_mask & FILE_EXECUTE)))) {
3058 0 : DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3059 : (int)SVAL(req->vwv+0, 0)));
3060 0 : reply_readbraw_error(xconn);
3061 0 : END_PROFILE(SMBreadbraw);
3062 0 : return;
3063 : }
3064 :
3065 44 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3066 44 : if(req->wct == 10) {
3067 : /*
3068 : * This is a large offset (64 bit) read.
3069 : */
3070 :
3071 44 : startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3072 :
3073 44 : if(startpos < 0) {
3074 4 : DEBUG(0,("reply_readbraw: negative 64 bit "
3075 : "readraw offset (%.0f) !\n",
3076 : (double)startpos ));
3077 4 : reply_readbraw_error(xconn);
3078 4 : END_PROFILE(SMBreadbraw);
3079 4 : return;
3080 : }
3081 : }
3082 :
3083 40 : maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3084 40 : mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3085 :
3086 : /* ensure we don't overrun the packet size */
3087 40 : maxcount = MIN(65535,maxcount);
3088 :
3089 40 : init_strict_lock_struct(fsp,
3090 40 : (uint64_t)req->smbpid,
3091 : (uint64_t)startpos,
3092 : (uint64_t)maxcount,
3093 : READ_LOCK,
3094 : lp_posix_cifsu_locktype(fsp),
3095 : &lock);
3096 :
3097 40 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3098 8 : reply_readbraw_error(xconn);
3099 8 : END_PROFILE(SMBreadbraw);
3100 8 : return;
3101 : }
3102 :
3103 32 : status = vfs_stat_fsp(fsp);
3104 32 : if (NT_STATUS_IS_OK(status)) {
3105 32 : size = fsp->fsp_name->st.st_ex_size;
3106 : }
3107 :
3108 32 : if (startpos >= size) {
3109 12 : nread = 0;
3110 : } else {
3111 20 : nread = MIN(maxcount,(size - startpos));
3112 : }
3113 :
3114 : #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3115 : if (nread < mincount)
3116 : nread = 0;
3117 : #endif
3118 :
3119 32 : DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3120 : "min=%lu nread=%lu\n",
3121 : fsp_fnum_dbg(fsp), (double)startpos,
3122 : (unsigned long)maxcount,
3123 : (unsigned long)mincount,
3124 : (unsigned long)nread ) );
3125 :
3126 32 : send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3127 :
3128 32 : DEBUG(5,("reply_readbraw finished\n"));
3129 :
3130 32 : END_PROFILE(SMBreadbraw);
3131 32 : return;
3132 : }
3133 :
3134 : #undef DBGC_CLASS
3135 : #define DBGC_CLASS DBGC_LOCKING
3136 :
3137 : /****************************************************************************
3138 : Reply to a lockread (core+ protocol).
3139 : ****************************************************************************/
3140 :
3141 : static void reply_lockread_locked(struct tevent_req *subreq);
3142 :
3143 91 : void reply_lockread(struct smb_request *req)
3144 : {
3145 91 : struct tevent_req *subreq = NULL;
3146 91 : connection_struct *conn = req->conn;
3147 13 : files_struct *fsp;
3148 91 : struct smbd_lock_element *lck = NULL;
3149 :
3150 91 : START_PROFILE(SMBlockread);
3151 :
3152 91 : if (req->wct < 5) {
3153 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3154 0 : END_PROFILE(SMBlockread);
3155 0 : return;
3156 : }
3157 :
3158 91 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3159 :
3160 91 : if (!check_fsp(conn, req, fsp)) {
3161 7 : END_PROFILE(SMBlockread);
3162 7 : return;
3163 : }
3164 :
3165 84 : if (!CHECK_READ(fsp,req)) {
3166 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3167 0 : END_PROFILE(SMBlockread);
3168 0 : return;
3169 : }
3170 :
3171 84 : lck = talloc(req, struct smbd_lock_element);
3172 84 : if (lck == NULL) {
3173 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
3174 0 : END_PROFILE(SMBlockread);
3175 0 : return;
3176 : }
3177 :
3178 : /*
3179 : * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3180 : * protocol request that predates the read/write lock concept.
3181 : * Thus instead of asking for a read lock here we need to ask
3182 : * for a write lock. JRA.
3183 : * Note that the requested lock size is unaffected by max_send.
3184 : */
3185 :
3186 96 : *lck = (struct smbd_lock_element) {
3187 84 : .req_guid = smbd_request_guid(req, 0),
3188 84 : .smblctx = req->smbpid,
3189 : .brltype = WRITE_LOCK,
3190 : .lock_flav = WINDOWS_LOCK,
3191 84 : .count = SVAL(req->vwv+1, 0),
3192 84 : .offset = IVAL_TO_SMB_OFF_T(req->vwv+2, 0),
3193 : };
3194 :
3195 96 : subreq = smbd_smb1_do_locks_send(
3196 : fsp,
3197 84 : req->sconn->ev_ctx,
3198 : &req,
3199 : fsp,
3200 : 0,
3201 : false, /* large_offset */
3202 : 1,
3203 : lck);
3204 84 : if (subreq == NULL) {
3205 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
3206 0 : END_PROFILE(SMBlockread);
3207 0 : return;
3208 : }
3209 84 : tevent_req_set_callback(subreq, reply_lockread_locked, NULL);
3210 84 : END_PROFILE(SMBlockread);
3211 : }
3212 :
3213 84 : static void reply_lockread_locked(struct tevent_req *subreq)
3214 : {
3215 84 : struct smb_request *req = NULL;
3216 84 : ssize_t nread = -1;
3217 84 : char *data = NULL;
3218 12 : NTSTATUS status;
3219 12 : bool ok;
3220 12 : off_t startpos;
3221 12 : size_t numtoread, maxtoread;
3222 84 : struct files_struct *fsp = NULL;
3223 84 : char *p = NULL;
3224 :
3225 84 : START_PROFILE(SMBlockread);
3226 :
3227 84 : ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
3228 84 : SMB_ASSERT(ok);
3229 :
3230 84 : status = smbd_smb1_do_locks_recv(subreq);
3231 84 : TALLOC_FREE(subreq);
3232 :
3233 84 : if (!NT_STATUS_IS_OK(status)) {
3234 42 : reply_nterror(req, status);
3235 42 : goto send;
3236 : }
3237 :
3238 42 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3239 42 : if (fsp == NULL) {
3240 0 : reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
3241 0 : goto send;
3242 : }
3243 :
3244 42 : numtoread = SVAL(req->vwv+1, 0);
3245 42 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3246 :
3247 : /*
3248 : * However the requested READ size IS affected by max_send. Insanity.... JRA.
3249 : */
3250 42 : maxtoread = req->xconn->smb1.sessions.max_send - (MIN_SMB_SIZE + 5*2 + 3);
3251 :
3252 42 : if (numtoread > maxtoread) {
3253 7 : DBG_WARNING("requested read size (%zu) is greater than "
3254 : "maximum allowed (%zu/%d). "
3255 : "Returning short read of maximum allowed for "
3256 : "compatibility with Windows 2000.\n",
3257 : numtoread,
3258 : maxtoread,
3259 : req->xconn->smb1.sessions.max_send);
3260 6 : numtoread = maxtoread;
3261 : }
3262 :
3263 42 : reply_smb1_outbuf(req, 5, numtoread + 3);
3264 :
3265 42 : data = smb_buf(req->outbuf) + 3;
3266 :
3267 42 : nread = read_file(fsp,data,startpos,numtoread);
3268 :
3269 42 : if (nread < 0) {
3270 0 : reply_nterror(req, map_nt_error_from_unix(errno));
3271 0 : goto send;
3272 : }
3273 :
3274 42 : srv_smb1_set_message((char *)req->outbuf, 5, nread+3, False);
3275 :
3276 42 : SSVAL(req->outbuf,smb_vwv0,nread);
3277 42 : SSVAL(req->outbuf,smb_vwv5,nread+3);
3278 42 : p = smb_buf(req->outbuf);
3279 42 : SCVAL(p,0,0); /* pad byte. */
3280 42 : SSVAL(p,1,nread);
3281 :
3282 42 : DEBUG(3,("lockread %s num=%d nread=%d\n",
3283 : fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3284 :
3285 84 : send:
3286 108 : ok = smb1_srv_send(req->xconn,
3287 84 : (char *)req->outbuf,
3288 : true,
3289 84 : req->seqnum + 1,
3290 84 : IS_CONN_ENCRYPTED(req->conn));
3291 84 : if (!ok) {
3292 0 : exit_server_cleanly("reply_lock_done: smb1_srv_send failed.");
3293 : }
3294 84 : TALLOC_FREE(req);
3295 84 : END_PROFILE(SMBlockread);
3296 84 : return;
3297 : }
3298 :
3299 : #undef DBGC_CLASS
3300 : #define DBGC_CLASS DBGC_ALL
3301 :
3302 : /****************************************************************************
3303 : Reply to a read.
3304 : ****************************************************************************/
3305 :
3306 56 : void reply_read(struct smb_request *req)
3307 : {
3308 56 : connection_struct *conn = req->conn;
3309 8 : size_t numtoread;
3310 8 : size_t maxtoread;
3311 56 : ssize_t nread = 0;
3312 8 : char *data;
3313 8 : off_t startpos;
3314 8 : files_struct *fsp;
3315 8 : struct lock_struct lock;
3316 56 : struct smbXsrv_connection *xconn = req->xconn;
3317 :
3318 56 : START_PROFILE(SMBread);
3319 :
3320 56 : if (req->wct < 3) {
3321 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3322 0 : END_PROFILE(SMBread);
3323 0 : return;
3324 : }
3325 :
3326 56 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3327 :
3328 56 : if (!check_fsp(conn, req, fsp)) {
3329 7 : END_PROFILE(SMBread);
3330 7 : return;
3331 : }
3332 :
3333 49 : if (!CHECK_READ(fsp,req)) {
3334 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3335 0 : END_PROFILE(SMBread);
3336 0 : return;
3337 : }
3338 :
3339 49 : numtoread = SVAL(req->vwv+1, 0);
3340 49 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3341 :
3342 : /*
3343 : * The requested read size cannot be greater than max_send. JRA.
3344 : */
3345 49 : maxtoread = xconn->smb1.sessions.max_send - (MIN_SMB_SIZE + 5*2 + 3);
3346 :
3347 49 : if (numtoread > maxtoread) {
3348 14 : DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3349 : Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3350 : (unsigned int)numtoread, (unsigned int)maxtoread,
3351 : (unsigned int)xconn->smb1.sessions.max_send));
3352 12 : numtoread = maxtoread;
3353 : }
3354 :
3355 49 : reply_smb1_outbuf(req, 5, numtoread+3);
3356 :
3357 49 : data = smb_buf(req->outbuf) + 3;
3358 :
3359 49 : init_strict_lock_struct(fsp,
3360 49 : (uint64_t)req->smbpid,
3361 : (uint64_t)startpos,
3362 : (uint64_t)numtoread,
3363 : READ_LOCK,
3364 : lp_posix_cifsu_locktype(fsp),
3365 : &lock);
3366 :
3367 49 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3368 7 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3369 7 : END_PROFILE(SMBread);
3370 7 : return;
3371 : }
3372 :
3373 42 : if (numtoread > 0)
3374 35 : nread = read_file(fsp,data,startpos,numtoread);
3375 :
3376 41 : if (nread < 0) {
3377 0 : reply_nterror(req, map_nt_error_from_unix(errno));
3378 0 : goto out;
3379 : }
3380 :
3381 42 : srv_smb1_set_message((char *)req->outbuf, 5, nread+3, False);
3382 :
3383 42 : SSVAL(req->outbuf,smb_vwv0,nread);
3384 42 : SSVAL(req->outbuf,smb_vwv5,nread+3);
3385 42 : SCVAL(smb_buf(req->outbuf),0,1);
3386 42 : SSVAL(smb_buf(req->outbuf),1,nread);
3387 :
3388 42 : DEBUG(3, ("read %s num=%d nread=%d\n",
3389 : fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3390 :
3391 42 : out:
3392 42 : END_PROFILE(SMBread);
3393 36 : return;
3394 : }
3395 :
3396 : /****************************************************************************
3397 : Setup readX header.
3398 : ****************************************************************************/
3399 :
3400 9420 : size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
3401 : {
3402 45 : size_t outsize;
3403 :
3404 9420 : outsize = srv_smb1_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3405 : False);
3406 :
3407 9420 : memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3408 :
3409 9420 : SCVAL(outbuf,smb_vwv0,0xFF);
3410 9420 : SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3411 9420 : SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3412 9420 : SSVAL(outbuf,smb_vwv6,
3413 : (smb_wct - 4) /* offset from smb header to wct */
3414 : + 1 /* the wct field */
3415 : + 12 * sizeof(uint16_t) /* vwv */
3416 : + 2 /* the buflen field */
3417 : + 1); /* padding byte */
3418 9420 : SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3419 9420 : SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3420 : /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3421 9420 : _smb_setlen_large(outbuf,
3422 : smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3423 9420 : return outsize;
3424 : }
3425 :
3426 : /****************************************************************************
3427 : Reply to a read and X - possibly using sendfile.
3428 : ****************************************************************************/
3429 :
3430 65 : static void send_file_readX(connection_struct *conn, struct smb_request *req,
3431 : files_struct *fsp, off_t startpos,
3432 : size_t smb_maxcnt)
3433 : {
3434 65 : struct smbXsrv_connection *xconn = req->xconn;
3435 65 : ssize_t nread = -1;
3436 3 : struct lock_struct lock;
3437 65 : int saved_errno = 0;
3438 3 : NTSTATUS status;
3439 :
3440 65 : init_strict_lock_struct(fsp,
3441 65 : (uint64_t)req->smbpid,
3442 : (uint64_t)startpos,
3443 : (uint64_t)smb_maxcnt,
3444 : READ_LOCK,
3445 : lp_posix_cifsu_locktype(fsp),
3446 : &lock);
3447 :
3448 65 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3449 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3450 0 : return;
3451 : }
3452 :
3453 : /*
3454 : * We can only use sendfile on a non-chained packet
3455 : * but we can use on a non-oplocked file. tridge proved this
3456 : * on a train in Germany :-). JRA.
3457 : */
3458 :
3459 65 : if (!req_is_in_chain(req) &&
3460 56 : !req->encrypted &&
3461 82 : !fsp_is_alternate_stream(fsp) &&
3462 27 : lp_use_sendfile(xconn, SNUM(conn), xconn->smb1.signing_state) ) {
3463 0 : uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3464 0 : DATA_BLOB header;
3465 :
3466 0 : status = vfs_stat_fsp(fsp);
3467 0 : if (!NT_STATUS_IS_OK(status)) {
3468 0 : reply_nterror(req, status);
3469 0 : goto out;
3470 : }
3471 :
3472 0 : if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3473 0 : (startpos > fsp->fsp_name->st.st_ex_size) ||
3474 0 : (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3475 : /*
3476 : * We already know that we would do a short read, so don't
3477 : * try the sendfile() path.
3478 : */
3479 0 : goto nosendfile_read;
3480 : }
3481 :
3482 : /*
3483 : * Set up the packet header before send. We
3484 : * assume here the sendfile will work (get the
3485 : * correct amount of data).
3486 : */
3487 :
3488 0 : header = data_blob_const(headerbuf, sizeof(headerbuf));
3489 :
3490 0 : construct_smb1_reply_common_req(req, (char *)headerbuf);
3491 0 : setup_readX_header((char *)headerbuf, smb_maxcnt);
3492 :
3493 0 : nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
3494 : startpos, smb_maxcnt);
3495 0 : if (nread == -1) {
3496 0 : saved_errno = errno;
3497 :
3498 : /* Returning ENOSYS means no data at all was sent.
3499 : Do this as a normal read. */
3500 0 : if (errno == ENOSYS) {
3501 0 : goto normal_read;
3502 : }
3503 :
3504 : /*
3505 : * Special hack for broken Linux with no working sendfile. If we
3506 : * return EINTR we sent the header but not the rest of the data.
3507 : * Fake this up by doing read/write calls.
3508 : */
3509 :
3510 0 : if (errno == EINTR) {
3511 : /* Ensure we don't do this again. */
3512 0 : set_use_sendfile(SNUM(conn), False);
3513 0 : DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3514 0 : nread = fake_sendfile(xconn, fsp, startpos,
3515 : smb_maxcnt);
3516 0 : if (nread == -1) {
3517 0 : saved_errno = errno;
3518 0 : DEBUG(0,("send_file_readX: "
3519 : "fake_sendfile failed for "
3520 : "file %s (%s) for client %s. "
3521 : "Terminating\n",
3522 : fsp_str_dbg(fsp),
3523 : smbXsrv_connection_dbg(xconn),
3524 : strerror(saved_errno)));
3525 0 : errno = saved_errno;
3526 0 : exit_server_cleanly("send_file_readX: fake_sendfile failed");
3527 : }
3528 0 : DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3529 : fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3530 : /* No outbuf here means successful sendfile. */
3531 0 : goto out;
3532 : }
3533 :
3534 0 : DEBUG(0,("send_file_readX: sendfile failed for file "
3535 : "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3536 : strerror(errno)));
3537 0 : exit_server_cleanly("send_file_readX sendfile failed");
3538 0 : } else if (nread == 0) {
3539 : /*
3540 : * Some sendfile implementations return 0 to indicate
3541 : * that there was a short read, but nothing was
3542 : * actually written to the socket. In this case,
3543 : * fallback to the normal read path so the header gets
3544 : * the correct byte count.
3545 : */
3546 0 : DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3547 : "falling back to the normal read: %s\n",
3548 : fsp_str_dbg(fsp)));
3549 0 : goto normal_read;
3550 : }
3551 :
3552 0 : DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3553 : fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3554 :
3555 : /* Deal with possible short send. */
3556 0 : if (nread != smb_maxcnt + sizeof(headerbuf)) {
3557 0 : ssize_t ret;
3558 :
3559 0 : ret = sendfile_short_send(xconn, fsp, nread,
3560 : sizeof(headerbuf), smb_maxcnt);
3561 0 : if (ret == -1) {
3562 0 : const char *r;
3563 0 : r = "send_file_readX: sendfile_short_send failed";
3564 0 : DEBUG(0,("%s for file %s (%s).\n",
3565 : r, fsp_str_dbg(fsp), strerror(errno)));
3566 0 : exit_server_cleanly(r);
3567 : }
3568 : }
3569 : /* No outbuf here means successful sendfile. */
3570 0 : goto out;
3571 : }
3572 :
3573 65 : normal_read:
3574 :
3575 65 : if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3576 0 : uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
3577 0 : ssize_t ret;
3578 :
3579 12 : if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3580 12 : (startpos > fsp->fsp_name->st.st_ex_size) ||
3581 12 : (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3582 : /*
3583 : * We already know that we would do a short
3584 : * read, so don't try the sendfile() path.
3585 : */
3586 0 : goto nosendfile_read;
3587 : }
3588 :
3589 12 : construct_smb1_reply_common_req(req, (char *)headerbuf);
3590 12 : setup_readX_header((char *)headerbuf, smb_maxcnt);
3591 :
3592 : /* Send out the header. */
3593 12 : ret = write_data(xconn->transport.sock, (char *)headerbuf,
3594 : sizeof(headerbuf));
3595 12 : if (ret != sizeof(headerbuf)) {
3596 0 : saved_errno = errno;
3597 : /*
3598 : * Try and give an error message saying what
3599 : * client failed.
3600 : */
3601 0 : DEBUG(0,("send_file_readX: write_data failed for file "
3602 : "%s (%s) for client %s. Terminating\n",
3603 : fsp_str_dbg(fsp),
3604 : smbXsrv_connection_dbg(xconn),
3605 : strerror(saved_errno)));
3606 0 : errno = saved_errno;
3607 0 : exit_server_cleanly("send_file_readX sendfile failed");
3608 : }
3609 12 : nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
3610 12 : if (nread == -1) {
3611 0 : saved_errno = errno;
3612 0 : DEBUG(0,("send_file_readX: fake_sendfile failed for file "
3613 : "%s (%s) for client %s. Terminating\n",
3614 : fsp_str_dbg(fsp),
3615 : smbXsrv_connection_dbg(xconn),
3616 : strerror(saved_errno)));
3617 0 : errno = saved_errno;
3618 0 : exit_server_cleanly("send_file_readX: fake_sendfile failed");
3619 : }
3620 12 : goto out;
3621 : }
3622 :
3623 53 : nosendfile_read:
3624 :
3625 53 : reply_smb1_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
3626 53 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3627 53 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3628 :
3629 53 : nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
3630 : startpos, smb_maxcnt);
3631 53 : saved_errno = errno;
3632 :
3633 53 : if (nread < 0) {
3634 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
3635 0 : return;
3636 : }
3637 :
3638 53 : setup_readX_header((char *)req->outbuf, nread);
3639 :
3640 53 : DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3641 : fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3642 50 : return;
3643 :
3644 12 : out:
3645 12 : TALLOC_FREE(req->outbuf);
3646 12 : return;
3647 : }
3648 :
3649 : /****************************************************************************
3650 : Work out how much space we have for a read return.
3651 : ****************************************************************************/
3652 :
3653 9441 : static size_t calc_max_read_pdu(const struct smb_request *req)
3654 : {
3655 9441 : struct smbXsrv_connection *xconn = req->xconn;
3656 :
3657 9441 : if (xconn->protocol < PROTOCOL_NT1) {
3658 0 : return xconn->smb1.sessions.max_send;
3659 : }
3660 :
3661 9441 : if (!lp_large_readwrite()) {
3662 0 : return xconn->smb1.sessions.max_send;
3663 : }
3664 :
3665 9441 : if (req_is_in_chain(req)) {
3666 10 : return xconn->smb1.sessions.max_send;
3667 : }
3668 :
3669 9431 : if (req->encrypted) {
3670 : /*
3671 : * Don't take encrypted traffic up to the
3672 : * limit. There are padding considerations
3673 : * that make that tricky.
3674 : */
3675 2959 : return xconn->smb1.sessions.max_send;
3676 : }
3677 :
3678 6472 : if (smb1_srv_is_signing_active(xconn)) {
3679 821 : return 0x1FFFF;
3680 : }
3681 :
3682 5607 : if (!lp_smb1_unix_extensions()) {
3683 0 : return 0x1FFFF;
3684 : }
3685 :
3686 : /*
3687 : * We can do ultra-large POSIX reads.
3688 : */
3689 5607 : return 0xFFFFFF;
3690 : }
3691 :
3692 : /****************************************************************************
3693 : Calculate how big a read can be. Copes with all clients. It's always
3694 : safe to return a short read - Windows does this.
3695 : ****************************************************************************/
3696 :
3697 9441 : static size_t calc_read_size(const struct smb_request *req,
3698 : size_t upper_size,
3699 : size_t lower_size)
3700 : {
3701 9441 : struct smbXsrv_connection *xconn = req->xconn;
3702 9441 : size_t max_pdu = calc_max_read_pdu(req);
3703 9441 : size_t total_size = 0;
3704 9441 : size_t hdr_len = MIN_SMB_SIZE + VWV(12);
3705 9441 : size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
3706 :
3707 : /*
3708 : * Windows explicitly ignores upper size of 0xFFFF.
3709 : * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
3710 : * We must do the same as these will never fit even in
3711 : * an extended size NetBIOS packet.
3712 : */
3713 9441 : if (upper_size == 0xFFFF) {
3714 6 : upper_size = 0;
3715 : }
3716 :
3717 9441 : if (xconn->protocol < PROTOCOL_NT1) {
3718 0 : upper_size = 0;
3719 : }
3720 :
3721 9441 : total_size = ((upper_size<<16) | lower_size);
3722 :
3723 : /*
3724 : * LARGE_READX test shows it's always safe to return
3725 : * a short read. Windows does so.
3726 : */
3727 9441 : return MIN(total_size, max_len);
3728 : }
3729 :
3730 : /****************************************************************************
3731 : Reply to a read and X.
3732 : ****************************************************************************/
3733 :
3734 9848 : void reply_read_and_X(struct smb_request *req)
3735 : {
3736 9848 : connection_struct *conn = req->conn;
3737 49 : files_struct *fsp;
3738 49 : off_t startpos;
3739 49 : size_t smb_maxcnt;
3740 49 : size_t upper_size;
3741 9848 : bool big_readX = False;
3742 : #if 0
3743 : size_t smb_mincnt = SVAL(req->vwv+6, 0);
3744 : #endif
3745 :
3746 9848 : START_PROFILE(SMBreadX);
3747 :
3748 9848 : if ((req->wct != 10) && (req->wct != 12)) {
3749 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3750 0 : return;
3751 : }
3752 :
3753 9848 : fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3754 9848 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3755 9848 : smb_maxcnt = SVAL(req->vwv+5, 0);
3756 :
3757 : /* If it's an IPC, pass off the pipe handler. */
3758 9848 : if (IS_IPC(conn)) {
3759 34 : reply_pipe_read_and_X(req);
3760 34 : END_PROFILE(SMBreadX);
3761 34 : return;
3762 : }
3763 :
3764 9814 : if (!check_fsp(conn, req, fsp)) {
3765 39 : END_PROFILE(SMBreadX);
3766 39 : return;
3767 : }
3768 :
3769 9775 : if (!CHECK_READ(fsp,req)) {
3770 334 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3771 334 : END_PROFILE(SMBreadX);
3772 334 : return;
3773 : }
3774 :
3775 9441 : upper_size = SVAL(req->vwv+7, 0);
3776 9441 : smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
3777 9441 : if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
3778 : /*
3779 : * This is a heuristic to avoid keeping large
3780 : * outgoing buffers around over long-lived aio
3781 : * requests.
3782 : */
3783 12 : big_readX = True;
3784 : }
3785 :
3786 9441 : if (req->wct == 12) {
3787 : /*
3788 : * This is a large offset (64 bit) read.
3789 : */
3790 9441 : startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
3791 :
3792 : }
3793 :
3794 9441 : if (!big_readX) {
3795 9429 : NTSTATUS status = schedule_aio_read_and_X(conn,
3796 : req,
3797 : fsp,
3798 : startpos,
3799 : smb_maxcnt);
3800 9429 : if (NT_STATUS_IS_OK(status)) {
3801 : /* Read scheduled - we're done. */
3802 9355 : goto out;
3803 : }
3804 74 : if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3805 : /* Real error - report to client. */
3806 21 : END_PROFILE(SMBreadX);
3807 21 : reply_nterror(req, status);
3808 21 : return;
3809 : }
3810 : /* NT_STATUS_RETRY - fall back to sync read. */
3811 : }
3812 :
3813 65 : smbd_lock_socket(req->xconn);
3814 65 : send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3815 65 : smbd_unlock_socket(req->xconn);
3816 :
3817 9420 : out:
3818 9420 : END_PROFILE(SMBreadX);
3819 9375 : return;
3820 : }
3821 :
3822 : /****************************************************************************
3823 : Error replies to writebraw must have smb_wct == 1. Fix this up.
3824 : ****************************************************************************/
3825 :
3826 0 : void error_to_writebrawerr(struct smb_request *req)
3827 : {
3828 0 : uint8_t *old_outbuf = req->outbuf;
3829 :
3830 0 : reply_smb1_outbuf(req, 1, 0);
3831 :
3832 0 : memcpy(req->outbuf, old_outbuf, smb_size);
3833 0 : TALLOC_FREE(old_outbuf);
3834 0 : }
3835 :
3836 : /****************************************************************************
3837 : Read 4 bytes of a smb packet and return the smb length of the packet.
3838 : Store the result in the buffer. This version of the function will
3839 : never return a session keepalive (length of zero).
3840 : Timeout is in milliseconds.
3841 : ****************************************************************************/
3842 :
3843 0 : static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3844 : size_t *len)
3845 : {
3846 0 : uint8_t msgtype = NBSSkeepalive;
3847 :
3848 0 : while (msgtype == NBSSkeepalive) {
3849 0 : NTSTATUS status;
3850 :
3851 0 : status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3852 : len);
3853 0 : if (!NT_STATUS_IS_OK(status)) {
3854 0 : char addr[INET6_ADDRSTRLEN];
3855 : /* Try and give an error message
3856 : * saying what client failed. */
3857 0 : DEBUG(0, ("read_smb_length_return_keepalive failed for "
3858 : "client %s read error = %s.\n",
3859 : get_peer_addr(fd,addr,sizeof(addr)),
3860 : nt_errstr(status)));
3861 0 : return status;
3862 : }
3863 :
3864 0 : msgtype = CVAL(inbuf, 0);
3865 : }
3866 :
3867 0 : DEBUG(10,("read_smb_length: got smb length of %lu\n",
3868 : (unsigned long)len));
3869 :
3870 0 : return NT_STATUS_OK;
3871 : }
3872 :
3873 : /****************************************************************************
3874 : Reply to a writebraw (core+ or LANMAN1.0 protocol).
3875 : ****************************************************************************/
3876 :
3877 0 : void reply_writebraw(struct smb_request *req)
3878 : {
3879 0 : connection_struct *conn = req->conn;
3880 0 : struct smbXsrv_connection *xconn = req->xconn;
3881 0 : char *buf = NULL;
3882 0 : ssize_t nwritten=0;
3883 0 : ssize_t total_written=0;
3884 0 : size_t numtowrite=0;
3885 0 : size_t tcount;
3886 0 : off_t startpos;
3887 0 : const char *data=NULL;
3888 0 : bool write_through;
3889 0 : files_struct *fsp;
3890 0 : struct lock_struct lock;
3891 0 : NTSTATUS status;
3892 :
3893 0 : START_PROFILE(SMBwritebraw);
3894 :
3895 : /*
3896 : * If we ever reply with an error, it must have the SMB command
3897 : * type of SMBwritec, not SMBwriteBraw, as this tells the client
3898 : * we're finished.
3899 : */
3900 0 : SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
3901 :
3902 0 : if (smb1_srv_is_signing_active(xconn)) {
3903 0 : END_PROFILE(SMBwritebraw);
3904 0 : exit_server_cleanly("reply_writebraw: SMB signing is active - "
3905 : "raw reads/writes are disallowed.");
3906 : }
3907 :
3908 0 : if (req->wct < 12) {
3909 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3910 0 : error_to_writebrawerr(req);
3911 0 : END_PROFILE(SMBwritebraw);
3912 0 : return;
3913 : }
3914 :
3915 0 : if (xconn->smb1.echo_handler.trusted_fde) {
3916 0 : DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3917 : "'async smb echo handler = yes'\n"));
3918 0 : reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3919 0 : error_to_writebrawerr(req);
3920 0 : END_PROFILE(SMBwritebraw);
3921 0 : return;
3922 : }
3923 :
3924 0 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3925 0 : if (!check_fsp(conn, req, fsp)) {
3926 0 : error_to_writebrawerr(req);
3927 0 : END_PROFILE(SMBwritebraw);
3928 0 : return;
3929 : }
3930 :
3931 0 : status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
3932 0 : if (!NT_STATUS_IS_OK(status)) {
3933 0 : reply_nterror(req, status);
3934 0 : error_to_writebrawerr(req);
3935 0 : END_PROFILE(SMBwritebraw);
3936 0 : return;
3937 : }
3938 :
3939 0 : tcount = IVAL(req->vwv+1, 0);
3940 0 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3941 0 : write_through = BITSETW(req->vwv+7,0);
3942 :
3943 : /* We have to deal with slightly different formats depending
3944 : on whether we are using the core+ or lanman1.0 protocol */
3945 :
3946 0 : if(xconn->protocol <= PROTOCOL_COREPLUS) {
3947 0 : numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
3948 0 : data = smb_buf_const(req->inbuf);
3949 : } else {
3950 0 : numtowrite = SVAL(req->vwv+10, 0);
3951 0 : data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3952 : }
3953 :
3954 : /* Ensure we don't write bytes past the end of this packet. */
3955 : /*
3956 : * This already protects us against CVE-2017-12163.
3957 : */
3958 0 : if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3959 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3960 0 : error_to_writebrawerr(req);
3961 0 : END_PROFILE(SMBwritebraw);
3962 0 : return;
3963 : }
3964 :
3965 0 : if (!fsp->print_file) {
3966 0 : init_strict_lock_struct(fsp,
3967 0 : (uint64_t)req->smbpid,
3968 : (uint64_t)startpos,
3969 : (uint64_t)tcount,
3970 : WRITE_LOCK,
3971 : lp_posix_cifsu_locktype(fsp),
3972 : &lock);
3973 :
3974 0 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3975 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3976 0 : error_to_writebrawerr(req);
3977 0 : END_PROFILE(SMBwritebraw);
3978 0 : return;
3979 : }
3980 : }
3981 :
3982 0 : if (numtowrite>0) {
3983 0 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
3984 : }
3985 :
3986 0 : DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
3987 : "wrote=%d sync=%d\n",
3988 : fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
3989 : (int)nwritten, (int)write_through));
3990 :
3991 0 : if (nwritten < (ssize_t)numtowrite) {
3992 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
3993 0 : error_to_writebrawerr(req);
3994 0 : goto out;
3995 : }
3996 :
3997 0 : total_written = nwritten;
3998 :
3999 : /* Allocate a buffer of 64k + length. */
4000 0 : buf = talloc_array(NULL, char, 65540);
4001 0 : if (!buf) {
4002 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4003 0 : error_to_writebrawerr(req);
4004 0 : goto out;
4005 : }
4006 :
4007 : /* Return a SMBwritebraw message to the redirector to tell
4008 : * it to send more bytes */
4009 :
4010 0 : memcpy(buf, req->inbuf, smb_size);
4011 0 : srv_smb1_set_message(buf,xconn->protocol>PROTOCOL_COREPLUS?1:0,0,True);
4012 0 : SCVAL(buf,smb_com,SMBwritebraw);
4013 0 : SSVALS(buf,smb_vwv0,0xFFFF);
4014 0 : show_msg(buf);
4015 0 : if (!smb1_srv_send(req->xconn,
4016 : buf,
4017 : false,
4018 : 0, /* no signing */
4019 0 : IS_CONN_ENCRYPTED(conn))) {
4020 0 : exit_server_cleanly("reply_writebraw: smb1_srv_send "
4021 : "failed.");
4022 : }
4023 :
4024 : /* Now read the raw data into the buffer and write it */
4025 0 : status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4026 : &numtowrite);
4027 0 : if (!NT_STATUS_IS_OK(status)) {
4028 0 : exit_server_cleanly("secondary writebraw failed");
4029 : }
4030 :
4031 : /* Set up outbuf to return the correct size */
4032 0 : reply_smb1_outbuf(req, 1, 0);
4033 :
4034 0 : if (numtowrite != 0) {
4035 :
4036 0 : if (numtowrite > 0xFFFF) {
4037 0 : DEBUG(0,("reply_writebraw: Oversize secondary write "
4038 : "raw requested (%u). Terminating\n",
4039 : (unsigned int)numtowrite ));
4040 0 : exit_server_cleanly("secondary writebraw failed");
4041 : }
4042 :
4043 0 : if (tcount > nwritten+numtowrite) {
4044 0 : DEBUG(3,("reply_writebraw: Client overestimated the "
4045 : "write %d %d %d\n",
4046 : (int)tcount,(int)nwritten,(int)numtowrite));
4047 : }
4048 :
4049 0 : status = read_data_ntstatus(xconn->transport.sock, buf+4,
4050 : numtowrite);
4051 :
4052 0 : if (!NT_STATUS_IS_OK(status)) {
4053 : /* Try and give an error message
4054 : * saying what client failed. */
4055 0 : DEBUG(0, ("reply_writebraw: Oversize secondary write "
4056 : "raw read failed (%s) for client %s. "
4057 : "Terminating\n", nt_errstr(status),
4058 : smbXsrv_connection_dbg(xconn)));
4059 0 : exit_server_cleanly("secondary writebraw failed");
4060 : }
4061 :
4062 : /*
4063 : * We are not vulnerable to CVE-2017-12163
4064 : * here as we are guaranteed to have numtowrite
4065 : * bytes available - we just read from the client.
4066 : */
4067 0 : nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4068 0 : if (nwritten == -1) {
4069 0 : TALLOC_FREE(buf);
4070 0 : reply_nterror(req, map_nt_error_from_unix(errno));
4071 0 : error_to_writebrawerr(req);
4072 0 : goto out;
4073 : }
4074 :
4075 0 : if (nwritten < (ssize_t)numtowrite) {
4076 0 : SCVAL(req->outbuf,smb_rcls,ERRHRD);
4077 0 : SSVAL(req->outbuf,smb_err,ERRdiskfull);
4078 : }
4079 :
4080 0 : if (nwritten > 0) {
4081 0 : total_written += nwritten;
4082 : }
4083 : }
4084 :
4085 0 : TALLOC_FREE(buf);
4086 0 : SSVAL(req->outbuf,smb_vwv0,total_written);
4087 :
4088 0 : status = sync_file(conn, fsp, write_through);
4089 0 : if (!NT_STATUS_IS_OK(status)) {
4090 0 : DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4091 : fsp_str_dbg(fsp), nt_errstr(status)));
4092 0 : reply_nterror(req, status);
4093 0 : error_to_writebrawerr(req);
4094 0 : goto out;
4095 : }
4096 :
4097 0 : DEBUG(3,("reply_writebraw: secondary write %s start=%.0f num=%d "
4098 : "wrote=%d\n",
4099 : fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4100 : (int)total_written));
4101 :
4102 : /* We won't return a status if write through is not selected - this
4103 : * follows what WfWg does */
4104 0 : END_PROFILE(SMBwritebraw);
4105 :
4106 0 : if (!write_through && total_written==tcount) {
4107 :
4108 : #if RABBIT_PELLET_FIX
4109 : /*
4110 : * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4111 : * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4112 : * JRA.
4113 : */
4114 0 : if (!send_keepalive(xconn->transport.sock)) {
4115 0 : exit_server_cleanly("reply_writebraw: send of "
4116 : "keepalive failed");
4117 : }
4118 : #endif
4119 0 : TALLOC_FREE(req->outbuf);
4120 : }
4121 0 : return;
4122 :
4123 0 : out:
4124 0 : END_PROFILE(SMBwritebraw);
4125 0 : return;
4126 : }
4127 :
4128 : #undef DBGC_CLASS
4129 : #define DBGC_CLASS DBGC_LOCKING
4130 :
4131 : /****************************************************************************
4132 : Reply to a writeunlock (core+).
4133 : ****************************************************************************/
4134 :
4135 35 : void reply_writeunlock(struct smb_request *req)
4136 : {
4137 35 : connection_struct *conn = req->conn;
4138 35 : ssize_t nwritten = -1;
4139 7 : size_t numtowrite;
4140 7 : size_t remaining;
4141 7 : off_t startpos;
4142 7 : const char *data;
4143 35 : NTSTATUS status = NT_STATUS_OK;
4144 7 : files_struct *fsp;
4145 7 : struct lock_struct lock;
4146 35 : int saved_errno = 0;
4147 :
4148 35 : START_PROFILE(SMBwriteunlock);
4149 :
4150 35 : if (req->wct < 5) {
4151 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4152 0 : END_PROFILE(SMBwriteunlock);
4153 0 : return;
4154 : }
4155 :
4156 35 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4157 :
4158 35 : if (!check_fsp(conn, req, fsp)) {
4159 5 : END_PROFILE(SMBwriteunlock);
4160 5 : return;
4161 : }
4162 :
4163 30 : status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
4164 30 : if (!NT_STATUS_IS_OK(status)) {
4165 0 : reply_nterror(req, status);
4166 0 : END_PROFILE(SMBwriteunlock);
4167 0 : return;
4168 : }
4169 :
4170 30 : numtowrite = SVAL(req->vwv+1, 0);
4171 30 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4172 30 : data = (const char *)req->buf + 3;
4173 :
4174 : /*
4175 : * Ensure client isn't asking us to write more than
4176 : * they sent. CVE-2017-12163.
4177 : */
4178 30 : remaining = smbreq_bufrem(req, data);
4179 30 : if (numtowrite > remaining) {
4180 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4181 0 : END_PROFILE(SMBwriteunlock);
4182 0 : return;
4183 : }
4184 :
4185 30 : if (!fsp->print_file && numtowrite > 0) {
4186 25 : init_strict_lock_struct(fsp,
4187 25 : (uint64_t)req->smbpid,
4188 : (uint64_t)startpos,
4189 : (uint64_t)numtowrite,
4190 : WRITE_LOCK,
4191 : lp_posix_cifsu_locktype(fsp),
4192 : &lock);
4193 :
4194 25 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4195 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4196 0 : END_PROFILE(SMBwriteunlock);
4197 0 : return;
4198 : }
4199 : }
4200 :
4201 : /* The special X/Open SMB protocol handling of
4202 : zero length writes is *NOT* done for
4203 : this call */
4204 30 : if(numtowrite == 0) {
4205 4 : nwritten = 0;
4206 : } else {
4207 25 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
4208 25 : saved_errno = errno;
4209 : }
4210 :
4211 30 : status = sync_file(conn, fsp, False /* write through */);
4212 30 : if (!NT_STATUS_IS_OK(status)) {
4213 0 : DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4214 : fsp_str_dbg(fsp), nt_errstr(status)));
4215 0 : reply_nterror(req, status);
4216 0 : goto out;
4217 : }
4218 :
4219 30 : if(nwritten < 0) {
4220 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
4221 0 : goto out;
4222 : }
4223 :
4224 30 : if((nwritten < numtowrite) && (numtowrite != 0)) {
4225 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
4226 0 : goto out;
4227 : }
4228 :
4229 30 : if (numtowrite && !fsp->print_file) {
4230 30 : struct smbd_lock_element l = {
4231 25 : .req_guid = smbd_request_guid(req, 0),
4232 25 : .smblctx = req->smbpid,
4233 : .brltype = UNLOCK_LOCK,
4234 : .lock_flav = WINDOWS_LOCK,
4235 : .offset = startpos,
4236 : .count = numtowrite,
4237 : };
4238 25 : status = smbd_do_unlocking(req, fsp, 1, &l);
4239 25 : if (NT_STATUS_V(status)) {
4240 10 : reply_nterror(req, status);
4241 10 : goto out;
4242 : }
4243 : }
4244 :
4245 20 : reply_smb1_outbuf(req, 1, 0);
4246 :
4247 20 : SSVAL(req->outbuf,smb_vwv0,nwritten);
4248 :
4249 20 : DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4250 : fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4251 :
4252 30 : out:
4253 30 : END_PROFILE(SMBwriteunlock);
4254 24 : return;
4255 : }
4256 :
4257 : #undef DBGC_CLASS
4258 : #define DBGC_CLASS DBGC_ALL
4259 :
4260 : /****************************************************************************
4261 : Reply to a write.
4262 : ****************************************************************************/
4263 :
4264 204 : void reply_write(struct smb_request *req)
4265 : {
4266 204 : connection_struct *conn = req->conn;
4267 6 : size_t numtowrite;
4268 6 : size_t remaining;
4269 204 : ssize_t nwritten = -1;
4270 6 : off_t startpos;
4271 6 : const char *data;
4272 6 : files_struct *fsp;
4273 6 : struct lock_struct lock;
4274 6 : NTSTATUS status;
4275 204 : int saved_errno = 0;
4276 :
4277 204 : START_PROFILE(SMBwrite);
4278 :
4279 204 : if (req->wct < 5) {
4280 0 : END_PROFILE(SMBwrite);
4281 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4282 0 : return;
4283 : }
4284 :
4285 : /* If it's an IPC, pass off the pipe handler. */
4286 204 : if (IS_IPC(conn)) {
4287 0 : reply_pipe_write(req);
4288 0 : END_PROFILE(SMBwrite);
4289 0 : return;
4290 : }
4291 :
4292 204 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4293 :
4294 204 : if (!check_fsp(conn, req, fsp)) {
4295 5 : END_PROFILE(SMBwrite);
4296 5 : return;
4297 : }
4298 :
4299 199 : status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
4300 199 : if (!NT_STATUS_IS_OK(status)) {
4301 0 : reply_nterror(req, status);
4302 0 : END_PROFILE(SMBwrite);
4303 0 : return;
4304 : }
4305 :
4306 199 : numtowrite = SVAL(req->vwv+1, 0);
4307 199 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4308 199 : data = (const char *)req->buf + 3;
4309 :
4310 : /*
4311 : * Ensure client isn't asking us to write more than
4312 : * they sent. CVE-2017-12163.
4313 : */
4314 199 : remaining = smbreq_bufrem(req, data);
4315 199 : if (numtowrite > remaining) {
4316 5 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4317 5 : END_PROFILE(SMBwrite);
4318 5 : return;
4319 : }
4320 :
4321 194 : if (!fsp->print_file) {
4322 194 : init_strict_lock_struct(fsp,
4323 194 : (uint64_t)req->smbpid,
4324 : (uint64_t)startpos,
4325 : (uint64_t)numtowrite,
4326 : WRITE_LOCK,
4327 : lp_posix_cifsu_locktype(fsp),
4328 : &lock);
4329 :
4330 194 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4331 4 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4332 4 : END_PROFILE(SMBwrite);
4333 4 : return;
4334 : }
4335 : }
4336 :
4337 : /*
4338 : * X/Open SMB protocol says that if smb_vwv1 is
4339 : * zero then the file size should be extended or
4340 : * truncated to the size given in smb_vwv[2-3].
4341 : */
4342 :
4343 190 : if(numtowrite == 0) {
4344 : /*
4345 : * This is actually an allocate call, and set EOF. JRA.
4346 : */
4347 57 : nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4348 57 : if (nwritten < 0) {
4349 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
4350 0 : goto out;
4351 : }
4352 57 : nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4353 57 : if (nwritten < 0) {
4354 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
4355 0 : goto out;
4356 : }
4357 57 : trigger_write_time_update_immediate(fsp);
4358 : } else {
4359 133 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
4360 : }
4361 :
4362 190 : status = sync_file(conn, fsp, False);
4363 190 : if (!NT_STATUS_IS_OK(status)) {
4364 0 : DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4365 : fsp_str_dbg(fsp), nt_errstr(status)));
4366 0 : reply_nterror(req, status);
4367 0 : goto out;
4368 : }
4369 :
4370 190 : if(nwritten < 0) {
4371 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
4372 0 : goto out;
4373 : }
4374 :
4375 190 : if((nwritten == 0) && (numtowrite != 0)) {
4376 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
4377 0 : goto out;
4378 : }
4379 :
4380 190 : reply_smb1_outbuf(req, 1, 0);
4381 :
4382 190 : SSVAL(req->outbuf,smb_vwv0,nwritten);
4383 :
4384 190 : if (nwritten < (ssize_t)numtowrite) {
4385 0 : SCVAL(req->outbuf,smb_rcls,ERRHRD);
4386 0 : SSVAL(req->outbuf,smb_err,ERRdiskfull);
4387 : }
4388 :
4389 190 : DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4390 :
4391 190 : out:
4392 190 : END_PROFILE(SMBwrite);
4393 186 : return;
4394 : }
4395 :
4396 : /****************************************************************************
4397 : Ensure a buffer is a valid writeX for recvfile purposes.
4398 : ****************************************************************************/
4399 :
4400 : #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4401 : (2*14) + /* word count (including bcc) */ \
4402 : 1 /* pad byte */)
4403 :
4404 0 : bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4405 : const uint8_t *inbuf)
4406 : {
4407 0 : size_t numtowrite;
4408 0 : unsigned int doff = 0;
4409 0 : size_t len = smb_len_large(inbuf);
4410 0 : uint16_t fnum;
4411 0 : struct smbXsrv_open *op = NULL;
4412 0 : struct files_struct *fsp = NULL;
4413 0 : NTSTATUS status;
4414 :
4415 0 : if (is_encrypted_packet(inbuf)) {
4416 : /* Can't do this on encrypted
4417 : * connections. */
4418 0 : return false;
4419 : }
4420 :
4421 0 : if (CVAL(inbuf,smb_com) != SMBwriteX) {
4422 0 : return false;
4423 : }
4424 :
4425 0 : if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4426 0 : CVAL(inbuf,smb_wct) != 14) {
4427 0 : DEBUG(10,("is_valid_writeX_buffer: chained or "
4428 : "invalid word length.\n"));
4429 0 : return false;
4430 : }
4431 :
4432 0 : fnum = SVAL(inbuf, smb_vwv2);
4433 0 : status = smb1srv_open_lookup(xconn,
4434 : fnum,
4435 : 0, /* now */
4436 : &op);
4437 0 : if (!NT_STATUS_IS_OK(status)) {
4438 0 : DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4439 0 : return false;
4440 : }
4441 0 : fsp = op->compat;
4442 0 : if (fsp == NULL) {
4443 0 : DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4444 0 : return false;
4445 : }
4446 0 : if (fsp->conn == NULL) {
4447 0 : DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4448 0 : return false;
4449 : }
4450 :
4451 0 : if (IS_IPC(fsp->conn)) {
4452 0 : DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4453 0 : return false;
4454 : }
4455 0 : if (IS_PRINT(fsp->conn)) {
4456 0 : DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4457 0 : return false;
4458 : }
4459 0 : if (fsp_is_alternate_stream(fsp)) {
4460 0 : DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
4461 0 : return false;
4462 : }
4463 0 : doff = SVAL(inbuf,smb_vwv11);
4464 :
4465 0 : numtowrite = SVAL(inbuf,smb_vwv10);
4466 :
4467 0 : if (len > doff && len - doff > 0xFFFF) {
4468 0 : numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4469 : }
4470 :
4471 0 : if (numtowrite == 0) {
4472 0 : DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4473 0 : return false;
4474 : }
4475 :
4476 : /* Ensure the sizes match up. */
4477 0 : if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4478 : /* no pad byte...old smbclient :-( */
4479 0 : DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4480 : (unsigned int)doff,
4481 : (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4482 0 : return false;
4483 : }
4484 :
4485 0 : if (len - doff != numtowrite) {
4486 0 : DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4487 : "len = %u, doff = %u, numtowrite = %u\n",
4488 : (unsigned int)len,
4489 : (unsigned int)doff,
4490 : (unsigned int)numtowrite ));
4491 0 : return false;
4492 : }
4493 :
4494 0 : DEBUG(10,("is_valid_writeX_buffer: true "
4495 : "len = %u, doff = %u, numtowrite = %u\n",
4496 : (unsigned int)len,
4497 : (unsigned int)doff,
4498 : (unsigned int)numtowrite ));
4499 :
4500 0 : return true;
4501 : }
4502 :
4503 : /****************************************************************************
4504 : Reply to a write and X.
4505 : ****************************************************************************/
4506 :
4507 132870 : void reply_write_and_X(struct smb_request *req)
4508 : {
4509 132870 : connection_struct *conn = req->conn;
4510 132870 : struct smbXsrv_connection *xconn = req->xconn;
4511 59 : files_struct *fsp;
4512 59 : struct lock_struct lock;
4513 59 : off_t startpos;
4514 59 : size_t numtowrite;
4515 59 : bool write_through;
4516 59 : ssize_t nwritten;
4517 59 : unsigned int smb_doff;
4518 59 : unsigned int smblen;
4519 59 : const char *data;
4520 59 : NTSTATUS status;
4521 132870 : int saved_errno = 0;
4522 :
4523 132870 : START_PROFILE(SMBwriteX);
4524 :
4525 132870 : if ((req->wct != 12) && (req->wct != 14)) {
4526 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4527 0 : goto out;
4528 : }
4529 :
4530 132870 : numtowrite = SVAL(req->vwv+10, 0);
4531 132870 : smb_doff = SVAL(req->vwv+11, 0);
4532 132870 : smblen = smb_len(req->inbuf);
4533 :
4534 132870 : if (req->unread_bytes > 0xFFFF ||
4535 132865 : (smblen > smb_doff &&
4536 132865 : smblen - smb_doff > 0xFFFF)) {
4537 1379 : numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4538 : }
4539 :
4540 132870 : if (req->unread_bytes) {
4541 : /* Can't do a recvfile write on IPC$ */
4542 0 : if (IS_IPC(conn)) {
4543 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4544 0 : goto out;
4545 : }
4546 0 : if (numtowrite != req->unread_bytes) {
4547 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4548 0 : goto out;
4549 : }
4550 : } else {
4551 : /*
4552 : * This already protects us against CVE-2017-12163.
4553 : */
4554 132870 : if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4555 132870 : smb_doff + numtowrite > smblen) {
4556 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4557 0 : goto out;
4558 : }
4559 : }
4560 :
4561 : /* If it's an IPC, pass off the pipe handler. */
4562 132870 : if (IS_IPC(conn)) {
4563 8 : if (req->unread_bytes) {
4564 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4565 0 : goto out;
4566 : }
4567 8 : reply_pipe_write_and_X(req);
4568 8 : goto out;
4569 : }
4570 :
4571 132862 : fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4572 132862 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4573 132862 : write_through = BITSETW(req->vwv+7,0);
4574 :
4575 132862 : if (!check_fsp(conn, req, fsp)) {
4576 14 : goto out;
4577 : }
4578 :
4579 132848 : status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
4580 132848 : if (!NT_STATUS_IS_OK(status)) {
4581 286 : reply_nterror(req, status);
4582 286 : goto out;
4583 : }
4584 :
4585 132562 : data = smb_base(req->inbuf) + smb_doff;
4586 :
4587 132562 : if(req->wct == 14) {
4588 : /*
4589 : * This is a large offset (64 bit) write.
4590 : */
4591 132562 : startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4592 :
4593 : }
4594 :
4595 : /* X/Open SMB protocol says that, unlike SMBwrite
4596 : if the length is zero then NO truncation is
4597 : done, just a write of zero. To truncate a file,
4598 : use SMBwrite. */
4599 :
4600 132562 : if(numtowrite == 0) {
4601 4 : nwritten = 0;
4602 : } else {
4603 132557 : if (req->unread_bytes == 0) {
4604 132557 : status = schedule_aio_write_and_X(conn,
4605 : req,
4606 : fsp,
4607 : data,
4608 : startpos,
4609 : numtowrite);
4610 :
4611 132557 : if (NT_STATUS_IS_OK(status)) {
4612 : /* write scheduled - we're done. */
4613 132472 : goto out;
4614 : }
4615 85 : if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4616 : /* Real error - report to client. */
4617 45 : reply_nterror(req, status);
4618 45 : goto out;
4619 : }
4620 : /* NT_STATUS_RETRY - fall through to sync write. */
4621 : }
4622 :
4623 40 : init_strict_lock_struct(fsp,
4624 40 : (uint64_t)req->smbpid,
4625 : (uint64_t)startpos,
4626 : (uint64_t)numtowrite,
4627 : WRITE_LOCK,
4628 : lp_posix_cifsu_locktype(fsp),
4629 : &lock);
4630 :
4631 40 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4632 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4633 0 : goto out;
4634 : }
4635 :
4636 40 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
4637 40 : saved_errno = errno;
4638 : }
4639 :
4640 44 : if(nwritten < 0) {
4641 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
4642 0 : goto out;
4643 : }
4644 :
4645 45 : if((nwritten == 0) && (numtowrite != 0)) {
4646 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
4647 0 : goto out;
4648 : }
4649 :
4650 45 : reply_smb1_outbuf(req, 6, 0);
4651 45 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4652 45 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4653 45 : SSVAL(req->outbuf,smb_vwv2,nwritten);
4654 45 : SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4655 :
4656 45 : DEBUG(3,("writeX %s num=%d wrote=%d\n",
4657 : fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4658 :
4659 45 : status = sync_file(conn, fsp, write_through);
4660 45 : if (!NT_STATUS_IS_OK(status)) {
4661 0 : DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4662 : fsp_str_dbg(fsp), nt_errstr(status)));
4663 0 : reply_nterror(req, status);
4664 0 : goto out;
4665 : }
4666 :
4667 45 : END_PROFILE(SMBwriteX);
4668 44 : return;
4669 :
4670 132825 : out:
4671 132825 : if (req->unread_bytes) {
4672 : /* writeX failed. drain socket. */
4673 0 : if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
4674 0 : req->unread_bytes) {
4675 0 : smb_panic("failed to drain pending bytes");
4676 : }
4677 0 : req->unread_bytes = 0;
4678 : }
4679 :
4680 132825 : END_PROFILE(SMBwriteX);
4681 132767 : return;
4682 : }
4683 :
4684 : /****************************************************************************
4685 : Reply to a lseek.
4686 : ****************************************************************************/
4687 :
4688 40 : void reply_lseek(struct smb_request *req)
4689 : {
4690 40 : connection_struct *conn = req->conn;
4691 8 : off_t startpos;
4692 40 : off_t res= -1;
4693 8 : int mode,umode;
4694 8 : files_struct *fsp;
4695 8 : NTSTATUS status;
4696 :
4697 40 : START_PROFILE(SMBlseek);
4698 :
4699 40 : if (req->wct < 4) {
4700 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4701 0 : END_PROFILE(SMBlseek);
4702 0 : return;
4703 : }
4704 :
4705 40 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4706 :
4707 40 : if (!check_fsp(conn, req, fsp)) {
4708 4 : return;
4709 : }
4710 :
4711 35 : mode = SVAL(req->vwv+1, 0) & 3;
4712 : /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4713 35 : startpos = (off_t)IVALS(req->vwv+2, 0);
4714 :
4715 35 : switch (mode) {
4716 8 : case 0:
4717 8 : umode = SEEK_SET;
4718 8 : res = startpos;
4719 8 : break;
4720 20 : case 1:
4721 20 : umode = SEEK_CUR;
4722 20 : res = fh_get_pos(fsp->fh) + startpos;
4723 20 : break;
4724 4 : case 2:
4725 5 : umode = SEEK_END;
4726 5 : break;
4727 0 : default:
4728 0 : umode = SEEK_SET;
4729 0 : res = startpos;
4730 0 : break;
4731 : }
4732 :
4733 32 : if (umode == SEEK_END) {
4734 5 : if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4735 0 : if(errno == EINVAL) {
4736 0 : off_t current_pos = startpos;
4737 :
4738 0 : status = vfs_stat_fsp(fsp);
4739 0 : if (!NT_STATUS_IS_OK(status)) {
4740 0 : reply_nterror(req, status);
4741 0 : END_PROFILE(SMBlseek);
4742 0 : return;
4743 : }
4744 :
4745 0 : current_pos += fsp->fsp_name->st.st_ex_size;
4746 0 : if(current_pos < 0)
4747 0 : res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4748 : }
4749 : }
4750 :
4751 5 : if(res == -1) {
4752 0 : reply_nterror(req, map_nt_error_from_unix(errno));
4753 0 : END_PROFILE(SMBlseek);
4754 0 : return;
4755 : }
4756 : }
4757 :
4758 35 : fh_set_pos(fsp->fh, res);
4759 :
4760 35 : reply_smb1_outbuf(req, 2, 0);
4761 35 : SIVAL(req->outbuf,smb_vwv0,res);
4762 :
4763 35 : DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4764 : fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4765 :
4766 35 : END_PROFILE(SMBlseek);
4767 28 : return;
4768 : }
4769 :
4770 0 : static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
4771 : void *private_data)
4772 : {
4773 0 : connection_struct *conn = talloc_get_type_abort(
4774 : private_data, connection_struct);
4775 :
4776 0 : if (conn != fsp->conn) {
4777 0 : return NULL;
4778 : }
4779 0 : if (fsp_get_io_fd(fsp) == -1) {
4780 0 : return NULL;
4781 : }
4782 0 : sync_file(conn, fsp, True /* write through */);
4783 :
4784 0 : if (fsp->fsp_flags.modified) {
4785 0 : trigger_write_time_update_immediate(fsp);
4786 : }
4787 :
4788 0 : return NULL;
4789 : }
4790 :
4791 : /****************************************************************************
4792 : Reply to a flush.
4793 : ****************************************************************************/
4794 :
4795 22 : void reply_flush(struct smb_request *req)
4796 : {
4797 22 : connection_struct *conn = req->conn;
4798 4 : uint16_t fnum;
4799 4 : files_struct *fsp;
4800 :
4801 22 : START_PROFILE(SMBflush);
4802 :
4803 22 : if (req->wct < 1) {
4804 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4805 0 : return;
4806 : }
4807 :
4808 22 : fnum = SVAL(req->vwv+0, 0);
4809 22 : fsp = file_fsp(req, fnum);
4810 :
4811 22 : if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4812 8 : return;
4813 : }
4814 :
4815 12 : if (!fsp) {
4816 5 : files_forall(req->sconn, file_sync_one_fn, conn);
4817 : } else {
4818 7 : NTSTATUS status = sync_file(conn, fsp, True);
4819 7 : if (!NT_STATUS_IS_OK(status)) {
4820 0 : DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4821 : fsp_str_dbg(fsp), nt_errstr(status)));
4822 0 : reply_nterror(req, status);
4823 0 : END_PROFILE(SMBflush);
4824 0 : return;
4825 : }
4826 7 : if (fsp->fsp_flags.modified) {
4827 7 : trigger_write_time_update_immediate(fsp);
4828 : }
4829 : }
4830 :
4831 12 : reply_smb1_outbuf(req, 0, 0);
4832 :
4833 12 : DEBUG(3,("flush\n"));
4834 12 : END_PROFILE(SMBflush);
4835 10 : return;
4836 : }
4837 :
4838 : /****************************************************************************
4839 : Reply to a exit.
4840 : conn POINTER CAN BE NULL HERE !
4841 : ****************************************************************************/
4842 :
4843 : static struct tevent_req *reply_exit_send(struct smb_request *smb1req);
4844 : static void reply_exit_done(struct tevent_req *req);
4845 :
4846 1793 : void reply_exit(struct smb_request *smb1req)
4847 : {
4848 129 : struct tevent_req *req;
4849 :
4850 : /*
4851 : * Don't setup the profile charge here, take
4852 : * it in reply_exit_done(). Not strictly correct
4853 : * but better than the other SMB1 async
4854 : * code that double-charges at the moment.
4855 : */
4856 1793 : req = reply_exit_send(smb1req);
4857 1793 : if (req == NULL) {
4858 : /* Not going async, profile here. */
4859 0 : START_PROFILE(SMBexit);
4860 0 : reply_force_doserror(smb1req, ERRDOS, ERRnomem);
4861 0 : END_PROFILE(SMBexit);
4862 0 : return;
4863 : }
4864 :
4865 : /* We're async. This will complete later. */
4866 1793 : tevent_req_set_callback(req, reply_exit_done, smb1req);
4867 1793 : return;
4868 : }
4869 :
4870 : struct reply_exit_state {
4871 : struct tevent_queue *wait_queue;
4872 : };
4873 :
4874 : static void reply_exit_wait_done(struct tevent_req *subreq);
4875 :
4876 : /****************************************************************************
4877 : Async SMB1 exit.
4878 : Note, on failure here we deallocate and return NULL to allow the caller to
4879 : SMB1 return an error of ERRnomem immediately.
4880 : ****************************************************************************/
4881 :
4882 1793 : static struct tevent_req *reply_exit_send(struct smb_request *smb1req)
4883 : {
4884 129 : struct tevent_req *req;
4885 129 : struct reply_exit_state *state;
4886 129 : struct tevent_req *subreq;
4887 129 : files_struct *fsp;
4888 1793 : struct smbd_server_connection *sconn = smb1req->sconn;
4889 :
4890 1793 : req = tevent_req_create(smb1req, &state,
4891 : struct reply_exit_state);
4892 1793 : if (req == NULL) {
4893 0 : return NULL;
4894 : }
4895 1793 : state->wait_queue = tevent_queue_create(state,
4896 : "reply_exit_wait_queue");
4897 1793 : if (tevent_req_nomem(state->wait_queue, req)) {
4898 0 : TALLOC_FREE(req);
4899 0 : return NULL;
4900 : }
4901 :
4902 2071 : for (fsp = sconn->files; fsp; fsp = fsp->next) {
4903 278 : if (fsp->file_pid != smb1req->smbpid) {
4904 36 : continue;
4905 : }
4906 242 : if (fsp->vuid != smb1req->vuid) {
4907 0 : continue;
4908 : }
4909 : /*
4910 : * Flag the file as close in progress.
4911 : * This will prevent any more IO being
4912 : * done on it.
4913 : */
4914 242 : fsp->fsp_flags.closing = true;
4915 :
4916 242 : if (fsp->num_aio_requests > 0) {
4917 : /*
4918 : * Now wait until all aio requests on this fsp are
4919 : * finished.
4920 : *
4921 : * We don't set a callback, as we just want to block the
4922 : * wait queue and the talloc_free() of fsp->aio_request
4923 : * will remove the item from the wait queue.
4924 : */
4925 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
4926 : sconn->ev_ctx,
4927 0 : state->wait_queue);
4928 0 : if (tevent_req_nomem(subreq, req)) {
4929 0 : TALLOC_FREE(req);
4930 0 : return NULL;
4931 : }
4932 : }
4933 : }
4934 :
4935 : /*
4936 : * Now we add our own waiter to the end of the queue,
4937 : * this way we get notified when all pending requests are finished
4938 : * and reply to the outstanding SMB1 request.
4939 : */
4940 1922 : subreq = tevent_queue_wait_send(state,
4941 : sconn->ev_ctx,
4942 1793 : state->wait_queue);
4943 1793 : if (tevent_req_nomem(subreq, req)) {
4944 0 : TALLOC_FREE(req);
4945 0 : return NULL;
4946 : }
4947 :
4948 : /*
4949 : * We're really going async - move the SMB1 request from
4950 : * a talloc stackframe above us to the conn talloc-context.
4951 : * We need this to stick around until the wait_done
4952 : * callback is invoked.
4953 : */
4954 1793 : smb1req = talloc_move(sconn, &smb1req);
4955 :
4956 1793 : tevent_req_set_callback(subreq, reply_exit_wait_done, req);
4957 :
4958 1793 : return req;
4959 : }
4960 :
4961 1793 : static void reply_exit_wait_done(struct tevent_req *subreq)
4962 : {
4963 1793 : struct tevent_req *req = tevent_req_callback_data(
4964 : subreq, struct tevent_req);
4965 :
4966 1793 : tevent_queue_wait_recv(subreq);
4967 1793 : TALLOC_FREE(subreq);
4968 1793 : tevent_req_done(req);
4969 1793 : }
4970 :
4971 1793 : static NTSTATUS reply_exit_recv(struct tevent_req *req)
4972 : {
4973 1793 : return tevent_req_simple_recv_ntstatus(req);
4974 : }
4975 :
4976 1793 : static void reply_exit_done(struct tevent_req *req)
4977 : {
4978 1793 : struct smb_request *smb1req = tevent_req_callback_data(
4979 : req, struct smb_request);
4980 1793 : struct smbd_server_connection *sconn = smb1req->sconn;
4981 1793 : struct smbXsrv_connection *xconn = smb1req->xconn;
4982 1793 : NTTIME now = timeval_to_nttime(&smb1req->request_time);
4983 1793 : struct smbXsrv_session *session = NULL;
4984 129 : files_struct *fsp, *next;
4985 129 : NTSTATUS status;
4986 :
4987 : /*
4988 : * Take the profile charge here. Not strictly
4989 : * correct but better than the other SMB1 async
4990 : * code that double-charges at the moment.
4991 : */
4992 1793 : START_PROFILE(SMBexit);
4993 :
4994 1793 : status = reply_exit_recv(req);
4995 1793 : TALLOC_FREE(req);
4996 1793 : if (!NT_STATUS_IS_OK(status)) {
4997 0 : TALLOC_FREE(smb1req);
4998 0 : END_PROFILE(SMBexit);
4999 0 : exit_server(__location__ ": reply_exit_recv failed");
5000 : return;
5001 : }
5002 :
5003 : /*
5004 : * Ensure the session is still valid.
5005 : */
5006 1922 : status = smb1srv_session_lookup(xconn,
5007 1793 : smb1req->vuid,
5008 : now,
5009 : &session);
5010 1793 : if (!NT_STATUS_IS_OK(status)) {
5011 4 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5012 4 : smb_request_done(smb1req);
5013 4 : END_PROFILE(SMBexit);
5014 4 : return;
5015 : }
5016 :
5017 : /*
5018 : * Ensure the vuid is still valid - no one
5019 : * called reply_ulogoffX() in the meantime.
5020 : * reply_exit() doesn't have AS_USER set, so
5021 : * use set_current_user_info() directly.
5022 : * This is the same logic as in switch_message().
5023 : */
5024 1789 : if (session->global->auth_session_info != NULL) {
5025 1789 : set_current_user_info(
5026 1660 : session->global->auth_session_info->unix_info->sanitized_username,
5027 1789 : session->global->auth_session_info->unix_info->unix_name,
5028 1789 : session->global->auth_session_info->info->domain_name);
5029 : }
5030 :
5031 : /* No more aio - do the actual closes. */
5032 2067 : for (fsp = sconn->files; fsp; fsp = next) {
5033 4 : bool ok;
5034 278 : next = fsp->next;
5035 :
5036 278 : if (fsp->file_pid != smb1req->smbpid) {
5037 36 : continue;
5038 : }
5039 242 : if (fsp->vuid != smb1req->vuid) {
5040 0 : continue;
5041 : }
5042 242 : if (!fsp->fsp_flags.closing) {
5043 0 : continue;
5044 : }
5045 :
5046 : /*
5047 : * reply_exit() has the DO_CHDIR flag set.
5048 : */
5049 242 : ok = chdir_current_service(fsp->conn);
5050 242 : if (!ok) {
5051 0 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5052 0 : smb_request_done(smb1req);
5053 0 : END_PROFILE(SMBexit);
5054 0 : return;
5055 : }
5056 242 : close_file_free(NULL, &fsp, SHUTDOWN_CLOSE);
5057 : }
5058 :
5059 1789 : reply_smb1_outbuf(smb1req, 0, 0);
5060 : /*
5061 : * The following call is needed to push the
5062 : * reply data back out the socket after async
5063 : * return. Plus it frees smb1req.
5064 : */
5065 1789 : smb_request_done(smb1req);
5066 1789 : DBG_INFO("reply_exit complete\n");
5067 1789 : END_PROFILE(SMBexit);
5068 1660 : return;
5069 : }
5070 :
5071 : static struct tevent_req *reply_close_send(struct smb_request *smb1req,
5072 : files_struct *fsp);
5073 : static void reply_close_done(struct tevent_req *req);
5074 :
5075 36226 : void reply_close(struct smb_request *smb1req)
5076 : {
5077 36226 : connection_struct *conn = smb1req->conn;
5078 36226 : NTSTATUS status = NT_STATUS_OK;
5079 36226 : files_struct *fsp = NULL;
5080 36226 : START_PROFILE(SMBclose);
5081 :
5082 36226 : if (smb1req->wct < 3) {
5083 0 : reply_nterror(smb1req, NT_STATUS_INVALID_PARAMETER);
5084 0 : END_PROFILE(SMBclose);
5085 0 : return;
5086 : }
5087 :
5088 36226 : fsp = file_fsp(smb1req, SVAL(smb1req->vwv+0, 0));
5089 :
5090 : /*
5091 : * We can only use check_fsp if we know it's not a directory.
5092 : */
5093 :
5094 36226 : if (!check_fsp_open(conn, smb1req, fsp)) {
5095 2505 : END_PROFILE(SMBclose);
5096 2505 : return;
5097 : }
5098 :
5099 33721 : DBG_NOTICE("Close %s fd=%d %s (numopen=%d)\n",
5100 : fsp->fsp_flags.is_directory ?
5101 : "directory" : "file",
5102 : fsp_get_pathref_fd(fsp), fsp_fnum_dbg(fsp),
5103 : conn->num_files_open);
5104 :
5105 33721 : if (!fsp->fsp_flags.is_directory) {
5106 283 : time_t t;
5107 :
5108 : /*
5109 : * Take care of any time sent in the close.
5110 : */
5111 :
5112 30869 : t = srv_make_unix_date3(smb1req->vwv+1);
5113 30869 : set_close_write_time(fsp, time_t_to_full_timespec(t));
5114 : }
5115 :
5116 33721 : if (fsp->num_aio_requests != 0) {
5117 0 : struct tevent_req *req;
5118 :
5119 0 : req = reply_close_send(smb1req, fsp);
5120 0 : if (req == NULL) {
5121 0 : status = NT_STATUS_NO_MEMORY;
5122 0 : goto done;
5123 : }
5124 : /* We're async. This will complete later. */
5125 0 : tevent_req_set_callback(req, reply_close_done, smb1req);
5126 0 : END_PROFILE(SMBclose);
5127 0 : return;
5128 : }
5129 :
5130 : /*
5131 : * close_file_free() returns the unix errno if an error was detected on
5132 : * close - normally this is due to a disk full error. If not then it
5133 : * was probably an I/O error.
5134 : */
5135 :
5136 33721 : status = close_file_free(smb1req, &fsp, NORMAL_CLOSE);
5137 33721 : done:
5138 33721 : if (!NT_STATUS_IS_OK(status)) {
5139 0 : reply_nterror(smb1req, status);
5140 0 : END_PROFILE(SMBclose);
5141 0 : return;
5142 : }
5143 :
5144 33721 : reply_smb1_outbuf(smb1req, 0, 0);
5145 33721 : END_PROFILE(SMBclose);
5146 33412 : return;
5147 : }
5148 :
5149 : struct reply_close_state {
5150 : files_struct *fsp;
5151 : struct tevent_queue *wait_queue;
5152 : };
5153 :
5154 : static void reply_close_wait_done(struct tevent_req *subreq);
5155 :
5156 : /****************************************************************************
5157 : Async SMB1 close.
5158 : Note, on failure here we deallocate and return NULL to allow the caller to
5159 : SMB1 return an error of ERRnomem immediately.
5160 : ****************************************************************************/
5161 :
5162 0 : static struct tevent_req *reply_close_send(struct smb_request *smb1req,
5163 : files_struct *fsp)
5164 : {
5165 0 : struct tevent_req *req;
5166 0 : struct reply_close_state *state;
5167 0 : struct tevent_req *subreq;
5168 0 : struct smbd_server_connection *sconn = smb1req->sconn;
5169 :
5170 0 : req = tevent_req_create(smb1req, &state,
5171 : struct reply_close_state);
5172 0 : if (req == NULL) {
5173 0 : return NULL;
5174 : }
5175 0 : state->wait_queue = tevent_queue_create(state,
5176 : "reply_close_wait_queue");
5177 0 : if (tevent_req_nomem(state->wait_queue, req)) {
5178 0 : TALLOC_FREE(req);
5179 0 : return NULL;
5180 : }
5181 :
5182 : /*
5183 : * Flag the file as close in progress.
5184 : * This will prevent any more IO being
5185 : * done on it.
5186 : */
5187 0 : fsp->fsp_flags.closing = true;
5188 :
5189 : /*
5190 : * Now wait until all aio requests on this fsp are
5191 : * finished.
5192 : *
5193 : * We don't set a callback, as we just want to block the
5194 : * wait queue and the talloc_free() of fsp->aio_request
5195 : * will remove the item from the wait queue.
5196 : */
5197 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
5198 : sconn->ev_ctx,
5199 0 : state->wait_queue);
5200 0 : if (tevent_req_nomem(subreq, req)) {
5201 0 : TALLOC_FREE(req);
5202 0 : return NULL;
5203 : }
5204 :
5205 : /*
5206 : * Now we add our own waiter to the end of the queue,
5207 : * this way we get notified when all pending requests are finished
5208 : * and reply to the outstanding SMB1 request.
5209 : */
5210 0 : subreq = tevent_queue_wait_send(state,
5211 : sconn->ev_ctx,
5212 0 : state->wait_queue);
5213 0 : if (tevent_req_nomem(subreq, req)) {
5214 0 : TALLOC_FREE(req);
5215 0 : return NULL;
5216 : }
5217 :
5218 : /*
5219 : * We're really going async - move the SMB1 request from
5220 : * a talloc stackframe above us to the conn talloc-context.
5221 : * We need this to stick around until the wait_done
5222 : * callback is invoked.
5223 : */
5224 0 : smb1req = talloc_move(sconn, &smb1req);
5225 :
5226 0 : tevent_req_set_callback(subreq, reply_close_wait_done, req);
5227 :
5228 0 : return req;
5229 : }
5230 :
5231 0 : static void reply_close_wait_done(struct tevent_req *subreq)
5232 : {
5233 0 : struct tevent_req *req = tevent_req_callback_data(
5234 : subreq, struct tevent_req);
5235 :
5236 0 : tevent_queue_wait_recv(subreq);
5237 0 : TALLOC_FREE(subreq);
5238 0 : tevent_req_done(req);
5239 0 : }
5240 :
5241 0 : static NTSTATUS reply_close_recv(struct tevent_req *req)
5242 : {
5243 0 : return tevent_req_simple_recv_ntstatus(req);
5244 : }
5245 :
5246 0 : static void reply_close_done(struct tevent_req *req)
5247 : {
5248 0 : struct smb_request *smb1req = tevent_req_callback_data(
5249 : req, struct smb_request);
5250 0 : struct reply_close_state *state = tevent_req_data(req,
5251 : struct reply_close_state);
5252 0 : NTSTATUS status;
5253 :
5254 0 : status = reply_close_recv(req);
5255 0 : TALLOC_FREE(req);
5256 0 : if (!NT_STATUS_IS_OK(status)) {
5257 0 : TALLOC_FREE(smb1req);
5258 0 : exit_server(__location__ ": reply_close_recv failed");
5259 : return;
5260 : }
5261 :
5262 0 : status = close_file_free(smb1req, &state->fsp, NORMAL_CLOSE);
5263 0 : if (NT_STATUS_IS_OK(status)) {
5264 0 : reply_smb1_outbuf(smb1req, 0, 0);
5265 : } else {
5266 0 : reply_nterror(smb1req, status);
5267 : }
5268 : /*
5269 : * The following call is needed to push the
5270 : * reply data back out the socket after async
5271 : * return. Plus it frees smb1req.
5272 : */
5273 0 : smb_request_done(smb1req);
5274 : }
5275 :
5276 : /****************************************************************************
5277 : Reply to a writeclose (Core+ protocol).
5278 : ****************************************************************************/
5279 :
5280 45 : void reply_writeclose(struct smb_request *req)
5281 : {
5282 45 : connection_struct *conn = req->conn;
5283 9 : size_t numtowrite;
5284 9 : size_t remaining;
5285 45 : ssize_t nwritten = -1;
5286 45 : NTSTATUS close_status = NT_STATUS_OK;
5287 9 : off_t startpos;
5288 9 : const char *data;
5289 9 : struct timespec mtime;
5290 9 : files_struct *fsp;
5291 9 : struct lock_struct lock;
5292 9 : NTSTATUS status;
5293 :
5294 45 : START_PROFILE(SMBwriteclose);
5295 :
5296 45 : if (req->wct < 6) {
5297 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5298 0 : END_PROFILE(SMBwriteclose);
5299 0 : return;
5300 : }
5301 :
5302 45 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5303 :
5304 45 : if (!check_fsp(conn, req, fsp)) {
5305 15 : END_PROFILE(SMBwriteclose);
5306 15 : return;
5307 : }
5308 30 : status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
5309 30 : if (!NT_STATUS_IS_OK(status)) {
5310 0 : reply_nterror(req, status);
5311 0 : END_PROFILE(SMBwriteclose);
5312 0 : return;
5313 : }
5314 :
5315 30 : numtowrite = SVAL(req->vwv+1, 0);
5316 30 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5317 30 : mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+4));
5318 30 : data = (const char *)req->buf + 1;
5319 :
5320 : /*
5321 : * Ensure client isn't asking us to write more than
5322 : * they sent. CVE-2017-12163.
5323 : */
5324 30 : remaining = smbreq_bufrem(req, data);
5325 30 : if (numtowrite > remaining) {
5326 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5327 0 : END_PROFILE(SMBwriteclose);
5328 0 : return;
5329 : }
5330 :
5331 30 : if (fsp->print_file == NULL) {
5332 30 : init_strict_lock_struct(fsp,
5333 30 : (uint64_t)req->smbpid,
5334 : (uint64_t)startpos,
5335 : (uint64_t)numtowrite,
5336 : WRITE_LOCK,
5337 : lp_posix_cifsu_locktype(fsp),
5338 : &lock);
5339 :
5340 30 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5341 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5342 0 : END_PROFILE(SMBwriteclose);
5343 0 : return;
5344 : }
5345 : }
5346 :
5347 30 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
5348 :
5349 30 : set_close_write_time(fsp, mtime);
5350 :
5351 : /*
5352 : * More insanity. W2K only closes the file if writelen > 0.
5353 : * JRA.
5354 : */
5355 :
5356 30 : DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5357 : fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5358 : (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5359 :
5360 30 : if (numtowrite) {
5361 20 : DEBUG(3,("reply_writeclose: zero length write doesn't close "
5362 : "file %s\n", fsp_str_dbg(fsp)));
5363 20 : close_status = close_file_free(req, &fsp, NORMAL_CLOSE);
5364 : }
5365 :
5366 30 : if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5367 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
5368 0 : goto out;
5369 : }
5370 :
5371 30 : if(!NT_STATUS_IS_OK(close_status)) {
5372 0 : reply_nterror(req, close_status);
5373 0 : goto out;
5374 : }
5375 :
5376 30 : reply_smb1_outbuf(req, 1, 0);
5377 :
5378 30 : SSVAL(req->outbuf,smb_vwv0,nwritten);
5379 :
5380 30 : out:
5381 :
5382 30 : END_PROFILE(SMBwriteclose);
5383 24 : return;
5384 : }
5385 :
5386 : #undef DBGC_CLASS
5387 : #define DBGC_CLASS DBGC_LOCKING
5388 :
5389 : /****************************************************************************
5390 : Reply to a lock.
5391 : ****************************************************************************/
5392 :
5393 : static void reply_lock_done(struct tevent_req *subreq);
5394 :
5395 22 : void reply_lock(struct smb_request *req)
5396 : {
5397 22 : struct tevent_req *subreq = NULL;
5398 22 : connection_struct *conn = req->conn;
5399 0 : files_struct *fsp;
5400 22 : struct smbd_lock_element *lck = NULL;
5401 :
5402 22 : START_PROFILE(SMBlock);
5403 :
5404 22 : if (req->wct < 5) {
5405 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5406 0 : END_PROFILE(SMBlock);
5407 0 : return;
5408 : }
5409 :
5410 22 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5411 :
5412 22 : if (!check_fsp(conn, req, fsp)) {
5413 0 : END_PROFILE(SMBlock);
5414 0 : return;
5415 : }
5416 :
5417 22 : lck = talloc(req, struct smbd_lock_element);
5418 22 : if (lck == NULL) {
5419 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5420 0 : END_PROFILE(SMBlock);
5421 0 : return;
5422 : }
5423 :
5424 22 : *lck = (struct smbd_lock_element) {
5425 22 : .req_guid = smbd_request_guid(req, 0),
5426 22 : .smblctx = req->smbpid,
5427 : .brltype = WRITE_LOCK,
5428 : .lock_flav = WINDOWS_LOCK,
5429 22 : .count = IVAL(req->vwv+1, 0),
5430 22 : .offset = IVAL(req->vwv+3, 0),
5431 : };
5432 :
5433 22 : DBG_NOTICE("lock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
5434 : fsp_get_io_fd(fsp),
5435 : fsp_fnum_dbg(fsp),
5436 : lck->offset,
5437 : lck->count);
5438 :
5439 22 : subreq = smbd_smb1_do_locks_send(
5440 : fsp,
5441 22 : req->sconn->ev_ctx,
5442 : &req,
5443 : fsp,
5444 : 0,
5445 : false, /* large_offset */
5446 : 1,
5447 : lck);
5448 22 : if (subreq == NULL) {
5449 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
5450 0 : END_PROFILE(SMBlock);
5451 0 : return;
5452 : }
5453 22 : tevent_req_set_callback(subreq, reply_lock_done, NULL);
5454 22 : END_PROFILE(SMBlock);
5455 : }
5456 :
5457 22 : static void reply_lock_done(struct tevent_req *subreq)
5458 : {
5459 22 : struct smb_request *req = NULL;
5460 0 : NTSTATUS status;
5461 0 : bool ok;
5462 :
5463 22 : START_PROFILE(SMBlock);
5464 :
5465 22 : ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
5466 22 : SMB_ASSERT(ok);
5467 :
5468 22 : status = smbd_smb1_do_locks_recv(subreq);
5469 22 : TALLOC_FREE(subreq);
5470 :
5471 22 : if (NT_STATUS_IS_OK(status)) {
5472 14 : reply_smb1_outbuf(req, 0, 0);
5473 : } else {
5474 8 : reply_nterror(req, status);
5475 : }
5476 :
5477 22 : ok = smb1_srv_send(req->xconn,
5478 22 : (char *)req->outbuf,
5479 : true,
5480 22 : req->seqnum + 1,
5481 22 : IS_CONN_ENCRYPTED(req->conn));
5482 22 : if (!ok) {
5483 0 : exit_server_cleanly("reply_lock_done: smb1_srv_send failed.");
5484 : }
5485 22 : TALLOC_FREE(req);
5486 22 : END_PROFILE(SMBlock);
5487 22 : }
5488 :
5489 : /****************************************************************************
5490 : Reply to a unlock.
5491 : ****************************************************************************/
5492 :
5493 22 : void reply_unlock(struct smb_request *req)
5494 : {
5495 22 : connection_struct *conn = req->conn;
5496 0 : NTSTATUS status;
5497 0 : files_struct *fsp;
5498 0 : struct smbd_lock_element lck;
5499 :
5500 22 : START_PROFILE(SMBunlock);
5501 :
5502 22 : if (req->wct < 5) {
5503 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5504 0 : END_PROFILE(SMBunlock);
5505 0 : return;
5506 : }
5507 :
5508 22 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5509 :
5510 22 : if (!check_fsp(conn, req, fsp)) {
5511 0 : END_PROFILE(SMBunlock);
5512 0 : return;
5513 : }
5514 :
5515 22 : lck = (struct smbd_lock_element) {
5516 22 : .req_guid = smbd_request_guid(req, 0),
5517 22 : .smblctx = req->smbpid,
5518 : .brltype = UNLOCK_LOCK,
5519 : .lock_flav = WINDOWS_LOCK,
5520 22 : .offset = IVAL(req->vwv+3, 0),
5521 22 : .count = IVAL(req->vwv+1, 0),
5522 : };
5523 :
5524 22 : status = smbd_do_unlocking(req, fsp, 1, &lck);
5525 :
5526 22 : if (!NT_STATUS_IS_OK(status)) {
5527 10 : reply_nterror(req, status);
5528 10 : END_PROFILE(SMBunlock);
5529 10 : return;
5530 : }
5531 :
5532 12 : DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
5533 : fsp_get_io_fd(fsp),
5534 : fsp_fnum_dbg(fsp),
5535 : lck.offset,
5536 : lck.count);
5537 :
5538 12 : reply_smb1_outbuf(req, 0, 0);
5539 :
5540 12 : END_PROFILE(SMBunlock);
5541 12 : return;
5542 : }
5543 :
5544 : #undef DBGC_CLASS
5545 : #define DBGC_CLASS DBGC_ALL
5546 :
5547 : /****************************************************************************
5548 : Reply to a tdis.
5549 : conn POINTER CAN BE NULL HERE !
5550 : ****************************************************************************/
5551 :
5552 : static struct tevent_req *reply_tdis_send(struct smb_request *smb1req);
5553 : static void reply_tdis_done(struct tevent_req *req);
5554 :
5555 6827 : void reply_tdis(struct smb_request *smb1req)
5556 : {
5557 6827 : connection_struct *conn = smb1req->conn;
5558 16 : struct tevent_req *req;
5559 :
5560 : /*
5561 : * Don't setup the profile charge here, take
5562 : * it in reply_tdis_done(). Not strictly correct
5563 : * but better than the other SMB1 async
5564 : * code that double-charges at the moment.
5565 : */
5566 :
5567 6827 : if (conn == NULL) {
5568 : /* Not going async, profile here. */
5569 16 : START_PROFILE(SMBtdis);
5570 16 : DBG_INFO("Invalid connection in tdis\n");
5571 16 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5572 16 : END_PROFILE(SMBtdis);
5573 16 : return;
5574 : }
5575 :
5576 6811 : req = reply_tdis_send(smb1req);
5577 6811 : if (req == NULL) {
5578 : /* Not going async, profile here. */
5579 0 : START_PROFILE(SMBtdis);
5580 0 : reply_force_doserror(smb1req, ERRDOS, ERRnomem);
5581 0 : END_PROFILE(SMBtdis);
5582 0 : return;
5583 : }
5584 : /* We're async. This will complete later. */
5585 6811 : tevent_req_set_callback(req, reply_tdis_done, smb1req);
5586 6811 : return;
5587 : }
5588 :
5589 : struct reply_tdis_state {
5590 : struct tevent_queue *wait_queue;
5591 : };
5592 :
5593 : static void reply_tdis_wait_done(struct tevent_req *subreq);
5594 :
5595 : /****************************************************************************
5596 : Async SMB1 tdis.
5597 : Note, on failure here we deallocate and return NULL to allow the caller to
5598 : SMB1 return an error of ERRnomem immediately.
5599 : ****************************************************************************/
5600 :
5601 6811 : static struct tevent_req *reply_tdis_send(struct smb_request *smb1req)
5602 : {
5603 16 : struct tevent_req *req;
5604 16 : struct reply_tdis_state *state;
5605 16 : struct tevent_req *subreq;
5606 6811 : connection_struct *conn = smb1req->conn;
5607 16 : files_struct *fsp;
5608 :
5609 6811 : req = tevent_req_create(smb1req, &state,
5610 : struct reply_tdis_state);
5611 6811 : if (req == NULL) {
5612 0 : return NULL;
5613 : }
5614 6811 : state->wait_queue = tevent_queue_create(state, "reply_tdis_wait_queue");
5615 6811 : if (tevent_req_nomem(state->wait_queue, req)) {
5616 0 : TALLOC_FREE(req);
5617 0 : return NULL;
5618 : }
5619 :
5620 : /*
5621 : * Make sure that no new request will be able to use this tcon.
5622 : * This ensures that once all outstanding fsp->aio_requests
5623 : * on this tcon are done, we are safe to close it.
5624 : */
5625 6811 : conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
5626 :
5627 6896 : for (fsp = conn->sconn->files; fsp; fsp = fsp->next) {
5628 85 : if (fsp->conn != conn) {
5629 4 : continue;
5630 : }
5631 : /*
5632 : * Flag the file as close in progress.
5633 : * This will prevent any more IO being
5634 : * done on it. Not strictly needed, but
5635 : * doesn't hurt to flag it as closing.
5636 : */
5637 81 : fsp->fsp_flags.closing = true;
5638 :
5639 81 : if (fsp->num_aio_requests > 0) {
5640 : /*
5641 : * Now wait until all aio requests on this fsp are
5642 : * finished.
5643 : *
5644 : * We don't set a callback, as we just want to block the
5645 : * wait queue and the talloc_free() of fsp->aio_request
5646 : * will remove the item from the wait queue.
5647 : */
5648 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
5649 0 : conn->sconn->ev_ctx,
5650 0 : state->wait_queue);
5651 0 : if (tevent_req_nomem(subreq, req)) {
5652 0 : TALLOC_FREE(req);
5653 0 : return NULL;
5654 : }
5655 : }
5656 : }
5657 :
5658 : /*
5659 : * Now we add our own waiter to the end of the queue,
5660 : * this way we get notified when all pending requests are finished
5661 : * and reply to the outstanding SMB1 request.
5662 : */
5663 6827 : subreq = tevent_queue_wait_send(state,
5664 6811 : conn->sconn->ev_ctx,
5665 6811 : state->wait_queue);
5666 6811 : if (tevent_req_nomem(subreq, req)) {
5667 0 : TALLOC_FREE(req);
5668 0 : return NULL;
5669 : }
5670 :
5671 : /*
5672 : * We're really going async - move the SMB1 request from
5673 : * a talloc stackframe above us to the sconn talloc-context.
5674 : * We need this to stick around until the wait_done
5675 : * callback is invoked.
5676 : */
5677 6811 : smb1req = talloc_move(smb1req->sconn, &smb1req);
5678 :
5679 6811 : tevent_req_set_callback(subreq, reply_tdis_wait_done, req);
5680 :
5681 6811 : return req;
5682 : }
5683 :
5684 6811 : static void reply_tdis_wait_done(struct tevent_req *subreq)
5685 : {
5686 6811 : struct tevent_req *req = tevent_req_callback_data(
5687 : subreq, struct tevent_req);
5688 :
5689 6811 : tevent_queue_wait_recv(subreq);
5690 6811 : TALLOC_FREE(subreq);
5691 6811 : tevent_req_done(req);
5692 6811 : }
5693 :
5694 6811 : static NTSTATUS reply_tdis_recv(struct tevent_req *req)
5695 : {
5696 6811 : return tevent_req_simple_recv_ntstatus(req);
5697 : }
5698 :
5699 6811 : static void reply_tdis_done(struct tevent_req *req)
5700 : {
5701 6811 : struct smb_request *smb1req = tevent_req_callback_data(
5702 : req, struct smb_request);
5703 16 : NTSTATUS status;
5704 6811 : struct smbXsrv_tcon *tcon = smb1req->conn->tcon;
5705 16 : bool ok;
5706 :
5707 : /*
5708 : * Take the profile charge here. Not strictly
5709 : * correct but better than the other SMB1 async
5710 : * code that double-charges at the moment.
5711 : */
5712 6811 : START_PROFILE(SMBtdis);
5713 :
5714 6811 : status = reply_tdis_recv(req);
5715 6811 : TALLOC_FREE(req);
5716 6811 : if (!NT_STATUS_IS_OK(status)) {
5717 0 : TALLOC_FREE(smb1req);
5718 0 : END_PROFILE(SMBtdis);
5719 0 : exit_server(__location__ ": reply_tdis_recv failed");
5720 : return;
5721 : }
5722 :
5723 : /*
5724 : * As we've been awoken, we may have changed
5725 : * directory in the meantime.
5726 : * reply_tdis() has the DO_CHDIR flag set.
5727 : */
5728 6811 : ok = chdir_current_service(smb1req->conn);
5729 6811 : if (!ok) {
5730 0 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5731 0 : smb_request_done(smb1req);
5732 0 : END_PROFILE(SMBtdis);
5733 : }
5734 :
5735 6811 : status = smbXsrv_tcon_disconnect(tcon,
5736 : smb1req->vuid);
5737 6811 : if (!NT_STATUS_IS_OK(status)) {
5738 0 : TALLOC_FREE(smb1req);
5739 0 : END_PROFILE(SMBtdis);
5740 0 : exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5741 : return;
5742 : }
5743 :
5744 : /* smbXsrv_tcon_disconnect frees smb1req->conn. */
5745 6811 : smb1req->conn = NULL;
5746 :
5747 6811 : TALLOC_FREE(tcon);
5748 :
5749 6811 : reply_smb1_outbuf(smb1req, 0, 0);
5750 : /*
5751 : * The following call is needed to push the
5752 : * reply data back out the socket after async
5753 : * return. Plus it frees smb1req.
5754 : */
5755 6811 : smb_request_done(smb1req);
5756 6811 : END_PROFILE(SMBtdis);
5757 : }
5758 :
5759 : /****************************************************************************
5760 : Reply to a echo.
5761 : conn POINTER CAN BE NULL HERE !
5762 : ****************************************************************************/
5763 :
5764 31 : void reply_echo(struct smb_request *req)
5765 : {
5766 31 : connection_struct *conn = req->conn;
5767 0 : int smb_reverb;
5768 0 : int seq_num;
5769 :
5770 31 : START_PROFILE(SMBecho);
5771 :
5772 31 : if (req->wct < 1) {
5773 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5774 0 : END_PROFILE(SMBecho);
5775 0 : return;
5776 : }
5777 :
5778 31 : smb_reverb = SVAL(req->vwv+0, 0);
5779 :
5780 31 : reply_smb1_outbuf(req, 1, req->buflen);
5781 :
5782 : /* copy any incoming data back out */
5783 31 : if (req->buflen > 0) {
5784 29 : memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5785 : }
5786 :
5787 31 : if (smb_reverb > 100) {
5788 0 : DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5789 0 : smb_reverb = 100;
5790 : }
5791 :
5792 62 : for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5793 :
5794 31 : SSVAL(req->outbuf,smb_vwv0,seq_num);
5795 :
5796 31 : show_msg((char *)req->outbuf);
5797 31 : if (!smb1_srv_send(req->xconn,
5798 31 : (char *)req->outbuf,
5799 : true,
5800 31 : req->seqnum + 1,
5801 31 : IS_CONN_ENCRYPTED(conn) || req->encrypted))
5802 0 : exit_server_cleanly("reply_echo: smb1_srv_send failed.");
5803 : }
5804 :
5805 31 : DEBUG(3,("echo %d times\n", smb_reverb));
5806 :
5807 31 : TALLOC_FREE(req->outbuf);
5808 :
5809 31 : END_PROFILE(SMBecho);
5810 31 : return;
5811 : }
5812 :
5813 : /****************************************************************************
5814 : Reply to a printopen.
5815 : ****************************************************************************/
5816 :
5817 0 : void reply_printopen(struct smb_request *req)
5818 : {
5819 0 : connection_struct *conn = req->conn;
5820 0 : files_struct *fsp;
5821 0 : NTSTATUS status;
5822 :
5823 0 : START_PROFILE(SMBsplopen);
5824 :
5825 0 : if (req->wct < 2) {
5826 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5827 0 : END_PROFILE(SMBsplopen);
5828 0 : return;
5829 : }
5830 :
5831 0 : if (!CAN_PRINT(conn)) {
5832 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5833 0 : END_PROFILE(SMBsplopen);
5834 0 : return;
5835 : }
5836 :
5837 0 : status = file_new(req, conn, &fsp);
5838 0 : if(!NT_STATUS_IS_OK(status)) {
5839 0 : reply_nterror(req, status);
5840 0 : END_PROFILE(SMBsplopen);
5841 0 : return;
5842 : }
5843 :
5844 : /* Open for exclusive use, write only. */
5845 0 : status = print_spool_open(fsp, NULL, req->vuid);
5846 :
5847 0 : if (!NT_STATUS_IS_OK(status)) {
5848 0 : file_free(req, fsp);
5849 0 : reply_nterror(req, status);
5850 0 : END_PROFILE(SMBsplopen);
5851 0 : return;
5852 : }
5853 :
5854 0 : reply_smb1_outbuf(req, 1, 0);
5855 0 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5856 :
5857 0 : DEBUG(3,("openprint fd=%d %s\n",
5858 : fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
5859 :
5860 0 : END_PROFILE(SMBsplopen);
5861 0 : return;
5862 : }
5863 :
5864 : /****************************************************************************
5865 : Reply to a printclose.
5866 : ****************************************************************************/
5867 :
5868 5 : void reply_printclose(struct smb_request *req)
5869 : {
5870 5 : connection_struct *conn = req->conn;
5871 1 : files_struct *fsp;
5872 1 : NTSTATUS status;
5873 :
5874 5 : START_PROFILE(SMBsplclose);
5875 :
5876 5 : if (req->wct < 1) {
5877 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5878 0 : END_PROFILE(SMBsplclose);
5879 0 : return;
5880 : }
5881 :
5882 5 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5883 :
5884 5 : if (!check_fsp(conn, req, fsp)) {
5885 0 : END_PROFILE(SMBsplclose);
5886 0 : return;
5887 : }
5888 :
5889 5 : if (!CAN_PRINT(conn)) {
5890 5 : reply_force_doserror(req, ERRSRV, ERRerror);
5891 5 : END_PROFILE(SMBsplclose);
5892 5 : return;
5893 : }
5894 :
5895 0 : DEBUG(3,("printclose fd=%d %s\n",
5896 : fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
5897 :
5898 0 : status = close_file_free(req, &fsp, NORMAL_CLOSE);
5899 :
5900 0 : if(!NT_STATUS_IS_OK(status)) {
5901 0 : reply_nterror(req, status);
5902 0 : END_PROFILE(SMBsplclose);
5903 0 : return;
5904 : }
5905 :
5906 0 : reply_smb1_outbuf(req, 0, 0);
5907 :
5908 0 : END_PROFILE(SMBsplclose);
5909 0 : return;
5910 : }
5911 :
5912 : /****************************************************************************
5913 : Reply to a printqueue.
5914 : ****************************************************************************/
5915 :
5916 0 : void reply_printqueue(struct smb_request *req)
5917 : {
5918 0 : const struct loadparm_substitution *lp_sub =
5919 0 : loadparm_s3_global_substitution();
5920 0 : connection_struct *conn = req->conn;
5921 0 : int max_count;
5922 0 : int start_index;
5923 :
5924 0 : START_PROFILE(SMBsplretq);
5925 :
5926 0 : if (req->wct < 2) {
5927 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5928 0 : END_PROFILE(SMBsplretq);
5929 0 : return;
5930 : }
5931 :
5932 0 : max_count = SVAL(req->vwv+0, 0);
5933 0 : start_index = SVAL(req->vwv+1, 0);
5934 :
5935 : /* we used to allow the client to get the cnum wrong, but that
5936 : is really quite gross and only worked when there was only
5937 : one printer - I think we should now only accept it if they
5938 : get it right (tridge) */
5939 0 : if (!CAN_PRINT(conn)) {
5940 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5941 0 : END_PROFILE(SMBsplretq);
5942 0 : return;
5943 : }
5944 :
5945 0 : reply_smb1_outbuf(req, 2, 3);
5946 0 : SSVAL(req->outbuf,smb_vwv0,0);
5947 0 : SSVAL(req->outbuf,smb_vwv1,0);
5948 0 : SCVAL(smb_buf(req->outbuf),0,1);
5949 0 : SSVAL(smb_buf(req->outbuf),1,0);
5950 :
5951 0 : DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5952 : start_index, max_count));
5953 :
5954 : {
5955 0 : TALLOC_CTX *mem_ctx = talloc_tos();
5956 0 : NTSTATUS status;
5957 0 : WERROR werr;
5958 0 : const char *sharename = lp_servicename(mem_ctx, lp_sub, SNUM(conn));
5959 0 : struct rpc_pipe_client *cli = NULL;
5960 0 : struct dcerpc_binding_handle *b = NULL;
5961 0 : struct policy_handle handle;
5962 0 : struct spoolss_DevmodeContainer devmode_ctr;
5963 0 : union spoolss_JobInfo *info;
5964 0 : uint32_t count;
5965 0 : uint32_t num_to_get;
5966 0 : uint32_t first;
5967 0 : uint32_t i;
5968 :
5969 0 : ZERO_STRUCT(handle);
5970 :
5971 0 : status = rpc_pipe_open_interface(mem_ctx,
5972 : &ndr_table_spoolss,
5973 0 : conn->session_info,
5974 0 : conn->sconn->remote_address,
5975 0 : conn->sconn->local_address,
5976 0 : conn->sconn->msg_ctx,
5977 : &cli);
5978 0 : if (!NT_STATUS_IS_OK(status)) {
5979 0 : DEBUG(0, ("reply_printqueue: "
5980 : "could not connect to spoolss: %s\n",
5981 : nt_errstr(status)));
5982 0 : reply_nterror(req, status);
5983 0 : goto out;
5984 : }
5985 0 : b = cli->binding_handle;
5986 :
5987 0 : ZERO_STRUCT(devmode_ctr);
5988 :
5989 0 : status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5990 : sharename,
5991 : NULL, devmode_ctr,
5992 : SEC_FLAG_MAXIMUM_ALLOWED,
5993 : &handle,
5994 : &werr);
5995 0 : if (!NT_STATUS_IS_OK(status)) {
5996 0 : reply_nterror(req, status);
5997 0 : goto out;
5998 : }
5999 0 : if (!W_ERROR_IS_OK(werr)) {
6000 0 : reply_nterror(req, werror_to_ntstatus(werr));
6001 0 : goto out;
6002 : }
6003 :
6004 0 : werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6005 : &handle,
6006 : 0, /* firstjob */
6007 : 0xff, /* numjobs */
6008 : 2, /* level */
6009 : 0, /* offered */
6010 : &count,
6011 : &info);
6012 0 : if (!W_ERROR_IS_OK(werr)) {
6013 0 : reply_nterror(req, werror_to_ntstatus(werr));
6014 0 : goto out;
6015 : }
6016 :
6017 0 : if (max_count > 0) {
6018 0 : first = start_index;
6019 : } else {
6020 0 : first = start_index + max_count + 1;
6021 : }
6022 :
6023 0 : if (first >= count) {
6024 0 : num_to_get = first;
6025 : } else {
6026 0 : num_to_get = first + MIN(ABS(max_count), count - first);
6027 : }
6028 :
6029 0 : for (i = first; i < num_to_get; i++) {
6030 0 : char blob[28];
6031 0 : char *p = blob;
6032 0 : struct timespec qtime = {
6033 0 : .tv_sec = spoolss_Time_to_time_t(
6034 0 : &info[i].info2.submitted),
6035 : };
6036 0 : int qstatus;
6037 0 : size_t len = 0;
6038 0 : uint16_t qrapjobid = pjobid_to_rap(sharename,
6039 0 : info[i].info2.job_id);
6040 :
6041 0 : if (info[i].info2.status == JOB_STATUS_PRINTING) {
6042 0 : qstatus = 2;
6043 : } else {
6044 0 : qstatus = 3;
6045 : }
6046 :
6047 0 : srv_put_dos_date2_ts(p, 0, qtime);
6048 0 : SCVAL(p, 4, qstatus);
6049 0 : SSVAL(p, 5, qrapjobid);
6050 0 : SIVAL(p, 7, info[i].info2.size);
6051 0 : SCVAL(p, 11, 0);
6052 0 : status = srvstr_push(blob, req->flags2, p+12,
6053 : info[i].info2.notify_name, 16, STR_ASCII, &len);
6054 0 : if (!NT_STATUS_IS_OK(status)) {
6055 0 : reply_nterror(req, status);
6056 0 : goto out;
6057 : }
6058 0 : if (message_push_blob(
6059 : &req->outbuf,
6060 : data_blob_const(
6061 : blob, sizeof(blob))) == -1) {
6062 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6063 0 : goto out;
6064 : }
6065 : }
6066 :
6067 0 : if (count > 0) {
6068 0 : SSVAL(req->outbuf,smb_vwv0,count);
6069 0 : SSVAL(req->outbuf,smb_vwv1,
6070 : (max_count>0?first+count:first-1));
6071 0 : SCVAL(smb_buf(req->outbuf),0,1);
6072 0 : SSVAL(smb_buf(req->outbuf),1,28*count);
6073 : }
6074 :
6075 :
6076 0 : DEBUG(3, ("%u entries returned in queue\n",
6077 : (unsigned)count));
6078 :
6079 0 : out:
6080 0 : if (b && is_valid_policy_hnd(&handle)) {
6081 0 : dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6082 : }
6083 :
6084 : }
6085 :
6086 0 : END_PROFILE(SMBsplretq);
6087 0 : return;
6088 : }
6089 :
6090 : /****************************************************************************
6091 : Reply to a printwrite.
6092 : ****************************************************************************/
6093 :
6094 0 : void reply_printwrite(struct smb_request *req)
6095 : {
6096 0 : connection_struct *conn = req->conn;
6097 0 : int numtowrite;
6098 0 : const char *data;
6099 0 : files_struct *fsp;
6100 0 : NTSTATUS status;
6101 :
6102 0 : START_PROFILE(SMBsplwr);
6103 :
6104 0 : if (req->wct < 1) {
6105 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6106 0 : END_PROFILE(SMBsplwr);
6107 0 : return;
6108 : }
6109 :
6110 0 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6111 :
6112 0 : if (!check_fsp(conn, req, fsp)) {
6113 0 : END_PROFILE(SMBsplwr);
6114 0 : return;
6115 : }
6116 :
6117 0 : if (!fsp->print_file) {
6118 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6119 0 : END_PROFILE(SMBsplwr);
6120 0 : return;
6121 : }
6122 :
6123 0 : status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
6124 0 : if (!NT_STATUS_IS_OK(status)) {
6125 0 : reply_nterror(req, status);
6126 0 : END_PROFILE(SMBsplwr);
6127 0 : return;
6128 : }
6129 :
6130 0 : numtowrite = SVAL(req->buf, 1);
6131 :
6132 : /*
6133 : * This already protects us against CVE-2017-12163.
6134 : */
6135 0 : if (req->buflen < numtowrite + 3) {
6136 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6137 0 : END_PROFILE(SMBsplwr);
6138 0 : return;
6139 : }
6140 :
6141 0 : data = (const char *)req->buf + 3;
6142 :
6143 0 : if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6144 0 : reply_nterror(req, map_nt_error_from_unix(errno));
6145 0 : END_PROFILE(SMBsplwr);
6146 0 : return;
6147 : }
6148 :
6149 0 : DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6150 :
6151 0 : reply_smb1_outbuf(req, 0, 0);
6152 :
6153 0 : END_PROFILE(SMBsplwr);
6154 0 : return;
6155 : }
6156 :
6157 : /****************************************************************************
6158 : Reply to a mkdir.
6159 : ****************************************************************************/
6160 :
6161 5648 : void reply_mkdir(struct smb_request *req)
6162 : {
6163 5648 : connection_struct *conn = req->conn;
6164 5648 : struct files_struct *dirfsp = NULL;
6165 5648 : struct smb_filename *smb_dname = NULL;
6166 5648 : char *directory = NULL;
6167 52 : NTSTATUS status;
6168 52 : uint32_t ucf_flags;
6169 5648 : NTTIME twrp = 0;
6170 5648 : TALLOC_CTX *ctx = talloc_tos();
6171 :
6172 5648 : START_PROFILE(SMBmkdir);
6173 :
6174 5648 : srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6175 : STR_TERMINATE, &status);
6176 5648 : if (!NT_STATUS_IS_OK(status)) {
6177 5 : reply_nterror(req, status);
6178 5 : goto out;
6179 : }
6180 :
6181 5643 : ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6182 5643 : if (ucf_flags & UCF_GMT_PATHNAME) {
6183 0 : extract_snapshot_token(directory, &twrp);
6184 : }
6185 5643 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &directory);
6186 5643 : if (!NT_STATUS_IS_OK(status)) {
6187 0 : reply_nterror(req, status);
6188 0 : goto out;
6189 : }
6190 :
6191 5643 : status = filename_convert_dirfsp(ctx,
6192 : conn,
6193 : directory,
6194 : ucf_flags,
6195 : twrp,
6196 : &dirfsp,
6197 : &smb_dname);
6198 5643 : if (!NT_STATUS_IS_OK(status)) {
6199 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6200 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6201 : ERRSRV, ERRbadpath);
6202 0 : goto out;
6203 : }
6204 0 : reply_nterror(req, status);
6205 0 : goto out;
6206 : }
6207 :
6208 5643 : status = create_directory(conn, req, dirfsp, smb_dname);
6209 :
6210 5643 : DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6211 :
6212 5643 : if (!NT_STATUS_IS_OK(status)) {
6213 :
6214 22 : if (!use_nt_status()
6215 4 : && NT_STATUS_EQUAL(status,
6216 : NT_STATUS_OBJECT_NAME_COLLISION)) {
6217 : /*
6218 : * Yes, in the DOS error code case we get a
6219 : * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6220 : * samba4 torture test.
6221 : */
6222 4 : status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6223 : }
6224 :
6225 22 : reply_nterror(req, status);
6226 22 : goto out;
6227 : }
6228 :
6229 5621 : reply_smb1_outbuf(req, 0, 0);
6230 :
6231 5621 : DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6232 5648 : out:
6233 5648 : TALLOC_FREE(smb_dname);
6234 5648 : END_PROFILE(SMBmkdir);
6235 5648 : return;
6236 : }
6237 :
6238 : /****************************************************************************
6239 : Reply to a rmdir.
6240 : ****************************************************************************/
6241 :
6242 6672 : void reply_rmdir(struct smb_request *req)
6243 : {
6244 6672 : connection_struct *conn = req->conn;
6245 6672 : struct smb_filename *smb_dname = NULL;
6246 6672 : char *directory = NULL;
6247 76 : NTSTATUS status;
6248 6672 : TALLOC_CTX *ctx = talloc_tos();
6249 6672 : struct files_struct *dirfsp = NULL;
6250 6672 : files_struct *fsp = NULL;
6251 6672 : int info = 0;
6252 6672 : NTTIME twrp = 0;
6253 6672 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
6254 :
6255 6672 : START_PROFILE(SMBrmdir);
6256 :
6257 6672 : srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6258 : STR_TERMINATE, &status);
6259 6672 : if (!NT_STATUS_IS_OK(status)) {
6260 0 : reply_nterror(req, status);
6261 0 : goto out;
6262 : }
6263 :
6264 6672 : if (ucf_flags & UCF_GMT_PATHNAME) {
6265 0 : extract_snapshot_token(directory, &twrp);
6266 : }
6267 6672 : status = smb1_strip_dfs_path(ctx, &ucf_flags, &directory);
6268 6672 : if (!NT_STATUS_IS_OK(status)) {
6269 0 : reply_nterror(req, status);
6270 0 : goto out;
6271 : }
6272 :
6273 6672 : status = filename_convert_dirfsp(ctx,
6274 : conn,
6275 : directory,
6276 : ucf_flags,
6277 : twrp,
6278 : &dirfsp,
6279 : &smb_dname);
6280 6672 : if (!NT_STATUS_IS_OK(status)) {
6281 7 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6282 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6283 : ERRSRV, ERRbadpath);
6284 0 : goto out;
6285 : }
6286 7 : reply_nterror(req, status);
6287 7 : goto out;
6288 : }
6289 :
6290 6665 : status = SMB_VFS_CREATE_FILE(
6291 : conn, /* conn */
6292 : req, /* req */
6293 : dirfsp, /* dirfsp */
6294 : smb_dname, /* fname */
6295 : DELETE_ACCESS, /* access_mask */
6296 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6297 : FILE_SHARE_DELETE),
6298 : FILE_OPEN, /* create_disposition*/
6299 : FILE_DIRECTORY_FILE |
6300 : FILE_OPEN_REPARSE_POINT, /* create_options */
6301 : FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6302 : 0, /* oplock_request */
6303 : NULL, /* lease */
6304 : 0, /* allocation_size */
6305 : 0, /* private_flags */
6306 : NULL, /* sd */
6307 : NULL, /* ea_list */
6308 : &fsp, /* result */
6309 : &info, /* pinfo */
6310 : NULL, NULL); /* create context */
6311 :
6312 6665 : if (!NT_STATUS_IS_OK(status)) {
6313 243 : if (open_was_deferred(req->xconn, req->mid)) {
6314 : /* We have re-scheduled this call. */
6315 0 : goto out;
6316 : }
6317 243 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
6318 32 : bool ok = defer_smb1_sharing_violation(req);
6319 32 : if (ok) {
6320 16 : goto out;
6321 : }
6322 : }
6323 227 : reply_nterror(req, status);
6324 227 : goto out;
6325 : }
6326 :
6327 6422 : status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6328 6422 : if (!NT_STATUS_IS_OK(status)) {
6329 42 : close_file_free(req, &fsp, ERROR_CLOSE);
6330 42 : reply_nterror(req, status);
6331 42 : goto out;
6332 : }
6333 :
6334 6380 : if (!set_delete_on_close(fsp, true,
6335 6380 : conn->session_info->security_token,
6336 6380 : conn->session_info->unix_token)) {
6337 0 : close_file_free(req, &fsp, ERROR_CLOSE);
6338 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6339 0 : goto out;
6340 : }
6341 :
6342 6380 : status = close_file_free(req, &fsp, NORMAL_CLOSE);
6343 6380 : if (!NT_STATUS_IS_OK(status)) {
6344 0 : reply_nterror(req, status);
6345 : } else {
6346 6380 : reply_smb1_outbuf(req, 0, 0);
6347 : }
6348 :
6349 6380 : DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6350 6672 : out:
6351 6672 : TALLOC_FREE(smb_dname);
6352 6672 : END_PROFILE(SMBrmdir);
6353 6672 : return;
6354 : }
6355 :
6356 : /****************************************************************************
6357 : Reply to a mv.
6358 : ****************************************************************************/
6359 :
6360 401 : void reply_mv(struct smb_request *req)
6361 : {
6362 401 : connection_struct *conn = req->conn;
6363 401 : char *name = NULL;
6364 401 : char *newname = NULL;
6365 15 : const char *p;
6366 15 : uint32_t attrs;
6367 15 : NTSTATUS status;
6368 401 : TALLOC_CTX *ctx = talloc_tos();
6369 401 : struct files_struct *src_dirfsp = NULL;
6370 401 : struct smb_filename *smb_fname_src = NULL;
6371 401 : struct files_struct *dst_dirfsp = NULL;
6372 401 : struct smb_filename *smb_fname_dst = NULL;
6373 401 : const char *dst_original_lcomp = NULL;
6374 401 : uint32_t src_ucf_flags = ucf_flags_from_smb_request(req);
6375 401 : NTTIME src_twrp = 0;
6376 401 : uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req);
6377 401 : NTTIME dst_twrp = 0;
6378 401 : bool stream_rename = false;
6379 :
6380 401 : START_PROFILE(SMBmv);
6381 :
6382 401 : if (req->wct < 1) {
6383 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6384 0 : goto out;
6385 : }
6386 :
6387 401 : attrs = SVAL(req->vwv+0, 0);
6388 :
6389 401 : p = (const char *)req->buf + 1;
6390 401 : p += srvstr_get_path_req(ctx, req, &name, p, STR_TERMINATE,
6391 : &status);
6392 401 : if (!NT_STATUS_IS_OK(status)) {
6393 0 : reply_nterror(req, status);
6394 0 : goto out;
6395 : }
6396 401 : p++;
6397 401 : p += srvstr_get_path_req(ctx, req, &newname, p, STR_TERMINATE,
6398 : &status);
6399 401 : if (!NT_STATUS_IS_OK(status)) {
6400 0 : reply_nterror(req, status);
6401 0 : goto out;
6402 : }
6403 :
6404 401 : if (!req->posix_pathnames) {
6405 : /* The newname must begin with a ':' if the
6406 : name contains a ':'. */
6407 359 : if (strchr_m(name, ':')) {
6408 4 : if (newname[0] != ':') {
6409 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6410 0 : goto out;
6411 : }
6412 4 : stream_rename = true;
6413 : }
6414 : }
6415 :
6416 401 : if (src_ucf_flags & UCF_GMT_PATHNAME) {
6417 0 : extract_snapshot_token(name, &src_twrp);
6418 : }
6419 401 : status = smb1_strip_dfs_path(ctx, &src_ucf_flags, &name);
6420 401 : if (!NT_STATUS_IS_OK(status)) {
6421 0 : reply_nterror(req, status);
6422 0 : goto out;
6423 : }
6424 401 : status = filename_convert_dirfsp(ctx,
6425 : conn,
6426 : name,
6427 : src_ucf_flags,
6428 : src_twrp,
6429 : &src_dirfsp,
6430 : &smb_fname_src);
6431 :
6432 401 : if (!NT_STATUS_IS_OK(status)) {
6433 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6434 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6435 : ERRSRV, ERRbadpath);
6436 0 : goto out;
6437 : }
6438 0 : reply_nterror(req, status);
6439 0 : goto out;
6440 : }
6441 :
6442 401 : if (dst_ucf_flags & UCF_GMT_PATHNAME) {
6443 0 : extract_snapshot_token(newname, &dst_twrp);
6444 : }
6445 401 : status = smb1_strip_dfs_path(ctx, &dst_ucf_flags, &newname);
6446 401 : if (!NT_STATUS_IS_OK(status)) {
6447 0 : reply_nterror(req, status);
6448 0 : goto out;
6449 : }
6450 401 : status = filename_convert_dirfsp(ctx,
6451 : conn,
6452 : newname,
6453 : dst_ucf_flags,
6454 : dst_twrp,
6455 : &dst_dirfsp,
6456 : &smb_fname_dst);
6457 :
6458 401 : if (!NT_STATUS_IS_OK(status)) {
6459 48 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6460 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6461 : ERRSRV, ERRbadpath);
6462 0 : goto out;
6463 : }
6464 48 : reply_nterror(req, status);
6465 48 : goto out;
6466 : }
6467 :
6468 : /* Get the last component of the destination for rename_internals(). */
6469 353 : dst_original_lcomp = get_original_lcomp(ctx,
6470 : conn,
6471 : newname,
6472 : dst_ucf_flags);
6473 353 : if (dst_original_lcomp == NULL) {
6474 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6475 0 : goto out;
6476 : }
6477 :
6478 353 : if (stream_rename) {
6479 : /* smb_fname_dst->base_name must be the same as
6480 : smb_fname_src->base_name. */
6481 4 : TALLOC_FREE(smb_fname_dst->base_name);
6482 8 : smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6483 4 : smb_fname_src->base_name);
6484 4 : if (!smb_fname_dst->base_name) {
6485 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6486 0 : goto out;
6487 : }
6488 : }
6489 :
6490 353 : DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6491 : smb_fname_str_dbg(smb_fname_dst)));
6492 :
6493 353 : status = rename_internals(ctx,
6494 : conn,
6495 : req,
6496 : src_dirfsp, /* src_dirfsp */
6497 : smb_fname_src,
6498 : smb_fname_dst,
6499 : dst_original_lcomp,
6500 : attrs,
6501 : false,
6502 : DELETE_ACCESS);
6503 353 : if (!NT_STATUS_IS_OK(status)) {
6504 96 : if (open_was_deferred(req->xconn, req->mid)) {
6505 : /* We have re-scheduled this call. */
6506 4 : goto out;
6507 : }
6508 92 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
6509 46 : bool ok = defer_smb1_sharing_violation(req);
6510 46 : if (ok) {
6511 23 : goto out;
6512 : }
6513 : }
6514 69 : reply_nterror(req, status);
6515 69 : goto out;
6516 : }
6517 :
6518 257 : reply_smb1_outbuf(req, 0, 0);
6519 401 : out:
6520 401 : TALLOC_FREE(smb_fname_src);
6521 401 : TALLOC_FREE(smb_fname_dst);
6522 401 : END_PROFILE(SMBmv);
6523 401 : return;
6524 : }
6525 :
6526 : /****************************************************************************
6527 : Reply to a file copy.
6528 :
6529 : From MS-CIFS.
6530 :
6531 : This command was introduced in the LAN Manager 1.0 dialect
6532 : It was rendered obsolete in the NT LAN Manager dialect.
6533 : This command was used to perform server-side file copies, but
6534 : is no longer used. Clients SHOULD
6535 : NOT send requests using this command code.
6536 : Servers receiving requests with this command code
6537 : SHOULD return STATUS_NOT_IMPLEMENTED (ERRDOS/ERRbadfunc).
6538 : ****************************************************************************/
6539 :
6540 0 : void reply_copy(struct smb_request *req)
6541 : {
6542 0 : START_PROFILE(SMBcopy);
6543 0 : reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
6544 0 : END_PROFILE(SMBcopy);
6545 0 : return;
6546 : }
6547 :
6548 : #undef DBGC_CLASS
6549 : #define DBGC_CLASS DBGC_LOCKING
6550 :
6551 : /****************************************************************************
6552 : Get a lock pid, dealing with large count requests.
6553 : ****************************************************************************/
6554 :
6555 5671 : uint64_t get_lock_pid(const uint8_t *data, int data_offset,
6556 : bool large_file_format)
6557 : {
6558 5671 : if(!large_file_format)
6559 5151 : return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
6560 : else
6561 520 : return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
6562 : }
6563 :
6564 : /****************************************************************************
6565 : Get a lock count, dealing with large count requests.
6566 : ****************************************************************************/
6567 :
6568 5671 : uint64_t get_lock_count(const uint8_t *data, int data_offset,
6569 : bool large_file_format)
6570 : {
6571 5671 : uint64_t count = 0;
6572 :
6573 5671 : if(!large_file_format) {
6574 5151 : count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
6575 : } else {
6576 : /*
6577 : * No BVAL, this is reversed!
6578 : */
6579 520 : count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
6580 520 : ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
6581 : }
6582 :
6583 5671 : return count;
6584 : }
6585 :
6586 : /****************************************************************************
6587 : Reply to a lockingX request.
6588 : ****************************************************************************/
6589 :
6590 : static void reply_lockingx_done(struct tevent_req *subreq);
6591 :
6592 5733 : void reply_lockingX(struct smb_request *req)
6593 : {
6594 5733 : connection_struct *conn = req->conn;
6595 15 : files_struct *fsp;
6596 15 : unsigned char locktype;
6597 15 : enum brl_type brltype;
6598 15 : unsigned char oplocklevel;
6599 15 : uint16_t num_ulocks;
6600 15 : uint16_t num_locks;
6601 15 : int32_t lock_timeout;
6602 15 : uint16_t i;
6603 15 : const uint8_t *data;
6604 15 : bool large_file_format;
6605 5733 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
6606 5733 : struct smbd_lock_element *locks = NULL;
6607 5733 : struct tevent_req *subreq = NULL;
6608 :
6609 5733 : START_PROFILE(SMBlockingX);
6610 :
6611 5733 : if (req->wct < 8) {
6612 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6613 0 : END_PROFILE(SMBlockingX);
6614 0 : return;
6615 : }
6616 :
6617 5733 : fsp = file_fsp(req, SVAL(req->vwv+2, 0));
6618 5733 : locktype = CVAL(req->vwv+3, 0);
6619 5733 : oplocklevel = CVAL(req->vwv+3, 1);
6620 5733 : num_ulocks = SVAL(req->vwv+6, 0);
6621 5733 : num_locks = SVAL(req->vwv+7, 0);
6622 5733 : lock_timeout = IVAL(req->vwv+4, 0);
6623 5733 : large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
6624 :
6625 5733 : if (!check_fsp(conn, req, fsp)) {
6626 4 : END_PROFILE(SMBlockingX);
6627 4 : return;
6628 : }
6629 :
6630 5729 : data = req->buf;
6631 :
6632 5729 : if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6633 : /* we don't support these - and CANCEL_LOCK makes w2k
6634 : and XP reboot so I don't really want to be
6635 : compatible! (tridge) */
6636 8 : reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
6637 8 : END_PROFILE(SMBlockingX);
6638 8 : return;
6639 : }
6640 :
6641 : /* Check if this is an oplock break on a file
6642 : we have granted an oplock on.
6643 : */
6644 5721 : if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
6645 : /* Client can insist on breaking to none. */
6646 96 : bool break_to_none = (oplocklevel == 0);
6647 0 : bool result;
6648 :
6649 96 : DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
6650 : "for %s\n", (unsigned int)oplocklevel,
6651 : fsp_fnum_dbg(fsp)));
6652 :
6653 : /*
6654 : * Make sure we have granted an exclusive or batch oplock on
6655 : * this file.
6656 : */
6657 :
6658 96 : if (fsp->oplock_type == 0) {
6659 :
6660 : /* The Samba4 nbench simulator doesn't understand
6661 : the difference between break to level2 and break
6662 : to none from level2 - it sends oplock break
6663 : replies in both cases. Don't keep logging an error
6664 : message here - just ignore it. JRA. */
6665 :
6666 26 : DEBUG(5,("reply_lockingX: Error : oplock break from "
6667 : "client for %s (oplock=%d) and no "
6668 : "oplock granted on this file (%s).\n",
6669 : fsp_fnum_dbg(fsp), fsp->oplock_type,
6670 : fsp_str_dbg(fsp)));
6671 :
6672 : /* if this is a pure oplock break request then don't
6673 : * send a reply */
6674 26 : if (num_locks == 0 && num_ulocks == 0) {
6675 26 : END_PROFILE(SMBlockingX);
6676 26 : return;
6677 : }
6678 :
6679 0 : END_PROFILE(SMBlockingX);
6680 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
6681 0 : return;
6682 : }
6683 :
6684 70 : if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
6685 : (break_to_none)) {
6686 24 : result = remove_oplock(fsp);
6687 : } else {
6688 46 : result = downgrade_oplock(fsp);
6689 : }
6690 :
6691 70 : if (!result) {
6692 0 : DEBUG(0, ("reply_lockingX: error in removing "
6693 : "oplock on file %s\n", fsp_str_dbg(fsp)));
6694 : /* Hmmm. Is this panic justified? */
6695 0 : smb_panic("internal tdb error");
6696 : }
6697 :
6698 : /* if this is a pure oplock break request then don't send a
6699 : * reply */
6700 70 : if (num_locks == 0 && num_ulocks == 0) {
6701 : /* Sanity check - ensure a pure oplock break is not a
6702 : chained request. */
6703 70 : if (CVAL(req->vwv+0, 0) != 0xff) {
6704 0 : DEBUG(0,("reply_lockingX: Error : pure oplock "
6705 : "break is a chained %d request !\n",
6706 : (unsigned int)CVAL(req->vwv+0, 0)));
6707 : }
6708 70 : END_PROFILE(SMBlockingX);
6709 70 : return;
6710 : }
6711 : }
6712 :
6713 11250 : if (req->buflen <
6714 5638 : (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
6715 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6716 0 : END_PROFILE(SMBlockingX);
6717 0 : return;
6718 : }
6719 :
6720 5625 : if (num_ulocks != 0) {
6721 1569 : struct smbd_lock_element *ulocks = NULL;
6722 5 : bool ok;
6723 :
6724 1569 : ulocks = talloc_array(
6725 : req, struct smbd_lock_element, num_ulocks);
6726 1569 : if (ulocks == NULL) {
6727 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6728 0 : END_PROFILE(SMBlockingX);
6729 0 : return;
6730 : }
6731 :
6732 : /*
6733 : * Data now points at the beginning of the list of
6734 : * smb_unlkrng structs
6735 : */
6736 3150 : for (i = 0; i < num_ulocks; i++) {
6737 1581 : ulocks[i].req_guid = smbd_request_guid(req,
6738 1581 : UINT16_MAX - i),
6739 1581 : ulocks[i].smblctx = get_lock_pid(
6740 : data, i, large_file_format);
6741 1581 : ulocks[i].count = get_lock_count(
6742 : data, i, large_file_format);
6743 1581 : ulocks[i].offset = get_lock_offset(
6744 : data, i, large_file_format);
6745 1581 : ulocks[i].brltype = UNLOCK_LOCK;
6746 1581 : ulocks[i].lock_flav = WINDOWS_LOCK;
6747 : }
6748 :
6749 : /*
6750 : * Unlock cancels pending locks
6751 : */
6752 :
6753 1574 : ok = smbd_smb1_brl_finish_by_lock(
6754 : fsp,
6755 : large_file_format,
6756 : ulocks[0],
6757 1569 : NT_STATUS_OK);
6758 1569 : if (ok) {
6759 2 : reply_smb1_outbuf(req, 2, 0);
6760 2 : SSVAL(req->outbuf, smb_vwv0, 0xff);
6761 2 : SSVAL(req->outbuf, smb_vwv1, 0);
6762 2 : END_PROFILE(SMBlockingX);
6763 2 : return;
6764 : }
6765 :
6766 1567 : status = smbd_do_unlocking(
6767 : req, fsp, num_ulocks, ulocks);
6768 1567 : TALLOC_FREE(ulocks);
6769 1567 : if (!NT_STATUS_IS_OK(status)) {
6770 66 : END_PROFILE(SMBlockingX);
6771 66 : reply_nterror(req, status);
6772 66 : return;
6773 : }
6774 : }
6775 :
6776 : /* Now do any requested locks */
6777 5557 : data += ((large_file_format ? 20 : 10)*num_ulocks);
6778 :
6779 : /* Data now points at the beginning of the list
6780 : of smb_lkrng structs */
6781 :
6782 5557 : if (locktype & LOCKING_ANDX_SHARED_LOCK) {
6783 216 : brltype = READ_LOCK;
6784 : } else {
6785 5341 : brltype = WRITE_LOCK;
6786 : }
6787 :
6788 5557 : locks = talloc_array(req, struct smbd_lock_element, num_locks);
6789 5557 : if (locks == NULL) {
6790 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6791 0 : END_PROFILE(SMBlockingX);
6792 0 : return;
6793 : }
6794 :
6795 9647 : for (i = 0; i < num_locks; i++) {
6796 4090 : locks[i].req_guid = smbd_request_guid(req, i),
6797 4090 : locks[i].smblctx = get_lock_pid(data, i, large_file_format);
6798 4090 : locks[i].count = get_lock_count(data, i, large_file_format);
6799 4090 : locks[i].offset = get_lock_offset(data, i, large_file_format);
6800 4090 : locks[i].brltype = brltype;
6801 4090 : locks[i].lock_flav = WINDOWS_LOCK;
6802 : }
6803 :
6804 5557 : if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
6805 :
6806 0 : bool ok;
6807 :
6808 24 : if (num_locks == 0) {
6809 : /* See smbtorture3 lock11 test */
6810 4 : reply_smb1_outbuf(req, 2, 0);
6811 : /* andx chain ends */
6812 4 : SSVAL(req->outbuf, smb_vwv0, 0xff);
6813 4 : SSVAL(req->outbuf, smb_vwv1, 0);
6814 4 : END_PROFILE(SMBlockingX);
6815 4 : return;
6816 : }
6817 :
6818 20 : ok = smbd_smb1_brl_finish_by_lock(
6819 : fsp,
6820 : large_file_format,
6821 : locks[0], /* Windows only cancels the first lock */
6822 20 : NT_STATUS_FILE_LOCK_CONFLICT);
6823 :
6824 20 : if (!ok) {
6825 10 : reply_force_doserror(req, ERRDOS, ERRcancelviolation);
6826 10 : END_PROFILE(SMBlockingX);
6827 10 : return;
6828 : }
6829 :
6830 10 : reply_smb1_outbuf(req, 2, 0);
6831 10 : SSVAL(req->outbuf, smb_vwv0, 0xff);
6832 10 : SSVAL(req->outbuf, smb_vwv1, 0);
6833 10 : END_PROFILE(SMBlockingX);
6834 10 : return;
6835 : }
6836 :
6837 5548 : subreq = smbd_smb1_do_locks_send(
6838 : fsp,
6839 5533 : req->sconn->ev_ctx,
6840 : &req,
6841 : fsp,
6842 : lock_timeout,
6843 : large_file_format,
6844 : num_locks,
6845 : locks);
6846 5533 : if (subreq == NULL) {
6847 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6848 0 : END_PROFILE(SMBlockingX);
6849 0 : return;
6850 : }
6851 5533 : tevent_req_set_callback(subreq, reply_lockingx_done, NULL);
6852 5533 : END_PROFILE(SMBlockingX);
6853 : }
6854 :
6855 5533 : static void reply_lockingx_done(struct tevent_req *subreq)
6856 : {
6857 5533 : struct smb_request *req = NULL;
6858 15 : NTSTATUS status;
6859 15 : bool ok;
6860 :
6861 5533 : START_PROFILE(SMBlockingX);
6862 :
6863 5533 : ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
6864 5533 : SMB_ASSERT(ok);
6865 :
6866 5533 : status = smbd_smb1_do_locks_recv(subreq);
6867 5533 : TALLOC_FREE(subreq);
6868 :
6869 5533 : DBG_DEBUG("smbd_smb1_do_locks_recv returned %s\n", nt_errstr(status));
6870 :
6871 5533 : if (NT_STATUS_IS_OK(status)) {
6872 3381 : reply_smb1_outbuf(req, 2, 0);
6873 3381 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
6874 3381 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
6875 : } else {
6876 2152 : reply_nterror(req, status);
6877 : }
6878 :
6879 5563 : ok = smb1_srv_send(req->xconn,
6880 5533 : (char *)req->outbuf,
6881 : true,
6882 5533 : req->seqnum + 1,
6883 5533 : IS_CONN_ENCRYPTED(req->conn));
6884 5533 : if (!ok) {
6885 0 : exit_server_cleanly("reply_lock_done: smb1_srv_send failed.");
6886 : }
6887 5533 : TALLOC_FREE(req);
6888 5533 : END_PROFILE(SMBlockingX);
6889 5533 : }
6890 :
6891 : #undef DBGC_CLASS
6892 : #define DBGC_CLASS DBGC_ALL
6893 :
6894 : /****************************************************************************
6895 : Reply to a SMBreadbmpx (read block multiplex) request.
6896 : Always reply with an error, if someone has a platform really needs this,
6897 : please contact vl@samba.org
6898 : ****************************************************************************/
6899 :
6900 0 : void reply_readbmpx(struct smb_request *req)
6901 : {
6902 0 : START_PROFILE(SMBreadBmpx);
6903 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
6904 0 : END_PROFILE(SMBreadBmpx);
6905 0 : return;
6906 : }
6907 :
6908 : /****************************************************************************
6909 : Reply to a SMBreadbs (read block multiplex secondary) request.
6910 : Always reply with an error, if someone has a platform really needs this,
6911 : please contact vl@samba.org
6912 : ****************************************************************************/
6913 :
6914 0 : void reply_readbs(struct smb_request *req)
6915 : {
6916 0 : START_PROFILE(SMBreadBs);
6917 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
6918 0 : END_PROFILE(SMBreadBs);
6919 0 : return;
6920 : }
6921 :
6922 : /****************************************************************************
6923 : Reply to a SMBsetattrE.
6924 : ****************************************************************************/
6925 :
6926 0 : void reply_setattrE(struct smb_request *req)
6927 : {
6928 0 : connection_struct *conn = req->conn;
6929 0 : struct smb_file_time ft;
6930 0 : files_struct *fsp;
6931 0 : NTSTATUS status;
6932 :
6933 0 : START_PROFILE(SMBsetattrE);
6934 0 : init_smb_file_time(&ft);
6935 :
6936 0 : if (req->wct < 7) {
6937 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6938 0 : goto out;
6939 : }
6940 :
6941 0 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6942 :
6943 0 : if(!fsp || (fsp->conn != conn)) {
6944 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
6945 0 : goto out;
6946 : }
6947 :
6948 : /*
6949 : * Convert the DOS times into unix times.
6950 : */
6951 :
6952 0 : ft.atime = time_t_to_full_timespec(
6953 0 : srv_make_unix_date2(req->vwv+3));
6954 0 : ft.mtime = time_t_to_full_timespec(
6955 0 : srv_make_unix_date2(req->vwv+5));
6956 0 : ft.create_time = time_t_to_full_timespec(
6957 0 : srv_make_unix_date2(req->vwv+1));
6958 :
6959 0 : reply_smb1_outbuf(req, 0, 0);
6960 :
6961 : /*
6962 : * Patch from Ray Frush <frush@engr.colostate.edu>
6963 : * Sometimes times are sent as zero - ignore them.
6964 : */
6965 :
6966 : /* Ensure we have a valid stat struct for the source. */
6967 0 : status = vfs_stat_fsp(fsp);
6968 0 : if (!NT_STATUS_IS_OK(status)) {
6969 0 : reply_nterror(req, status);
6970 0 : goto out;
6971 : }
6972 :
6973 0 : status = check_any_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
6974 0 : if (!NT_STATUS_IS_OK(status)) {
6975 0 : reply_nterror(req, status);
6976 0 : goto out;
6977 : }
6978 :
6979 0 : status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
6980 0 : if (!NT_STATUS_IS_OK(status)) {
6981 0 : reply_nterror(req, status);
6982 0 : goto out;
6983 : }
6984 :
6985 0 : if (fsp->fsp_flags.modified) {
6986 0 : trigger_write_time_update_immediate(fsp);
6987 : }
6988 :
6989 0 : DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
6990 : " createtime=%u\n",
6991 : fsp_fnum_dbg(fsp),
6992 : (unsigned int)ft.atime.tv_sec,
6993 : (unsigned int)ft.mtime.tv_sec,
6994 : (unsigned int)ft.create_time.tv_sec
6995 : ));
6996 0 : out:
6997 0 : END_PROFILE(SMBsetattrE);
6998 0 : return;
6999 : }
7000 :
7001 :
7002 : /* Back from the dead for OS/2..... JRA. */
7003 :
7004 : /****************************************************************************
7005 : Reply to a SMBwritebmpx (write block multiplex primary) request.
7006 : Always reply with an error, if someone has a platform really needs this,
7007 : please contact vl@samba.org
7008 : ****************************************************************************/
7009 :
7010 0 : void reply_writebmpx(struct smb_request *req)
7011 : {
7012 0 : START_PROFILE(SMBwriteBmpx);
7013 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
7014 0 : END_PROFILE(SMBwriteBmpx);
7015 0 : return;
7016 : }
7017 :
7018 : /****************************************************************************
7019 : Reply to a SMBwritebs (write block multiplex secondary) request.
7020 : Always reply with an error, if someone has a platform really needs this,
7021 : please contact vl@samba.org
7022 : ****************************************************************************/
7023 :
7024 0 : void reply_writebs(struct smb_request *req)
7025 : {
7026 0 : START_PROFILE(SMBwriteBs);
7027 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
7028 0 : END_PROFILE(SMBwriteBs);
7029 0 : return;
7030 : }
7031 :
7032 : /****************************************************************************
7033 : Reply to a SMBgetattrE.
7034 : ****************************************************************************/
7035 :
7036 10 : void reply_getattrE(struct smb_request *req)
7037 : {
7038 10 : connection_struct *conn = req->conn;
7039 2 : int mode;
7040 2 : files_struct *fsp;
7041 2 : struct timespec create_ts;
7042 2 : NTSTATUS status;
7043 :
7044 10 : START_PROFILE(SMBgetattrE);
7045 :
7046 10 : if (req->wct < 1) {
7047 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7048 0 : END_PROFILE(SMBgetattrE);
7049 0 : return;
7050 : }
7051 :
7052 10 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7053 :
7054 10 : if(!fsp || (fsp->conn != conn)) {
7055 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7056 0 : END_PROFILE(SMBgetattrE);
7057 0 : return;
7058 : }
7059 :
7060 : /* Do an fstat on this file */
7061 10 : status = vfs_stat_fsp(fsp);
7062 10 : if (!NT_STATUS_IS_OK(status)) {
7063 0 : reply_nterror(req, status);
7064 0 : END_PROFILE(SMBgetattrE);
7065 0 : return;
7066 : }
7067 :
7068 10 : mode = fdos_mode(fsp);
7069 :
7070 : /*
7071 : * Convert the times into dos times. Set create
7072 : * date to be last modify date as UNIX doesn't save
7073 : * this.
7074 : */
7075 :
7076 10 : reply_smb1_outbuf(req, 11, 0);
7077 :
7078 10 : create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7079 10 : srv_put_dos_date2_ts((char *)req->outbuf, smb_vwv0, create_ts);
7080 10 : srv_put_dos_date2_ts((char *)req->outbuf,
7081 : smb_vwv2,
7082 10 : fsp->fsp_name->st.st_ex_atime);
7083 : /* Should we check pending modtime here ? JRA */
7084 10 : srv_put_dos_date2_ts((char *)req->outbuf,
7085 : smb_vwv4,
7086 10 : fsp->fsp_name->st.st_ex_mtime);
7087 :
7088 10 : if (mode & FILE_ATTRIBUTE_DIRECTORY) {
7089 0 : SIVAL(req->outbuf, smb_vwv6, 0);
7090 0 : SIVAL(req->outbuf, smb_vwv8, 0);
7091 : } else {
7092 10 : uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
7093 10 : SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
7094 10 : SIVAL(req->outbuf, smb_vwv8, allocation_size);
7095 : }
7096 10 : SSVAL(req->outbuf,smb_vwv10, mode);
7097 :
7098 10 : DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
7099 :
7100 10 : END_PROFILE(SMBgetattrE);
7101 8 : return;
7102 : }
7103 :
7104 : /****************************************************************************
7105 : Reply to a SMBfindclose (stop trans2 directory search).
7106 : ****************************************************************************/
7107 :
7108 0 : void reply_findclose(struct smb_request *req)
7109 : {
7110 0 : int dptr_num;
7111 0 : struct smbd_server_connection *sconn = req->sconn;
7112 0 : files_struct *fsp = NULL;
7113 :
7114 0 : START_PROFILE(SMBfindclose);
7115 :
7116 0 : if (req->wct < 1) {
7117 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7118 0 : END_PROFILE(SMBfindclose);
7119 0 : return;
7120 : }
7121 :
7122 0 : dptr_num = SVALS(req->vwv+0, 0);
7123 :
7124 0 : DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
7125 :
7126 : /*
7127 : * OS/2 seems to use -1 to indicate "close all directories"
7128 : * This has to mean on this specific connection struct.
7129 : */
7130 0 : if (dptr_num == -1) {
7131 0 : dptr_closecnum(req->conn);
7132 : } else {
7133 0 : fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
7134 0 : dptr_num = -1;
7135 0 : if (fsp != NULL) {
7136 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
7137 : }
7138 : }
7139 :
7140 0 : reply_smb1_outbuf(req, 0, 0);
7141 :
7142 0 : DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
7143 :
7144 0 : END_PROFILE(SMBfindclose);
7145 0 : return;
7146 : }
7147 :
7148 : /****************************************************************************
7149 : Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
7150 : ****************************************************************************/
7151 :
7152 0 : void reply_findnclose(struct smb_request *req)
7153 : {
7154 0 : int dptr_num;
7155 :
7156 0 : START_PROFILE(SMBfindnclose);
7157 :
7158 0 : if (req->wct < 1) {
7159 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7160 0 : END_PROFILE(SMBfindnclose);
7161 0 : return;
7162 : }
7163 :
7164 0 : dptr_num = SVAL(req->vwv+0, 0);
7165 :
7166 0 : DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
7167 :
7168 : /* We never give out valid handles for a
7169 : findnotifyfirst - so any dptr_num is ok here.
7170 : Just ignore it. */
7171 :
7172 0 : reply_smb1_outbuf(req, 0, 0);
7173 :
7174 0 : DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
7175 :
7176 0 : END_PROFILE(SMBfindnclose);
7177 0 : return;
7178 : }
|