⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wrepl_in_call.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Unix SMB/CIFS implementation.      WINS Replication server      Copyright (C) Stefan Metzmacher	2005      This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "lib/events/events.h"#include "lib/socket/socket.h"#include "smbd/service_stream.h"#include "libcli/wrepl/winsrepl.h"#include "wrepl_server/wrepl_server.h"#include "libcli/composite/composite.h"#include "nbt_server/wins/winsdb.h"#include "lib/ldb/include/ldb.h"#include "lib/ldb/include/ldb_errors.h"#include "system/time.h"static NTSTATUS wreplsrv_in_start_association(struct wreplsrv_in_call *call){	struct wrepl_start *start	= &call->req_packet.message.start;	struct wrepl_start *start_reply	= &call->rep_packet.message.start_reply;	if (call->req_packet.opcode & WREPL_OPCODE_BITS) {		/*		 *if the assoc_ctx doesn't match ignore the packet		 */		if ((call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx)		   && (call->req_packet.assoc_ctx != 0)) {			return ERROR_INVALID_PARAMETER;		}	} else {		call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_INVALID_ASSOC_CTX;		return NT_STATUS_OK;	}/* * it seems that we don't know all details about the start_association * to support replication with NT4 (it sends 1.1 instead of 5.2) * we ignore the version numbers until we know all details */#if 0	if (start->minor_version != 2 || start->major_version != 5) {		/* w2k terminate the connection if the versions doesn't match */		return NT_STATUS_UNKNOWN_REVISION;	}#endif	call->wreplconn->assoc_ctx.stopped	= false;	call->wreplconn->assoc_ctx.our_ctx	= WREPLSRV_VALID_ASSOC_CTX;	call->wreplconn->assoc_ctx.peer_ctx	= start->assoc_ctx;	call->rep_packet.mess_type		= WREPL_START_ASSOCIATION_REPLY;	start_reply->assoc_ctx			= call->wreplconn->assoc_ctx.our_ctx;	start_reply->minor_version		= 2;	start_reply->major_version		= 5;	/*	 * nt4 uses 41 bytes for the start_association call	 * so do it the same and as we don't know the meanings of this bytes	 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this	 *	 * if we don't do this nt4 uses an old version of the wins replication protocol	 * and that would break nt4 <-> samba replication	 */	call->rep_packet.padding		= data_blob_talloc(call, NULL, 21);	NT_STATUS_HAVE_NO_MEMORY(call->rep_packet.padding.data);	memset(call->rep_packet.padding.data, 0, call->rep_packet.padding.length);	return NT_STATUS_OK;}static NTSTATUS wreplsrv_in_stop_assoc_ctx(struct wreplsrv_in_call *call){	struct wrepl_stop *stop_out		= &call->rep_packet.message.stop;	call->wreplconn->assoc_ctx.stopped	= true;	call->rep_packet.mess_type		= WREPL_STOP_ASSOCIATION;	stop_out->reason			= 4;	return NT_STATUS_OK;}static NTSTATUS wreplsrv_in_stop_association(struct wreplsrv_in_call *call){	/*	 * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set	 */	if (call->req_packet.opcode & WREPL_OPCODE_BITS) {		/*		 *if the assoc_ctx doesn't match ignore the packet		 */		if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {			return ERROR_INVALID_PARAMETER;		}		/* when the opcode bits are set the connection should be directly terminated */		return NT_STATUS_CONNECTION_RESET;	}	if (call->wreplconn->assoc_ctx.stopped) {		/* this causes the connection to be directly terminated */		return NT_STATUS_CONNECTION_RESET;	}	/* this will cause to not receive packets anymore and terminate the connection if the reply is send */	call->terminate_after_send = true;	return wreplsrv_in_stop_assoc_ctx(call);}static NTSTATUS wreplsrv_in_table_query(struct wreplsrv_in_call *call){	struct wreplsrv_service *service = call->wreplconn->service;	struct wrepl_replication *repl_out = &call->rep_packet.message.replication;	struct wrepl_table *table_out = &call->rep_packet.message.replication.info.table;	repl_out->command = WREPL_REPL_TABLE_REPLY;	return wreplsrv_fill_wrepl_table(service, call, table_out,					 service->wins_db->local_owner, true);}static int wreplsrv_in_sort_wins_name(struct wrepl_wins_name *n1,				      struct wrepl_wins_name *n2){	if (n1->id < n2->id) return -1;	if (n1->id > n2->id) return 1;	return 0;}static NTSTATUS wreplsrv_record2wins_name(TALLOC_CTX *mem_ctx,					  struct wrepl_wins_name *name,					  struct winsdb_record *rec){	uint32_t num_ips, i;	struct wrepl_ip *ips;	name->name		= rec->name;	talloc_steal(mem_ctx, rec->name);	name->id		= rec->version;	name->unknown		= "255.255.255.255";	name->flags		= WREPL_NAME_FLAGS(rec->type, rec->state, rec->node, rec->is_static);	switch (name->flags & 2) {	case 0:		name->addresses.ip			= rec->addresses[0]->address;		talloc_steal(mem_ctx, rec->addresses[0]->address);		break;	case 2:		num_ips	= winsdb_addr_list_length(rec->addresses);		ips	= talloc_array(mem_ctx, struct wrepl_ip, num_ips);		NT_STATUS_HAVE_NO_MEMORY(ips);		for (i = 0; i < num_ips; i++) {			ips[i].owner	= rec->addresses[i]->wins_owner;			talloc_steal(ips, rec->addresses[i]->wins_owner);			ips[i].ip	= rec->addresses[i]->address;			talloc_steal(ips, rec->addresses[i]->address);		}		name->addresses.addresses.num_ips	= num_ips;		name->addresses.addresses.ips		= ips;		break;	}	return NT_STATUS_OK;}static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call){	struct wreplsrv_service *service = call->wreplconn->service;	struct wrepl_wins_owner *owner_in = &call->req_packet.message.replication.info.owner;	struct wrepl_replication *repl_out = &call->rep_packet.message.replication;	struct wrepl_send_reply *reply_out = &call->rep_packet.message.replication.info.reply;	struct wreplsrv_owner *owner;	const char *owner_filter;	const char *filter;	struct ldb_result *res = NULL;	int ret;	struct wrepl_wins_name *names;	struct winsdb_record *rec;	NTSTATUS status;	uint32_t i, j;	time_t now = time(NULL);	owner = wreplsrv_find_owner(service, service->table, owner_in->address);	repl_out->command	= WREPL_REPL_SEND_REPLY;	reply_out->num_names	= 0;	reply_out->names	= NULL;	/*	 * if we didn't know this owner, must be a bug in the partners client code...	 * return an empty list.	 */	if (!owner) {		DEBUG(2,("WINSREPL:reply [0] records unknown owner[%s] to partner[%s]\n",			owner_in->address, call->wreplconn->partner->address));		return NT_STATUS_OK;	}	/*	 * the client sends a max_version of 0, interpret it as	 * (uint64_t)-1	 */	if (owner_in->max_version == 0) {		owner_in->max_version = (uint64_t)-1;	}	/*	 * if the partner ask for nothing, or give invalid ranges,	 * return an empty list.	 */	if (owner_in->min_version > owner_in->max_version) {		DEBUG(2,("WINSREPL:reply [0] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",			owner_in->address, 			(long long)owner_in->min_version, 			(long long)owner_in->max_version,			call->wreplconn->partner->address));		return NT_STATUS_OK;	}	/*	 * if the partner has already all records for nothing, or give invalid ranges,	 * return an empty list.	 */	if (owner_in->min_version > owner->owner.max_version) {		DEBUG(2,("WINSREPL:reply [0] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",			owner_in->address, 			(long long)owner_in->min_version, 			(long long)owner_in->max_version,			call->wreplconn->partner->address));		return NT_STATUS_OK;	}	owner_filter = wreplsrv_owner_filter(service, call, owner->owner.address);	NT_STATUS_HAVE_NO_MEMORY(owner_filter);	filter = talloc_asprintf(call,				 "(&%s(objectClass=winsRecord)"				 "(|(recordState=%u)(recordState=%u))"				 "(versionID>=%llu)(versionID<=%llu))",				 owner_filter,				 WREPL_STATE_ACTIVE, WREPL_STATE_TOMBSTONE,				 (long long)owner_in->min_version, 				 (long long)owner_in->max_version);	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(call, res);	DEBUG(10,("WINSREPL: filter '%s' count %d\n", filter, res->count));	if (res->count == 0) {		DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",			res->count, owner_in->address, 			(long long)owner_in->min_version, 			(long long)owner_in->max_version,			call->wreplconn->partner->address));		return NT_STATUS_OK;	}	names = talloc_array(call, struct wrepl_wins_name, res->count);	NT_STATUS_HAVE_NO_MEMORY(names);	for (i=0, j=0; i < res->count; i++) {		status = winsdb_record(service->wins_db, res->msgs[i], call, now, &rec);		NT_STATUS_NOT_OK_RETURN(status);		/*		 * it's possible that winsdb_record() made the record RELEASED		 * because it's expired, but in the database it's still stored		 * as ACTIVE...

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -