Changeset 745 for trunk/server/source3/smbd/smb2_create.c
- Timestamp:
- Nov 27, 2012, 4:43:17 PM (13 years ago)
- Location:
- trunk/server
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/server
- Property svn:mergeinfo changed
/vendor/current merged: 581,587,591,594,597,600,615,618,740
- Property svn:mergeinfo changed
-
trunk/server/source3/smbd/smb2_create.c
r480 r745 4 4 5 5 Copyright (C) Stefan Metzmacher 2009 6 Copyright (C) Jeremy Allison 2010 6 7 7 8 This program is free software; you can redistribute it and/or modify … … 20 21 21 22 #include "includes.h" 23 #include "printing.h" 24 #include "smbd/smbd.h" 22 25 #include "smbd/globals.h" 23 26 #include "../libcli/smb/smb_common.h" 27 #include "../librpc/gen_ndr/ndr_security.h" 28 #include "../lib/util/tevent_ntstatus.h" 29 30 int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level) 31 { 32 switch(in_oplock_level) { 33 case SMB2_OPLOCK_LEVEL_NONE: 34 return NO_OPLOCK; 35 case SMB2_OPLOCK_LEVEL_II: 36 return LEVEL_II_OPLOCK; 37 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: 38 return EXCLUSIVE_OPLOCK; 39 case SMB2_OPLOCK_LEVEL_BATCH: 40 return BATCH_OPLOCK; 41 case SMB2_OPLOCK_LEVEL_LEASE: 42 DEBUG(2,("map_smb2_oplock_levels_to_samba: " 43 "LEASE_OPLOCK_REQUESTED\n")); 44 return NO_OPLOCK; 45 default: 46 DEBUG(2,("map_smb2_oplock_levels_to_samba: " 47 "unknown level %u\n", 48 (unsigned int)in_oplock_level)); 49 return NO_OPLOCK; 50 } 51 } 52 53 static uint8_t map_samba_oplock_levels_to_smb2(int oplock_type) 54 { 55 if (BATCH_OPLOCK_TYPE(oplock_type)) { 56 return SMB2_OPLOCK_LEVEL_BATCH; 57 } else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type)) { 58 return SMB2_OPLOCK_LEVEL_EXCLUSIVE; 59 } else if (oplock_type == LEVEL_II_OPLOCK) { 60 /* 61 * Don't use LEVEL_II_OPLOCK_TYPE here as 62 * this also includes FAKE_LEVEL_II_OPLOCKs 63 * which are internal only. 64 */ 65 return SMB2_OPLOCK_LEVEL_II; 66 } else { 67 return SMB2_OPLOCK_LEVEL_NONE; 68 } 69 } 24 70 25 71 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, … … 46 92 uint64_t *out_end_of_file, 47 93 uint32_t *out_file_attributes, 94 uint64_t *out_file_id_persistent, 48 95 uint64_t *out_file_id_volatile, 49 96 struct smb2_create_blobs *out_context_blobs); 50 97 51 static void smbd_smb2_request_create_done(struct tevent_req * subreq);52 NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request * req)98 static void smbd_smb2_request_create_done(struct tevent_req *tsubreq); 99 NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req) 53 100 { 54 101 const uint8_t *inbody; 55 int i = req->current_idx;102 int i = smb2req->current_idx; 56 103 size_t expected_body_size = 0x39; 57 104 size_t body_size; … … 79 126 NTSTATUS status; 80 127 bool ok; 81 struct tevent_req * subreq;82 83 if ( req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {84 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);85 } 86 87 inbody = (const uint8_t *) req->in.vector[i+1].iov_base;128 struct tevent_req *tsubreq; 129 130 if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { 131 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 132 } 133 134 inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base; 88 135 89 136 body_size = SVAL(inbody, 0x00); 90 137 if (body_size != expected_body_size) { 91 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);138 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 92 139 } 93 140 … … 118 165 name_offset = 0; 119 166 } else if (in_name_offset < dyn_offset) { 120 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);167 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 121 168 } else { 122 169 name_offset = in_name_offset - dyn_offset; 123 170 } 124 171 125 if (name_offset > req->in.vector[i+2].iov_len) {126 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);127 } 128 129 name_available_length = req->in.vector[i+2].iov_len - name_offset;172 if (name_offset > smb2req->in.vector[i+2].iov_len) { 173 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 174 } 175 176 name_available_length = smb2req->in.vector[i+2].iov_len - name_offset; 130 177 131 178 if (in_name_length > name_available_length) { 132 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);133 } 134 135 in_name_buffer.data = (uint8_t *) req->in.vector[i+2].iov_base +179 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 180 } 181 182 in_name_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base + 136 183 name_offset; 137 184 in_name_buffer.length = in_name_length; … … 141 188 context_offset = 0; 142 189 } else if (in_context_offset < dyn_offset) { 143 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);190 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 144 191 } else { 145 192 context_offset = in_context_offset - dyn_offset; 146 193 } 147 194 148 if (context_offset > req->in.vector[i+2].iov_len) {149 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);150 } 151 152 context_available_length = req->in.vector[i+2].iov_len - context_offset;195 if (context_offset > smb2req->in.vector[i+2].iov_len) { 196 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 197 } 198 199 context_available_length = smb2req->in.vector[i+2].iov_len - context_offset; 153 200 154 201 if (in_context_length > context_available_length) { 155 return smbd_smb2_request_error( req, NT_STATUS_INVALID_PARAMETER);156 } 157 158 in_context_buffer.data = (uint8_t *) req->in.vector[i+2].iov_base +202 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); 203 } 204 205 in_context_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base + 159 206 context_offset; 160 207 in_context_buffer.length = in_context_length; … … 164 211 */ 165 212 166 ok = convert_string_talloc( req, CH_UTF16, CH_UNIX,213 ok = convert_string_talloc(smb2req, CH_UTF16, CH_UNIX, 167 214 in_name_buffer.data, 168 215 in_name_buffer.length, … … 170 217 &in_name_string_size, false); 171 218 if (!ok) { 172 return smbd_smb2_request_error( req, NT_STATUS_ILLEGAL_CHARACTER);219 return smbd_smb2_request_error(smb2req, NT_STATUS_ILLEGAL_CHARACTER); 173 220 } 174 221 175 222 ZERO_STRUCT(in_context_blobs); 176 status = smb2_create_blob_parse( req, in_context_buffer, &in_context_blobs);223 status = smb2_create_blob_parse(smb2req, in_context_buffer, &in_context_blobs); 177 224 if (!NT_STATUS_IS_OK(status)) { 178 return smbd_smb2_request_error( req, status);179 } 180 181 subreq = smbd_smb2_create_send(req,182 req->sconn->smb2.event_ctx,183 req,225 return smbd_smb2_request_error(smb2req, status); 226 } 227 228 tsubreq = smbd_smb2_create_send(smb2req, 229 smb2req->sconn->smb2.event_ctx, 230 smb2req, 184 231 in_oplock_level, 185 232 in_impersonation_level, … … 191 238 in_name_string, 192 239 in_context_blobs); 193 if (subreq == NULL) { 194 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); 195 } 196 tevent_req_set_callback(subreq, smbd_smb2_request_create_done, req); 197 198 return smbd_smb2_request_pending_queue(req, subreq); 199 } 200 201 static void smbd_smb2_request_create_done(struct tevent_req *subreq) 202 { 203 struct smbd_smb2_request *req = tevent_req_callback_data(subreq, 240 if (tsubreq == NULL) { 241 smb2req->subreq = NULL; 242 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); 243 } 244 tevent_req_set_callback(tsubreq, smbd_smb2_request_create_done, smb2req); 245 246 return smbd_smb2_request_pending_queue(smb2req, tsubreq); 247 } 248 249 static uint64_t get_mid_from_smb2req(struct smbd_smb2_request *smb2req) 250 { 251 uint8_t *reqhdr = (uint8_t *)smb2req->out.vector[smb2req->current_idx].iov_base; 252 return BVAL(reqhdr, SMB2_HDR_MESSAGE_ID); 253 } 254 255 static void smbd_smb2_request_create_done(struct tevent_req *tsubreq) 256 { 257 struct smbd_smb2_request *smb2req = tevent_req_callback_data(tsubreq, 204 258 struct smbd_smb2_request); 205 int i = req->current_idx;259 int i = smb2req->current_idx; 206 260 uint8_t *outhdr; 207 261 DATA_BLOB outbody; … … 216 270 uint64_t out_end_of_file = 0; 217 271 uint32_t out_file_attributes = 0; 272 uint64_t out_file_id_persistent = 0; 218 273 uint64_t out_file_id_volatile = 0; 219 274 struct smb2_create_blobs out_context_blobs; … … 223 278 NTSTATUS error; /* transport error */ 224 279 225 status = smbd_smb2_create_recv(subreq, 226 req, 280 if (smb2req->cancelled) { 281 uint64_t mid = get_mid_from_smb2req(smb2req); 282 DEBUG(10,("smbd_smb2_request_create_done: cancelled mid %llu\n", 283 (unsigned long long)mid )); 284 error = smbd_smb2_request_error(smb2req, NT_STATUS_CANCELLED); 285 if (!NT_STATUS_IS_OK(error)) { 286 smbd_server_connection_terminate(smb2req->sconn, 287 nt_errstr(error)); 288 return; 289 } 290 return; 291 } 292 293 status = smbd_smb2_create_recv(tsubreq, 294 smb2req, 227 295 &out_oplock_level, 228 296 &out_create_action, … … 234 302 &out_end_of_file, 235 303 &out_file_attributes, 304 &out_file_id_persistent, 236 305 &out_file_id_volatile, 237 306 &out_context_blobs); 238 TALLOC_FREE(subreq);239 307 if (!NT_STATUS_IS_OK(status)) { 240 error = smbd_smb2_request_error( req, status);308 error = smbd_smb2_request_error(smb2req, status); 241 309 if (!NT_STATUS_IS_OK(error)) { 242 smbd_server_connection_terminate( req->sconn,310 smbd_server_connection_terminate(smb2req->sconn, 243 311 nt_errstr(error)); 244 312 return; … … 247 315 } 248 316 249 status = smb2_create_blob_push( req, &out_context_buffer, out_context_blobs);317 status = smb2_create_blob_push(smb2req, &out_context_buffer, out_context_blobs); 250 318 if (!NT_STATUS_IS_OK(status)) { 251 error = smbd_smb2_request_error( req, status);319 error = smbd_smb2_request_error(smb2req, status); 252 320 if (!NT_STATUS_IS_OK(error)) { 253 smbd_server_connection_terminate( req->sconn,321 smbd_server_connection_terminate(smb2req->sconn, 254 322 nt_errstr(error)); 255 323 return; … … 262 330 } 263 331 264 outhdr = (uint8_t *) req->out.vector[i].iov_base;265 266 outbody = data_blob_talloc( req->out.vector, NULL, 0x58);332 outhdr = (uint8_t *)smb2req->out.vector[i].iov_base; 333 334 outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x58); 267 335 if (outbody.data == NULL) { 268 error = smbd_smb2_request_error( req, NT_STATUS_NO_MEMORY);336 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); 269 337 if (!NT_STATUS_IS_OK(error)) { 270 smbd_server_connection_terminate( req->sconn,338 smbd_server_connection_terminate(smb2req->sconn, 271 339 nt_errstr(error)); 272 340 return; … … 296 364 out_file_attributes); /* file attributes */ 297 365 SIVAL(outbody.data, 0x3C, 0); /* reserved */ 298 SBVAL(outbody.data, 0x40, 0); /* file id (persistent) */ 366 SBVAL(outbody.data, 0x40, 367 out_file_id_persistent); /* file id (persistent) */ 299 368 SBVAL(outbody.data, 0x48, 300 369 out_file_id_volatile); /* file id (volatile) */ … … 306 375 outdyn = out_context_buffer; 307 376 308 error = smbd_smb2_request_done( req, outbody, &outdyn);377 error = smbd_smb2_request_done(smb2req, outbody, &outdyn); 309 378 if (!NT_STATUS_IS_OK(error)) { 310 smbd_server_connection_terminate( req->sconn,379 smbd_server_connection_terminate(smb2req->sconn, 311 380 nt_errstr(error)); 312 381 return; … … 316 385 struct smbd_smb2_create_state { 317 386 struct smbd_smb2_request *smb2req; 387 struct smb_request *smb1req; 388 struct timed_event *te; 389 struct tevent_immediate *im; 390 struct timeval request_time; 391 struct file_id id; 392 DATA_BLOB private_data; 318 393 uint8_t out_oplock_level; 319 394 uint32_t out_create_action; … … 325 400 uint64_t out_end_of_file; 326 401 uint32_t out_file_attributes; 402 uint64_t out_file_id_persistent; 327 403 uint64_t out_file_id_volatile; 328 404 struct smb2_create_blobs out_context_blobs; … … 342 418 struct smb2_create_blobs in_context_blobs) 343 419 { 344 struct tevent_req *req ;345 struct smbd_smb2_create_state *state ;420 struct tevent_req *req = NULL; 421 struct smbd_smb2_create_state *state = NULL; 346 422 NTSTATUS status; 347 struct smb_request *smb req;348 files_struct *result ;423 struct smb_request *smb1req = NULL; 424 files_struct *result = NULL; 349 425 int info; 350 426 struct timespec write_time_ts; 351 427 struct smb2_create_blobs out_context_blobs; 428 int requested_oplock_level; 352 429 353 430 ZERO_STRUCT(out_context_blobs); 354 431 355 req = tevent_req_create(mem_ctx, &state, 432 if(lp_fake_oplocks(SNUM(smb2req->tcon->compat_conn))) { 433 requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 434 } else { 435 requested_oplock_level = in_oplock_level; 436 } 437 438 439 if (!smb2req->async) { 440 /* New create call. */ 441 req = tevent_req_create(mem_ctx, &state, 356 442 struct smbd_smb2_create_state); 357 if (req == NULL) { 358 return NULL; 359 } 360 state->smb2req = smb2req; 361 362 DEBUG(10,("smbd_smb2_create: name[%s]\n", 363 in_name)); 364 365 smbreq = smbd_smb2_fake_smb_request(smb2req); 366 if (tevent_req_nomem(smbreq, req)) { 367 return tevent_req_post(req, ev); 368 } 369 370 if (IS_IPC(smbreq->conn)) { 443 if (req == NULL) { 444 return NULL; 445 } 446 state->smb2req = smb2req; 447 smb2req->subreq = req; /* So we can find this when going async. */ 448 449 smb1req = smbd_smb2_fake_smb_request(smb2req); 450 if (tevent_req_nomem(smb1req, req)) { 451 return tevent_req_post(req, ev); 452 } 453 state->smb1req = smb1req; 454 DEBUG(10,("smbd_smb2_create: name[%s]\n", 455 in_name)); 456 } else { 457 /* Re-entrant create call. */ 458 req = smb2req->subreq; 459 state = tevent_req_data(req, 460 struct smbd_smb2_create_state); 461 smb1req = state->smb1req; 462 DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n", 463 in_name )); 464 } 465 466 if (IS_IPC(smb1req->conn)) { 371 467 const char *pipe_name = in_name; 372 468 … … 381 477 } 382 478 383 status = open_np_file(smb req, pipe_name, &result);479 status = open_np_file(smb1req, pipe_name, &result); 384 480 if (!NT_STATUS_IS_OK(status)) { 385 481 tevent_req_nterror(req, status); … … 387 483 } 388 484 info = FILE_WAS_OPENED; 389 } else if (CAN_PRINT(smb req->conn)) {390 status = file_new(smb req, smbreq->conn, &result);485 } else if (CAN_PRINT(smb1req->conn)) { 486 status = file_new(smb1req, smb1req->conn, &result); 391 487 if(!NT_STATUS_IS_OK(status)) { 392 488 tevent_req_nterror(req, status); … … 394 490 } 395 491 396 status = print_fsp_open(smbreq, 397 smbreq->conn, 398 in_name, 399 smbreq->vuid, 400 result); 492 status = print_spool_open(result, in_name, 493 smb1req->vuid); 401 494 if (!NT_STATUS_IS_OK(status)) { 402 file_free(smb req, result);495 file_free(smb1req, result); 403 496 tevent_req_nterror(req, status); 404 497 return tevent_req_post(req, ev); … … 488 581 489 582 ndr_err = ndr_pull_struct_blob(&secd->data, 490 sec_desc, NULL,sec_desc,583 sec_desc, sec_desc, 491 584 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); 492 585 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { … … 582 675 in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */ 583 676 584 /* convert '\\' into '/' */ 585 status = check_path_syntax(fname); 586 if (!NT_STATUS_IS_OK(status)) { 587 tevent_req_nterror(req, status); 588 return tevent_req_post(req, ev); 677 /* 678 * For a DFS path the function parse_dfs_path() 679 * will do the path processing. 680 */ 681 682 if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) { 683 /* convert '\\' into '/' */ 684 status = check_path_syntax(fname); 685 if (!NT_STATUS_IS_OK(status)) { 686 tevent_req_nterror(req, status); 687 return tevent_req_post(req, ev); 688 } 589 689 } 590 690 591 691 status = filename_convert(req, 592 smb req->conn,593 smb req->flags2 & FLAGS2_DFS_PATHNAMES,692 smb1req->conn, 693 smb1req->flags2 & FLAGS2_DFS_PATHNAMES, 594 694 fname, 595 695 0, … … 601 701 } 602 702 603 status = SMB_VFS_CREATE_FILE(smbreq->conn, 604 smbreq, 703 in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; 704 705 status = SMB_VFS_CREATE_FILE(smb1req->conn, 706 smb1req, 605 707 0, /* root_dir_fid */ 606 708 smb_fname, … … 610 712 in_create_options, 611 713 in_file_attributes, 612 0, /* oplock_request */714 map_smb2_oplock_levels_to_samba(requested_oplock_level), 613 715 allocation_size, 716 0, /* private_flags */ 614 717 sec_desc, 615 718 ea_list, … … 617 720 &info); 618 721 if (!NT_STATUS_IS_OK(status)) { 722 if (open_was_deferred(smb1req->mid)) { 723 return req; 724 } 619 725 tevent_req_nterror(req, status); 620 726 return tevent_req_post(req, ev); … … 631 737 DATA_BLOB blob = data_blob_const(p, sizeof(p)); 632 738 633 status = smbd_c heck_open_rights(smbreq->conn,739 status = smbd_calculate_access_mask(smb1req->conn, 634 740 result->fsp_name, 741 /* 742 * at this stage 743 * it exists 744 */ 745 true, 635 746 SEC_FLAG_MAXIMUM_ALLOWED, 636 747 &max_access_granted); … … 675 786 } 676 787 677 smb2req->compat_chain_fsp = smbreq->chain_fsp; 678 679 state->out_oplock_level = 0; 788 smb2req->compat_chain_fsp = smb1req->chain_fsp; 789 790 if(lp_fake_oplocks(SNUM(smb2req->tcon->compat_conn))) { 791 state->out_oplock_level = in_oplock_level; 792 } else { 793 state->out_oplock_level = map_samba_oplock_levels_to_smb2(result->oplock_type); 794 } 795 680 796 if ((in_create_disposition == FILE_SUPERSEDE) 681 797 && (info == FILE_WAS_OVERWRITTEN)) { … … 689 805 write time. JRA. */ 690 806 ZERO_STRUCT(write_time_ts); 691 get_file_infos(result->file_id, NULL, &write_time_ts);807 get_file_infos(result->file_id, 0, NULL, &write_time_ts); 692 808 if (!null_timespec(write_time_ts)) { 693 809 update_stat_ex_mtime(&result->fsp_name->st, write_time_ts); … … 695 811 696 812 unix_timespec_to_nt_time(&state->out_creation_time, 697 get_create_timespec(smb req->conn, result,813 get_create_timespec(smb1req->conn, result, 698 814 result->fsp_name)); 699 815 unix_timespec_to_nt_time(&state->out_last_access_time, … … 702 818 result->fsp_name->st.st_ex_mtime); 703 819 unix_timespec_to_nt_time(&state->out_change_time, 704 get_change_timespec(smb req->conn, result,820 get_change_timespec(smb1req->conn, result, 705 821 result->fsp_name)); 706 822 state->out_allocation_size = … … 711 827 state->out_file_attributes = FILE_ATTRIBUTE_NORMAL; 712 828 } 829 state->out_file_id_persistent = result->fnum; 713 830 state->out_file_id_volatile = result->fnum; 714 831 state->out_context_blobs = out_context_blobs; … … 729 846 uint64_t *out_end_of_file, 730 847 uint32_t *out_file_attributes, 848 uint64_t *out_file_id_persistent, 731 849 uint64_t *out_file_id_volatile, 732 850 struct smb2_create_blobs *out_context_blobs) … … 750 868 *out_end_of_file = state->out_end_of_file; 751 869 *out_file_attributes = state->out_file_attributes; 870 *out_file_id_persistent = state->out_file_id_persistent; 752 871 *out_file_id_volatile = state->out_file_id_volatile; 753 872 *out_context_blobs = state->out_context_blobs; … … 758 877 return NT_STATUS_OK; 759 878 } 879 880 /********************************************************* 881 Code for dealing with deferred opens. 882 *********************************************************/ 883 884 bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req, 885 struct timeval *p_request_time, 886 void **pp_state) 887 { 888 struct smbd_smb2_create_state *state = NULL; 889 struct tevent_req *req = NULL; 890 891 if (!smb2req) { 892 return false; 893 } 894 if (!smb2req->async) { 895 return false; 896 } 897 req = smb2req->subreq; 898 if (!req) { 899 return false; 900 } 901 state = tevent_req_data(req, struct smbd_smb2_create_state); 902 if (!state) { 903 return false; 904 } 905 if (p_request_time) { 906 *p_request_time = state->request_time; 907 } 908 if (pp_state) { 909 *pp_state = (void *)state->private_data.data; 910 } 911 return true; 912 } 913 914 /********************************************************* 915 Re-process this call early - requested by message or 916 close. 917 *********************************************************/ 918 919 static struct smbd_smb2_request *find_open_smb2req( 920 struct smbd_server_connection *sconn, uint64_t mid) 921 { 922 struct smbd_smb2_request *smb2req; 923 924 for (smb2req = sconn->smb2.requests; smb2req; smb2req = smb2req->next) { 925 uint64_t message_id; 926 if (smb2req->subreq == NULL) { 927 /* This message has been processed. */ 928 continue; 929 } 930 if (!tevent_req_is_in_progress(smb2req->subreq)) { 931 /* This message has been processed. */ 932 continue; 933 } 934 message_id = get_mid_from_smb2req(smb2req); 935 if (message_id == mid) { 936 return smb2req; 937 } 938 } 939 return NULL; 940 } 941 942 bool open_was_deferred_smb2(struct smbd_server_connection *sconn, uint64_t mid) 943 { 944 struct smbd_smb2_create_state *state = NULL; 945 struct smbd_smb2_request *smb2req; 946 947 smb2req = find_open_smb2req(sconn, mid); 948 949 if (!smb2req) { 950 DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n", 951 (unsigned long long)mid)); 952 return false; 953 } 954 if (!smb2req->subreq) { 955 return false; 956 } 957 if (!tevent_req_is_in_progress(smb2req->subreq)) { 958 return false; 959 } 960 state = tevent_req_data(smb2req->subreq, 961 struct smbd_smb2_create_state); 962 if (!state) { 963 return false; 964 } 965 /* It's not in progress if there's no timeout event. */ 966 if (!state->te) { 967 return false; 968 } 969 970 DEBUG(10,("open_was_deferred_smb2: mid = %llu\n", 971 (unsigned long long)mid)); 972 973 return true; 974 } 975 976 static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request *smb2req, 977 uint64_t mid) 978 { 979 struct smbd_smb2_create_state *state = NULL; 980 981 if (!smb2req->subreq) { 982 return; 983 } 984 if (!tevent_req_is_in_progress(smb2req->subreq)) { 985 return; 986 } 987 state = tevent_req_data(smb2req->subreq, 988 struct smbd_smb2_create_state); 989 if (!state) { 990 return; 991 } 992 993 DEBUG(10,("remove_deferred_open_message_smb2_internal: " 994 "mid %llu\n", 995 (unsigned long long)mid )); 996 997 /* Ensure we don't have any outstanding timer event. */ 998 TALLOC_FREE(state->te); 999 /* Ensure we don't have any outstanding immediate event. */ 1000 TALLOC_FREE(state->im); 1001 } 1002 1003 void remove_deferred_open_message_smb2( 1004 struct smbd_server_connection *sconn, uint64_t mid) 1005 { 1006 struct smbd_smb2_request *smb2req; 1007 1008 smb2req = find_open_smb2req(sconn, mid); 1009 1010 if (!smb2req) { 1011 DEBUG(10,("remove_deferred_open_message_smb2: " 1012 "can't find mid %llu\n", 1013 (unsigned long long)mid )); 1014 return; 1015 } 1016 remove_deferred_open_message_smb2_internal(smb2req, mid); 1017 } 1018 1019 static void smbd_smb2_create_request_dispatch_immediate(struct tevent_context *ctx, 1020 struct tevent_immediate *im, 1021 void *private_data) 1022 { 1023 struct smbd_smb2_request *smb2req = talloc_get_type_abort(private_data, 1024 struct smbd_smb2_request); 1025 struct smbd_server_connection *sconn = smb2req->sconn; 1026 uint64_t mid = get_mid_from_smb2req(smb2req); 1027 NTSTATUS status; 1028 1029 DEBUG(10,("smbd_smb2_create_request_dispatch_immediate: " 1030 "re-dispatching mid %llu\n", 1031 (unsigned long long)mid )); 1032 1033 status = smbd_smb2_request_dispatch(smb2req); 1034 if (!NT_STATUS_IS_OK(status)) { 1035 smbd_server_connection_terminate(sconn, nt_errstr(status)); 1036 return; 1037 } 1038 } 1039 1040 void schedule_deferred_open_message_smb2( 1041 struct smbd_server_connection *sconn, uint64_t mid) 1042 { 1043 struct smbd_smb2_create_state *state = NULL; 1044 struct smbd_smb2_request *smb2req; 1045 1046 smb2req = find_open_smb2req(sconn, mid); 1047 1048 if (!smb2req) { 1049 DEBUG(10,("schedule_deferred_open_message_smb2: " 1050 "can't find mid %llu\n", 1051 (unsigned long long)mid )); 1052 return; 1053 } 1054 if (!smb2req->subreq) { 1055 return; 1056 } 1057 if (!tevent_req_is_in_progress(smb2req->subreq)) { 1058 return; 1059 } 1060 state = tevent_req_data(smb2req->subreq, 1061 struct smbd_smb2_create_state); 1062 if (!state) { 1063 return; 1064 } 1065 1066 /* Ensure we don't have any outstanding timer event. */ 1067 TALLOC_FREE(state->te); 1068 /* Ensure we don't have any outstanding immediate event. */ 1069 TALLOC_FREE(state->im); 1070 1071 /* 1072 * This is subtle. We must null out the callback 1073 * before resheduling, else the first call to 1074 * tevent_req_nterror() causes the _receive() 1075 * function to be called, this causing tevent_req_post() 1076 * to crash. 1077 */ 1078 tevent_req_set_callback(smb2req->subreq, NULL, NULL); 1079 1080 state->im = tevent_create_immediate(smb2req); 1081 if (!state->im) { 1082 smbd_server_connection_terminate(smb2req->sconn, 1083 nt_errstr(NT_STATUS_NO_MEMORY)); 1084 } 1085 1086 DEBUG(10,("schedule_deferred_open_message_smb2: " 1087 "re-processing mid %llu\n", 1088 (unsigned long long)mid )); 1089 1090 tevent_schedule_immediate(state->im, 1091 smb2req->sconn->smb2.event_ctx, 1092 smbd_smb2_create_request_dispatch_immediate, 1093 smb2req); 1094 } 1095 1096 /********************************************************* 1097 Re-process this call. 1098 *********************************************************/ 1099 1100 static void smb2_deferred_open_timer(struct event_context *ev, 1101 struct timed_event *te, 1102 struct timeval _tval, 1103 void *private_data) 1104 { 1105 NTSTATUS status; 1106 struct smbd_smb2_create_state *state = NULL; 1107 struct smbd_smb2_request *smb2req = talloc_get_type(private_data, 1108 struct smbd_smb2_request); 1109 1110 DEBUG(10,("smb2_deferred_open_timer: [idx=%d], %s\n", 1111 smb2req->current_idx, 1112 tevent_req_default_print(smb2req->subreq, talloc_tos()) )); 1113 1114 state = tevent_req_data(smb2req->subreq, 1115 struct smbd_smb2_create_state); 1116 if (!state) { 1117 return; 1118 } 1119 /* 1120 * Null this out, don't talloc_free. It will 1121 * be talloc_free'd by the tevent library when 1122 * this returns. 1123 */ 1124 state->te = NULL; 1125 /* Ensure we don't have any outstanding immediate event. */ 1126 TALLOC_FREE(state->im); 1127 1128 /* 1129 * This is subtle. We must null out the callback 1130 * before resheduling, else the first call to 1131 * tevent_req_nterror() causes the _receive() 1132 * function to be called, this causing tevent_req_post() 1133 * to crash. 1134 */ 1135 tevent_req_set_callback(smb2req->subreq, NULL, NULL); 1136 1137 status = smbd_smb2_request_dispatch(smb2req); 1138 1139 if (!NT_STATUS_IS_OK(status)) { 1140 smbd_server_connection_terminate(smb2req->sconn, 1141 nt_errstr(status)); 1142 } 1143 } 1144 1145 static bool smbd_smb2_create_cancel(struct tevent_req *req) 1146 { 1147 struct smbd_smb2_request *smb2req = NULL; 1148 struct smbd_smb2_create_state *state = tevent_req_data(req, 1149 struct smbd_smb2_create_state); 1150 uint64_t mid; 1151 1152 if (!state) { 1153 return false; 1154 } 1155 1156 if (!state->smb2req) { 1157 return false; 1158 } 1159 1160 smb2req = state->smb2req; 1161 mid = get_mid_from_smb2req(smb2req); 1162 1163 remove_deferred_open_entry(state->id, mid, 1164 sconn_server_id(smb2req->sconn)); 1165 remove_deferred_open_message_smb2_internal(smb2req, mid); 1166 smb2req->cancelled = true; 1167 1168 tevent_req_done(req); 1169 return true; 1170 } 1171 1172 bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req, 1173 struct timeval request_time, 1174 struct timeval timeout, 1175 struct file_id id, 1176 char *private_data, 1177 size_t priv_len) 1178 { 1179 struct tevent_req *req = NULL; 1180 struct smbd_smb2_create_state *state = NULL; 1181 struct timeval end_time; 1182 1183 if (!smb2req) { 1184 return false; 1185 } 1186 req = smb2req->subreq; 1187 if (!req) { 1188 return false; 1189 } 1190 state = tevent_req_data(req, struct smbd_smb2_create_state); 1191 if (!state) { 1192 return false; 1193 } 1194 state->id = id; 1195 state->request_time = request_time; 1196 state->private_data = data_blob_talloc(state, private_data, 1197 priv_len); 1198 if (!state->private_data.data) { 1199 return false; 1200 } 1201 1202 #if 1 1203 /* Boo - turns out this isn't what W2K8R2 1204 does. It actually sends the STATUS_PENDING 1205 message followed by the STATUS_SHARING_VIOLATION 1206 message. Surely this means that all open 1207 calls (even on directories) will potentially 1208 fail in a chain.... ? And I've seen directory 1209 opens as the start of a chain. JRA. 1210 1211 Update: 19th May 2010. Talking with Microsoft 1212 engineers at the plugfest this is a bug in 1213 Windows. Re-enable this code. 1214 */ 1215 /* 1216 * More subtlety. To match W2K8R2 don't 1217 * send a "gone async" message if it's simply 1218 * a STATUS_SHARING_VIOLATION (short) wait, not 1219 * an oplock break wait. We do this by prematurely 1220 * setting smb2req->async flag. 1221 */ 1222 if (timeout.tv_sec < 2) { 1223 DEBUG(10,("push_deferred_open_message_smb2: " 1224 "short timer wait (usec = %u). " 1225 "Don't send async message.\n", 1226 (unsigned int)timeout.tv_usec )); 1227 smb2req->async = true; 1228 } 1229 #endif 1230 1231 /* Re-schedule us to retry on timer expiry. */ 1232 end_time = timeval_sum(&request_time, &timeout); 1233 1234 DEBUG(10,("push_deferred_open_message_smb2: " 1235 "timeout at %s\n", 1236 timeval_string(talloc_tos(), 1237 &end_time, 1238 true) )); 1239 1240 state->te = event_add_timed(smb2req->sconn->smb2.event_ctx, 1241 state, 1242 end_time, 1243 smb2_deferred_open_timer, 1244 smb2req); 1245 if (!state->te) { 1246 return false; 1247 } 1248 1249 /* allow this request to be canceled */ 1250 tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel); 1251 1252 return true; 1253 }
Note:
See TracChangeset
for help on using the changeset viewer.