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