static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTATUS status) { /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to FILE_LOCK_CONFLICT! (tridge) */ if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { status = NT_STATUS_FILE_LOCK_CONFLICT; } if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { /* Store the last lock error. */ files_struct *fsp = blr->fsp; if (fsp) { fsp->last_lock_failure.context.smblctx = blr->smblctx; fsp->last_lock_failure.context.tid = fsp->conn->cnum; fsp->last_lock_failure.context.pid = sconn_server_id(fsp->conn->sconn); fsp->last_lock_failure.start = blr->offset; fsp->last_lock_failure.size = blr->count; fsp->last_lock_failure.fnum = fsp->fnum; fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */ fsp->last_lock_failure.lock_flav = blr->lock_flav; } } reply_nterror(blr->req, status); if (!srv_send_smb(blr->req->sconn, (char *)blr->req->outbuf, true, blr->req->seqnum+1, blr->req->encrypted, NULL)) { exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed."); } TALLOC_FREE(blr->req->outbuf); }
struct blocking_lock_record *blocking_lock_cancel_smb1(files_struct *fsp, uint64_t smblctx, uint64_t offset, uint64_t count, enum brl_flavour lock_flav, unsigned char locktype, NTSTATUS err) { struct smbd_server_connection *sconn = fsp->conn->sconn; char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE]; struct blocking_lock_record *blr; if (!sconn->smb1.locks.blocking_lock_cancel_state) { /* Register our message. */ messaging_register(sconn->msg_ctx, NULL, MSG_SMB_BLOCKING_LOCK_CANCEL, process_blocking_lock_cancel_message); sconn->smb1.locks.blocking_lock_cancel_state = True; } for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) { if (fsp == blr->fsp && smblctx == blr->smblctx && offset == blr->offset && count == blr->count && lock_flav == blr->lock_flav) { break; } } if (!blr) { return NULL; } /* Check the flags are right. */ if (blr->req->cmd == SMBlockingX && (locktype & LOCKING_ANDX_LARGE_FILES) != (CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) { return NULL; } /* Move to cancelled queue. */ DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); DLIST_ADD(sconn->smb1.locks.blocking_lock_cancelled_queue, blr); /* Create the message. */ memcpy(msg, &blr, sizeof(blr)); memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS)); messaging_send_buf(sconn->msg_ctx, sconn_server_id(sconn), MSG_SMB_BLOCKING_LOCK_CANCEL, (uint8 *)&msg, sizeof(msg)); return blr; }
void smbd_cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck, enum file_close_type close_type) { struct smbd_server_connection *sconn = fsp->conn->sconn; struct blocking_lock_record *blr, *blr_cancelled, *next = NULL; if (sconn->using_smb2) { cancel_pending_lock_requests_by_fid_smb2(fsp, br_lck, close_type); return; } for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) { unsigned char locktype = 0; next = blr->next; if (blr->fsp->fnum != fsp->fnum) { continue; } if (blr->req->cmd == SMBlockingX) { locktype = CVAL(blr->req->vwv+3, 0); } DEBUG(10, ("remove_pending_lock_requests_by_fid - removing " "request type %d for file %s fnum = %d\n", blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum)); blr_cancelled = blocking_lock_cancel_smb1(fsp, blr->smblctx, blr->offset, blr->count, blr->lock_flav, locktype, NT_STATUS_RANGE_NOT_LOCKED); SMB_ASSERT(blr_cancelled == blr); brl_lock_cancel(br_lck, blr->smblctx, sconn_server_id(sconn), blr->offset, blr->count, blr->lock_flav, blr); /* We're closing the file fsp here, so ensure * we don't have a dangling pointer. */ blr->fsp = NULL; } }
struct db_record *connections_fetch_entry(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *name) { struct connections_key ckey; TDB_DATA key; ZERO_STRUCT(ckey); ckey.pid = sconn_server_id(conn->sconn); ckey.cnum = conn->cnum; strlcpy(ckey.name, name, sizeof(ckey.name)); key.dsize = sizeof(ckey); key.dptr = (uint8 *)&ckey; return connections_fetch_record(mem_ctx, key); }
void remove_pending_lock_requests_by_mid_smb1( struct smbd_server_connection *sconn, uint64_t mid) { struct blocking_lock_record *blr, *next = NULL; for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) { files_struct *fsp; struct byte_range_lock *br_lck; next = blr->next; if (blr->req->mid != mid) { continue; } fsp = blr->fsp; br_lck = brl_get_locks(talloc_tos(), fsp); if (br_lck) { DEBUG(10, ("remove_pending_lock_requests_by_mid_smb1 - " "removing request type %d for file %s fnum " "= %d\n", blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum )); brl_lock_cancel(br_lck, blr->smblctx, sconn_server_id(sconn), blr->offset, blr->count, blr->lock_flav, blr); TALLOC_FREE(br_lck); } blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); TALLOC_FREE(blr); } }
void reply_negprot(struct smb_request *req) { int choice= -1; int protocol; const char *p; int arch = ARCH_ALL; int num_cliprotos; char **cliprotos; int i; size_t converted_size; struct smbd_server_connection *sconn = req->sconn; START_PROFILE(SMBnegprot); if (sconn->smb1.negprot.done) { END_PROFILE(SMBnegprot); exit_server_cleanly("multiple negprot's are not permitted"); } sconn->smb1.negprot.done = true; if (req->buflen == 0) { DEBUG(0, ("negprot got no protocols\n")); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBnegprot); return; } if (req->buf[req->buflen-1] != '\0') { DEBUG(0, ("negprot protocols not 0-terminated\n")); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBnegprot); return; } p = (const char *)req->buf + 1; num_cliprotos = 0; cliprotos = NULL; while (smbreq_bufrem(req, p) > 0) { char **tmp; tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), cliprotos, char *, num_cliprotos+1); if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(cliprotos); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBnegprot); return; } cliprotos = tmp; if (!pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p, &converted_size)) { DEBUG(0, ("pull_ascii_talloc failed\n")); TALLOC_FREE(cliprotos); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBnegprot); return; } DEBUG(3, ("Requested protocol [%s]\n", cliprotos[num_cliprotos])); num_cliprotos += 1; p += strlen(p) + 2; } for (i=0; i<num_cliprotos; i++) { if (strcsequal(cliprotos[i], "Windows for Workgroups 3.1a")) arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); else if (strcsequal(cliprotos[i], "DOS LM1.2X002")) arch &= ( ARCH_WFWG | ARCH_WIN95 ); else if (strcsequal(cliprotos[i], "DOS LANMAN2.1")) arch &= ( ARCH_WFWG | ARCH_WIN95 ); else if (strcsequal(cliprotos[i], "NT LM 0.12")) arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS); else if (strcsequal(cliprotos[i], "SMB 2.001")) arch = ARCH_VISTA; else if (strcsequal(cliprotos[i], "LANMAN2.1")) arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "LM1.2X002")) arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 1.03")) arch &= ARCH_WINNT; else if (strcsequal(cliprotos[i], "XENIX CORE")) arch &= ( ARCH_WINNT | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "Samba")) { arch = ARCH_SAMBA; break; } else if (strcsequal(cliprotos[i], "POSIX 2")) { arch = ARCH_CIFSFS; break; } } /* CIFSFS can send one arch only, NT LM 0.12. */ if (i == 1 && (arch & ARCH_CIFSFS)) { arch = ARCH_CIFSFS; } switch ( arch ) { case ARCH_CIFSFS: set_remote_arch(RA_CIFSFS); break; case ARCH_SAMBA: set_remote_arch(RA_SAMBA); break; case ARCH_WFWG: set_remote_arch(RA_WFWG); break; case ARCH_WIN95: set_remote_arch(RA_WIN95); break; case ARCH_WINNT: if(req->flags2 == FLAGS2_WIN2K_SIGNATURE) set_remote_arch(RA_WIN2K); else set_remote_arch(RA_WINNT); break; case ARCH_WIN2K: /* Vista may have been set in the negprot so don't override it here */ if ( get_remote_arch() != RA_VISTA ) set_remote_arch(RA_WIN2K); break; case ARCH_VISTA: set_remote_arch(RA_VISTA); break; case ARCH_OS2: set_remote_arch(RA_OS2); break; default: set_remote_arch(RA_UNKNOWN); break; } /* possibly reload - change of architecture */ reload_services(sconn->msg_ctx, sconn->sock, True); /* moved from the netbios session setup code since we don't have that when the client connects to port 445. Of course there is a small window where we are listening to messages -- jerry */ serverid_register(sconn_server_id(sconn), FLAG_MSG_GENERAL|FLAG_MSG_SMBD |FLAG_MSG_PRINT_GENERAL); /* Check for protocols, most desirable first */ for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) { i = 0; if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) && (supported_protocols[protocol].protocol_level >= lp_minprotocol())) while (i < num_cliprotos) { if (strequal(cliprotos[i],supported_protocols[protocol].proto_name)) choice = i; i++; } if(choice != -1) break; } if(choice != -1) { fstrcpy(remote_proto,supported_protocols[protocol].short_name); reload_services(sconn->msg_ctx, sconn->sock, True); supported_protocols[protocol].proto_reply_fn(req, choice); DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); } else { DEBUG(0,("No protocol supported !\n")); reply_outbuf(req, 1, 0); SSVAL(req->outbuf, smb_vwv0, choice); } DEBUG( 5, ( "negprot index=%d\n", choice ) ); if ((lp_server_signing() == Required) && (get_Protocol() < PROTOCOL_NT1)) { exit_server_cleanly("SMB signing is required and " "client negotiated a downlevel protocol"); } TALLOC_FREE(cliprotos); if (lp_async_smb_echo_handler() && (get_Protocol() < PROTOCOL_SMB2) && !fork_echo_handler(sconn)) { exit_server("Failed to fork echo handler"); } END_PROFILE(SMBnegprot); return; }
void process_blocking_lock_queue(struct smbd_server_connection *sconn) { struct timeval tv_curr = timeval_current(); struct blocking_lock_record *blr, *next = NULL; if (sconn->using_smb2) { process_blocking_lock_queue_smb2(sconn, tv_curr); return; } /* * Go through the queue and see if we can get any of the locks. */ for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) { next = blr->next; /* * Go through the remaining locks and try and obtain them. * The call returns True if all locks were obtained successfully * and False if we still need to wait. */ DEBUG(10, ("Processing BLR = %p\n", blr)); /* We use set_current_service so connections with * pending locks are not marked as idle. */ set_current_service(blr->fsp->conn, SVAL(blr->req->inbuf,smb_flg), false); if(blocking_lock_record_process(blr)) { struct byte_range_lock *br_lck = brl_get_locks( talloc_tos(), blr->fsp); DEBUG(10, ("BLR_process returned true: cancelling and " "removing lock. BLR = %p\n", blr)); if (br_lck) { brl_lock_cancel(br_lck, blr->smblctx, sconn_server_id(sconn), blr->offset, blr->count, blr->lock_flav, blr); TALLOC_FREE(br_lck); } DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); TALLOC_FREE(blr); continue; } /* * We couldn't get the locks for this record on the list. * If the time has expired, return a lock error. */ if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) { struct byte_range_lock *br_lck = brl_get_locks( talloc_tos(), blr->fsp); DEBUG(10, ("Lock timed out! BLR = %p\n", blr)); /* * Lock expired - throw away all previously * obtained locks and return lock error. */ if (br_lck) { DEBUG(5,("process_blocking_lock_queue: " "pending lock fnum = %d for file %s " "timed out.\n", blr->fsp->fnum, fsp_str_dbg(blr->fsp))); brl_lock_cancel(br_lck, blr->smblctx, sconn_server_id(sconn), blr->offset, blr->count, blr->lock_flav, blr); TALLOC_FREE(br_lck); } blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); TALLOC_FREE(blr); } } recalc_brl_timeout(sconn); }
bool push_blocking_lock_request( struct byte_range_lock *br_lck, struct smb_request *req, files_struct *fsp, int lock_timeout, int lock_num, uint64_t smblctx, enum brl_type lock_type, enum brl_flavour lock_flav, uint64_t offset, uint64_t count, uint64_t blocking_smblctx) { struct smbd_server_connection *sconn = req->sconn; struct blocking_lock_record *blr; NTSTATUS status; if (req->smb2req) { return push_blocking_lock_request_smb2(br_lck, req, fsp, lock_timeout, lock_num, smblctx, lock_type, lock_flav, offset, count, blocking_smblctx); } if(req_is_in_chain(req)) { DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n")); return False; } /* * Now queue an entry on the blocking lock queue. We setup * the expiration time here. */ blr = talloc(NULL, struct blocking_lock_record); if (blr == NULL) { DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" )); return False; } blr->next = NULL; blr->prev = NULL; blr->fsp = fsp; if (lock_timeout == -1) { blr->expire_time.tv_sec = 0; blr->expire_time.tv_usec = 0; /* Never expire. */ } else { blr->expire_time = timeval_current_ofs_msec(lock_timeout); } blr->lock_num = lock_num; blr->smblctx = smblctx; blr->blocking_smblctx = blocking_smblctx; blr->lock_flav = lock_flav; blr->lock_type = lock_type; blr->offset = offset; blr->count = count; /* Specific brl_lock() implementations can fill this in. */ blr->blr_private = NULL; /* Add a pending lock record for this. */ status = brl_lock(req->sconn->msg_ctx, br_lck, smblctx, sconn_server_id(req->sconn), offset, count, lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK, blr->lock_flav, True, NULL, blr); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n")); TALLOC_FREE(blr); return False; } SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd); blr->req = talloc_move(blr, &req); DLIST_ADD_END(sconn->smb1.locks.blocking_lock_queue, blr, struct blocking_lock_record *); recalc_brl_timeout(sconn); /* Ensure we'll receive messages when this is unlocked. */ if (!sconn->smb1.locks.blocking_lock_unlock_state) { messaging_register(sconn->msg_ctx, NULL, MSG_SMB_UNLOCK, received_unlock_msg); sconn->smb1.locks.blocking_lock_unlock_state = true; } DEBUG(3,("push_blocking_lock_request: lock request blocked with " "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n", (unsigned int)blr->expire_time.tv_sec, (unsigned int)blr->expire_time.tv_usec, lock_timeout, blr->fsp->fnum, fsp_str_dbg(blr->fsp))); return True; }
static void exit_server_common(enum server_exit_reason how, const char *const reason) { struct smbd_server_connection *sconn = smbd_server_conn; if (!exit_firsttime) exit(0); exit_firsttime = false; change_to_root_user(); if (sconn && sconn->smb1.negprot.auth_context) { TALLOC_FREE(sconn->smb1.negprot.auth_context); } if (sconn) { if (lp_log_writeable_files_on_exit()) { bool found = false; files_forall(sconn, log_writeable_file_fn, &found); } (void)conn_close_all(sconn); invalidate_all_vuids(sconn); } /* 3 second timeout. */ print_notify_send_messages(sconn->msg_ctx, 3); /* delete our entry in the serverid database. */ if (am_parent) { /* * For children the parent takes care of cleaning up */ serverid_deregister(sconn_server_id(sconn)); } #ifdef WITH_DFS if (dcelogin_atmost_once) { dfs_unlogin(); } #endif #ifdef USE_DMAPI /* Destroy Samba DMAPI session only if we are master smbd process */ if (am_parent) { if (!dmapi_destroy_session()) { DEBUG(0,("Unable to close Samba DMAPI session\n")); } } #endif if (am_parent) { rpc_wkssvc_shutdown(); #ifdef ACTIVE_DIRECTORY rpc_dssetup_shutdown(); #endif #ifdef DEVELOPER rpc_rpcecho_shutdown(); #endif #ifdef DFS_SUPPORT rpc_netdfs_shutdown(); #endif rpc_initshutdown_shutdown(); #ifdef EXTRA_SERVICES rpc_eventlog_shutdown(); rpc_svcctl_shutdown(); rpc_ntsvcs_shutdown(); #endif #ifdef PRINTER_SUPPORT rpc_spoolss_shutdown(); #endif rpc_srvsvc_shutdown(); #ifdef WINREG_SUPPORT rpc_winreg_shutdown(); #endif #ifdef NETLOGON_SUPPORT rpc_netlogon_shutdown(); #endif #ifdef SAMR_SUPPORT rpc_samr_shutdown(); #endif #ifdef LSA_SUPPORT rpc_lsarpc_shutdown(); #endif } /* * we need to force the order of freeing the following, * because smbd_msg_ctx is not a talloc child of smbd_server_conn. */ sconn = NULL; TALLOC_FREE(smbd_server_conn); server_messaging_context_free(); server_event_context_free(); TALLOC_FREE(smbd_memcache_ctx); locking_end(); printing_end(); if (how != SERVER_EXIT_NORMAL) { DEBUGSEP(0); DEBUG(0,("Abnormal server exit: %s\n", reason ? reason : "no explanation provided")); DEBUGSEP(0); log_stack_trace(); dump_core(); /* Notreached. */ exit(1); } else { DEBUG(3,("Server exit (%s)\n", (reason ? reason : "normal exit"))); if (am_parent) { pidfile_unlink(); } gencache_stabilize(); } exit(0); }