NTSTATUS wreplsrv_out_pull_run(struct wreplsrv_service *service) { struct wreplsrv_partner *partner; for (partner = service->partners; partner; partner = partner->next) { /* if it's not a pull partner, go to the next partner */ if (!(partner->type & WINSREPL_PARTNER_PULL)) continue; /* if pulling is disabled for the partner, go to the next one */ if (partner->pull.interval == 0) continue; /* if the next timer isn't reached, go to the next partner */ if (!timeval_expired(&partner->pull.next_run)) continue; wreplsrv_out_pull_reschedule(partner, partner->pull.interval); wreplsrv_out_partner_pull(partner, NULL); } return NT_STATUS_OK; }
static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem) { NTSTATUS status; struct winsdb_record *rec = NULL; struct ldb_result *res = NULL; const char *owner_filter; const char *filter; uint32_t i; int ret; time_t now = time(NULL); const char *now_timestr; const char *action; const char *old_state=NULL; const char *new_state=NULL; uint32_t modify_flags; BOOL modify_record; BOOL delete_record; BOOL delete_tombstones; struct timeval tombstone_extra_time; now_timestr = ldb_timestring(tmp_mem, now); NT_STATUS_HAVE_NO_MEMORY(now_timestr); owner_filter = wreplsrv_owner_filter(service, tmp_mem, service->wins_db->local_owner); NT_STATUS_HAVE_NO_MEMORY(owner_filter); filter = talloc_asprintf(tmp_mem, "(&%s(objectClass=winsRecord)" "(expireTime<=%s))", owner_filter, now_timestr); NT_STATUS_HAVE_NO_MEMORY(filter); ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION; talloc_steal(tmp_mem, res); DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count)); tombstone_extra_time = timeval_add(&service->startup_time, service->config.tombstone_extra_timeout, 0); delete_tombstones = timeval_expired(&tombstone_extra_time); for (i=0; i < res->count; i++) { /* * we pass '0' as 'now' here, * because we want to get the raw timestamps which are in the DB */ status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, 0, &rec); NT_STATUS_NOT_OK_RETURN(status); talloc_free(res->msgs[i]); modify_flags = 0; modify_record = False; delete_record = False; switch (rec->state) { case WREPL_STATE_ACTIVE: old_state = "active"; new_state = "active"; if (!rec->is_static) { new_state = "released"; rec->state = WREPL_STATE_RELEASED; rec->expire_time= service->config.tombstone_interval + now; } modify_flags = 0; modify_record = True; break; case WREPL_STATE_RELEASED: old_state = "released"; new_state = "tombstone"; rec->state = WREPL_STATE_TOMBSTONE; rec->expire_time= service->config.tombstone_timeout + now; modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP; modify_record = True; break; case WREPL_STATE_TOMBSTONE: old_state = "tombstone"; new_state = "tombstone"; if (!delete_tombstones) break; new_state = "deleted"; delete_record = True; break; case WREPL_STATE_RESERVED: DEBUG(0,("%s: corrupted record: %s\n", __location__, nbt_name_string(rec, rec->name))); return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (modify_record) { action = "modify"; ret = winsdb_modify(service->wins_db, rec, modify_flags); } else if (delete_record) { action = "delete"; ret = winsdb_delete(service->wins_db, rec); } else { action = "skip"; ret = NBT_RCODE_OK; } if (ret != NBT_RCODE_OK) { DEBUG(1,("WINS scavenging: failed to %s name %s (owned:%s -> owned:%s): error:%u\n", action, nbt_name_string(rec, rec->name), old_state, new_state, ret)); } else { DEBUG(4,("WINS scavenging: %s name: %s (owned:%s -> owned:%s)\n", action, nbt_name_string(rec, rec->name), old_state, new_state)); } talloc_free(rec); } return NT_STATUS_OK; }
static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem) { NTSTATUS status; struct winsdb_record *rec = NULL; struct ldb_result *res = NULL; const char *owner_filter; const char *filter; unsigned int i; int ret; time_t now = time(NULL); const char *now_timestr; const char *action; const char *old_state=NULL; const char *new_state=NULL; uint32_t modify_flags; bool modify_record; bool delete_record; bool delete_tombstones; struct timeval tombstone_extra_time; const char *local_owner = service->wins_db->local_owner; bool propagate = lpcfg_parm_bool(service->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false); now_timestr = ldb_timestring(tmp_mem, now); NT_STATUS_HAVE_NO_MEMORY(now_timestr); owner_filter = wreplsrv_owner_filter(service, tmp_mem, local_owner); NT_STATUS_HAVE_NO_MEMORY(owner_filter); filter = talloc_asprintf(tmp_mem, "(&%s(objectClass=winsRecord)" "(expireTime<=%s))", owner_filter, now_timestr); NT_STATUS_HAVE_NO_MEMORY(filter); ret = ldb_search(service->wins_db->ldb, tmp_mem, &res, NULL, LDB_SCOPE_SUBTREE, NULL, "%s", filter); if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION; DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count)); tombstone_extra_time = timeval_add(&service->startup_time, service->config.tombstone_extra_timeout, 0); delete_tombstones = timeval_expired(&tombstone_extra_time); for (i=0; i < res->count; i++) { bool has_replicas = false; /* * we pass '0' as 'now' here, * because we want to get the raw timestamps which are in the DB */ status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, 0, &rec); NT_STATUS_NOT_OK_RETURN(status); talloc_free(res->msgs[i]); modify_flags = 0; modify_record = false; delete_record = false; switch (rec->state) { case WREPL_STATE_ACTIVE: old_state = "active"; if (rec->is_static) { /* *we store it again, so that it won't appear * in the scavenging the next time */ old_state = "active(static)"; new_state = "active(static)"; modify_flags = 0; modify_record = true; break; } if (rec->type != WREPL_TYPE_SGROUP || !propagate) { new_state = "released"; rec->state = WREPL_STATE_RELEASED; rec->expire_time= service->config.tombstone_interval + now; modify_flags = 0; modify_record = true; break; } /* check if there's any replica address */ for (i=0;rec->addresses[i];i++) { if (strcmp(rec->addresses[i]->wins_owner, local_owner) != 0) { has_replicas = true; rec->addresses[i]->expire_time= service->config.renew_interval + now; } } if (has_replicas) { /* if it has replica addresses propagate them */ new_state = "active(propagated)"; rec->state = WREPL_STATE_ACTIVE; rec->expire_time= service->config.renew_interval + now; modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP; modify_record = true; break; } /* * if it doesn't have replica addresses, make it a tombstone, * so that the released owned addresses are propagated */ new_state = "tombstone"; rec->state = WREPL_STATE_TOMBSTONE; rec->expire_time= time(NULL) + service->config.tombstone_interval + service->config.tombstone_timeout; modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP; modify_record = true; break; case WREPL_STATE_RELEASED: old_state = "released"; new_state = "tombstone"; rec->state = WREPL_STATE_TOMBSTONE; rec->expire_time= service->config.tombstone_timeout + now; modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP; modify_record = true; break; case WREPL_STATE_TOMBSTONE: old_state = "tombstone"; new_state = "tombstone"; if (!delete_tombstones) break; new_state = "deleted"; delete_record = true; break; case WREPL_STATE_RESERVED: DEBUG(0,("%s: corrupted record: %s\n", __location__, nbt_name_string(rec, rec->name))); return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (modify_record) { action = "modify"; ret = winsdb_modify(service->wins_db, rec, modify_flags); } else if (delete_record) { action = "delete"; ret = winsdb_delete(service->wins_db, rec); } else { action = "skip"; ret = NBT_RCODE_OK; } if (ret != NBT_RCODE_OK) { DEBUG(2,("WINS scavenging: failed to %s name %s (owned:%s -> owned:%s): error:%u\n", action, nbt_name_string(rec, rec->name), old_state, new_state, ret)); } else { DEBUG(4,("WINS scavenging: %s name: %s (owned:%s -> owned:%s)\n", action, nbt_name_string(rec, rec->name), old_state, new_state)); } talloc_free(rec); } return NT_STATUS_OK; }
static void print_notify_send_messages_to_printer(struct messaging_context *msg_ctx, const char *printer, unsigned int timeout) { char *buf; struct notify_queue *pq, *pq_next; size_t msg_count = 0, offset = 0; size_t num_pids = 0; size_t i; pid_t *pid_list = NULL; struct timeval end_time = timeval_zero(); /* Count the space needed to send the messages. */ for (pq = notify_queue_head; pq; pq = pq->next) { if (strequal(printer, pq->msg->printer)) { if (!flatten_message(pq)) { DEBUG(0,("print_notify_send_messages: Out of memory\n")); talloc_free_children(send_ctx); num_messages = 0; return; } offset += (pq->buflen + 4); msg_count++; } } offset += 4; /* For count. */ buf = (char *)TALLOC(send_ctx, offset); if (!buf) { DEBUG(0,("print_notify_send_messages: Out of memory\n")); talloc_free_children(send_ctx); num_messages = 0; return; } offset = 0; SIVAL(buf,offset,msg_count); offset += 4; for (pq = notify_queue_head; pq; pq = pq_next) { pq_next = pq->next; if (strequal(printer, pq->msg->printer)) { SIVAL(buf,offset,pq->buflen); offset += 4; memcpy(buf + offset, pq->buf, pq->buflen); offset += pq->buflen; /* Remove from list. */ DLIST_REMOVE(notify_queue_head, pq); } } DEBUG(5, ("print_notify_send_messages_to_printer: sending %lu print notify message%s to printer %s\n", (unsigned long)msg_count, msg_count != 1 ? "s" : "", printer)); /* * Get the list of PID's to send to. */ if (!print_notify_pid_list(printer, send_ctx, &num_pids, &pid_list)) return; if (timeout != 0) { end_time = timeval_current_ofs(timeout, 0); } for (i = 0; i < num_pids; i++) { messaging_send_buf(msg_ctx, pid_to_procid(pid_list[i]), MSG_PRINTER_NOTIFY2 | MSG_FLAG_LOWPRIORITY, (uint8 *)buf, offset); if ((timeout != 0) && timeval_expired(&end_time)) { break; } } }
NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context, struct messaging_context *msg_ctx, struct dcerpc_binding_handle *b, const char *domain, bool force) { TALLOC_CTX *frame = talloc_stackframe(); struct trust_pw_change_state *state; struct cli_credentials *creds = NULL; const struct samr_Password *current_nt_hash = NULL; const struct samr_Password *previous_nt_hash = NULL; enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL; time_t pass_last_set_time; uint32_t old_version = 0; struct pdb_trusted_domain *td = NULL; struct timeval g_timeout = { 0, }; int timeout = 0; struct timeval tv = { 0, }; size_t new_len = DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH; uint8_t new_password_buffer[256 * 2] = { 0, }; char *new_trust_passwd = NULL; size_t len = 0; uint32_t new_version = 0; uint32_t *new_trust_version = NULL; NTSTATUS status; bool ok; state = talloc_zero(frame, struct trust_pw_change_state); if (state == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } state->g_ctx = g_lock_ctx_init(state, msg_ctx); if (state->g_ctx == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } state->g_lock_key = talloc_asprintf(state, "trust_password_change_%s", domain); if (state->g_lock_key == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } g_timeout = timeval_current_ofs(10, 0); status = g_lock_lock(state->g_ctx, state->g_lock_key, G_LOCK_WRITE, g_timeout); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("could not get g_lock on [%s]!\n", state->g_lock_key)); TALLOC_FREE(frame); return status; } talloc_set_destructor(state, trust_pw_change_state_destructor); status = pdb_get_trust_credentials(domain, NULL, frame, &creds); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("could not fetch domain creds for domain %s - %s!\n", domain, nt_errstr(status))); TALLOC_FREE(frame); return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE; } current_nt_hash = cli_credentials_get_nt_hash(creds, frame); if (current_nt_hash == NULL) { DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n", domain)); TALLOC_FREE(frame); return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE; } old_version = cli_credentials_get_kvno(creds); pass_last_set_time = cli_credentials_get_password_last_changed_time(creds); sec_channel_type = cli_credentials_get_secure_channel_type(creds); new_version = old_version + 1; switch (sec_channel_type) { case SEC_CHAN_WKSTA: case SEC_CHAN_BDC: break; case SEC_CHAN_DNS_DOMAIN: /* * new_len * 2 = 498 bytes is the largest possible length * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes * and a confounder with at least 2 bytes is required. * * Windows uses new_len = 120 => 240 bytes. */ new_len = 120; /* fall through */ case SEC_CHAN_DOMAIN: status = pdb_get_trusted_domain(frame, domain, &td); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("pdb_get_trusted_domain() failed for domain %s - %s!\n", domain, nt_errstr(status))); TALLOC_FREE(frame); return status; } new_trust_version = &new_version; break; default: TALLOC_FREE(frame); return NT_STATUS_NOT_SUPPORTED; } timeout = lp_machine_password_timeout(); if (timeout == 0) { if (!force) { DEBUG(10,("machine password never expires\n")); TALLOC_FREE(frame); return NT_STATUS_OK; } } tv.tv_sec = pass_last_set_time; DEBUG(10, ("password last changed %s\n", timeval_string(talloc_tos(), &tv, false))); tv.tv_sec += timeout; DEBUGADD(10, ("password valid until %s\n", timeval_string(talloc_tos(), &tv, false))); if (!force && !timeval_expired(&tv)) { TALLOC_FREE(frame); return NT_STATUS_OK; } /* * Create a random machine account password * We create a random buffer and convert that to utf8. * This is similar to what windows is doing. */ generate_secret_buffer(new_password_buffer, new_len * 2); ok = convert_string_talloc(frame, CH_UTF16MUNGED, CH_UTF8, new_password_buffer, new_len * 2, (void *)&new_trust_passwd, &len); ZERO_STRUCT(new_password_buffer); if (!ok) { DEBUG(0, ("convert_string_talloc failed\n")); TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } /* * We could use cli_credentials_get_old_nt_hash(creds, frame) to * set previous_nt_hash. * * But we want to check if the dc has our current password and only do * a change if that's the case. So we keep previous_nt_hash = NULL. * * TODO: * If the previous password is the only password in common with the dc, * we better skip the password change, or use something like * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our * local secrets before doing the change. */ status = netlogon_creds_cli_auth(context, b, *current_nt_hash, previous_nt_hash); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("netlogon_creds_cli_auth for domain %s - %s!\n", domain, nt_errstr(status))); TALLOC_FREE(frame); return status; } /* * Return the result of trying to write the new password * back into the trust account file. */ switch (sec_channel_type) { case SEC_CHAN_WKSTA: case SEC_CHAN_BDC: ok = secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type); if (!ok) { DEBUG(0, ("secrets_store_machine_password failed for domain %s!\n", domain)); TALLOC_FREE(frame); return NT_STATUS_INTERNAL_DB_CORRUPTION; } break; case SEC_CHAN_DNS_DOMAIN: case SEC_CHAN_DOMAIN: /* * we need to get the sid first for the * pdb_set_trusteddom_pw call */ ok = pdb_set_trusteddom_pw(domain, new_trust_passwd, &td->security_identifier); if (!ok) { DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n", domain)); TALLOC_FREE(frame); return NT_STATUS_INTERNAL_DB_CORRUPTION; } break; default: smb_panic("Unsupported secure channel type"); break; } DEBUG(1,("%s : %s(%s): Changed password locally\n", current_timestring(talloc_tos(), false), __func__, domain)); status = netlogon_creds_cli_ServerPasswordSet(context, b, new_trust_passwd, new_trust_version); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("%s : %s(%s) remote password change set failed - %s\n", current_timestring(talloc_tos(), false), __func__, domain, nt_errstr(status))); TALLOC_FREE(frame); return status; } DEBUG(1,("%s : %s(%s): Changed password remotely.\n", current_timestring(talloc_tos(), false), __func__, domain)); TALLOC_FREE(frame); return NT_STATUS_OK; }