/* Validate an incoming authenticator against the credentials for the remote machine. The credentials are (re)read and from the schannel database, and written back after the caclulations are performed. The creds_out parameter (if not NULL) returns the credentials, if the caller needs some of that information. */ NTSTATUS schannel_creds_server_step_check_ldb(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *computer_name, bool schannel_required_for_call, bool schannel_in_use, struct netr_Authenticator *received_authenticator, struct netr_Authenticator *return_authenticator, struct netlogon_creds_CredentialState **creds_out) { struct netlogon_creds_CredentialState *creds; NTSTATUS nt_status; int ret; ret = ldb_transaction_start(ldb); if (ret != 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* Because this is a shared structure (even across * disconnects) we must update the database every time we * update the structure */ nt_status = schannel_fetch_session_key_ldb(ldb, ldb, computer_name, &creds); /* If we are flaged that schannel is required for a call, and * it is not in use, then make this an error */ /* It would be good to make this mandetory once schannel is * negoiated, bu this is not what windows does */ if (schannel_required_for_call && !schannel_in_use) { DEBUG(0,("schannel_creds_server_step_check: client %s not using schannel for netlogon, despite negotiating it\n", creds->computer_name )); ldb_transaction_cancel(ldb); return NT_STATUS_ACCESS_DENIED; } if (NT_STATUS_IS_OK(nt_status)) { nt_status = netlogon_creds_server_step_check(creds, received_authenticator, return_authenticator); } if (NT_STATUS_IS_OK(nt_status)) { nt_status = schannel_store_session_key_ldb(ldb, mem_ctx, creds); } if (NT_STATUS_IS_OK(nt_status)) { ldb_transaction_commit(ldb); if (creds_out) { *creds_out = creds; talloc_steal(mem_ctx, creds); } } else { ldb_transaction_cancel(ldb); } return nt_status; }
NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, const char *computer_name, struct netr_Authenticator *received_authenticator, struct netr_Authenticator *return_authenticator, struct netlogon_creds_CredentialState **creds_out) { TALLOC_CTX *tmpctx; struct tdb_wrap *tdb_sc; struct netlogon_creds_CredentialState *creds; NTSTATUS status; int ret; tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state"); if (!tmpctx) { return NT_STATUS_NO_MEMORY; } tdb_sc = open_schannel_session_store(tmpctx, lp_ctx); if (!tdb_sc) { status = NT_STATUS_ACCESS_DENIED; goto done; } ret = tdb_transaction_start(tdb_sc->tdb); if (ret != 0) { status = NT_STATUS_INTERNAL_DB_CORRUPTION; goto done; } /* Because this is a shared structure (even across * disconnects) we must update the database every time we * update the structure */ status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx, computer_name, &creds); if (!NT_STATUS_IS_OK(status)) { tdb_transaction_cancel(tdb_sc->tdb); goto done; } status = netlogon_creds_server_step_check(creds, received_authenticator, return_authenticator); if (!NT_STATUS_IS_OK(status)) { tdb_transaction_cancel(tdb_sc->tdb); goto done; } status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds); if (!NT_STATUS_IS_OK(status)) { tdb_transaction_cancel(tdb_sc->tdb); goto done; } tdb_transaction_commit(tdb_sc->tdb); if (creds_out) { *creds_out = talloc_steal(mem_ctx, creds); if (!*creds_out) { status = NT_STATUS_NO_MEMORY; goto done; } } status = NT_STATUS_OK; done: talloc_free(tmpctx); return status; }