process.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 984 行 · 第 1/2 页

C
984
字号
/*    Unix SMB/CIFS implementation.   process incoming packets - main loop   Copyright (C) Jean Fran鏾is Micouleau      1998-2002.      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 2 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, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"#include "wins_repl.h"extern fd_set *listen_set;extern int listen_number;extern int *sock_array;WINS_OWNER global_wins_table[64][64];int partner_count;TALLOC_CTX *mem_ctx;#define WINS_LIST "wins.tdb"#define INFO_VERSION	"INFO/version"#define INFO_COUNT	"INFO/num_entries"#define INFO_ID_HIGH	"INFO/id_high"#define INFO_ID_LOW	"INFO/id_low"#define ENTRY_PREFIX 	"ENTRY/"/*******************************************************************fill the header of a reply.********************************************************************/static void fill_header(GENERIC_PACKET *g, int opcode, int ctx, int mess){	if (g==NULL)		return;	g->header.opcode=opcode;	g->header.assoc_ctx=ctx;	g->header.mess_type=mess;}/*******************************************************************dump the global table, that's a debug code.********************************************************************/static void dump_global_table(void){	int i,j;		for (i=0;i<partner_count;i++) {		DEBUG(10,("\n%d ", i));		for (j=0; global_wins_table[i][j].address.s_addr!=0; j++)			DEBUG(10,("%s:%d \t", inet_ntoa(global_wins_table[i][j].address),				(int)global_wins_table[i][j].max_version));	}	DEBUG(10,("\n"));}/*******************************************************************start association********************************************************************/static void start_assoc_process(GENERIC_PACKET *q, GENERIC_PACKET *r){	/*	 * add this request to our current wins partners list	 * this list is used to know with who we are in contact	 *	 */	r->sa_rp.assoc_ctx=time(NULL);	fill_header(r, OPCODE_NON_NBT, q->sa_rq.assoc_ctx, MESSAGE_TYPE_START_ASSOC_REPLY);	/* reply we are a NT4 server */		/* w2K is min=2, maj=5 */		r->sa_rp.min_ver=1;	r->sa_rp.maj_ver=1;	add_partner(r->sa_rp.assoc_ctx, q->sa_rq.assoc_ctx, False, False);}/*******************************************************************start association reply********************************************************************/static void start_assoc_reply(GENERIC_PACKET *q, GENERIC_PACKET *r){	int i;	/* check if we have already registered this client */	if (!check_partner(q->header.assoc_ctx)) {		DEBUG(0,("start_assoc_reply: unknown client\n"));		stop_packet(q, r, STOP_REASON_USER_REASON);		return;	}	if (!update_server_partner(q->header.assoc_ctx, q->sa_rp.assoc_ctx)) {		DEBUG(0,("start_assoc_reply: can't update server ctx\n"));		stop_packet(q, r, STOP_REASON_USER_REASON);		return;	}	/* if pull, request map table */		if (check_pull_partner(q->header.assoc_ctx)) {		fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);		r->rep.msg_type=MESSAGE_REP_ADD_VERSION_REQUEST;		DEBUG(5,("start_assoc_reply: requesting map table\n"));		return;	}	/* if push, send our table */	if (check_push_partner(q->header.assoc_ctx)) {		fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);		r->rep.msg_type=MESSAGE_REP_UPDATE_NOTIFY_REQUEST;		r->rep.un_rq.partner_count=partner_count;				r->rep.un_rq.wins_owner=talloc_array(mem_ctx, WINS_OWNER, partner_count);		if (r->rep.un_rq.wins_owner==NULL) {			DEBUG(0,("start_assoc_reply: can't alloc memory\n"));			stop_packet(q, r, STOP_REASON_USER_REASON);			return;		}		for (i=0; i<partner_count; i++)			r->rep.un_rq.wins_owner[i]=global_wins_table[0][i];				DEBUG(5,("start_assoc_reply: sending update table\n"));		return;	}		/* neither push/pull, stop */	/* we should not come here */	DEBUG(0,("we have a partner which is neither push nor pull !\n"));	stop_packet(q, r, STOP_REASON_USER_REASON);}/****************************************************************************initialise and fill the in-memory partner table.****************************************************************************/int init_wins_partner_table(void){	int i=1,j=0,k;	char **partner = str_list_make(lp_wins_partners(), NULL);	if (partner==NULL) {		DEBUG(0,("wrepld: no partner list in smb.conf, exiting\n"));		exit_server("normal exit");		return(0);	}	DEBUG(4, ("init_wins_partner_table: partners: %s\n", lp_wins_partners()));	global_wins_table[0][0].address=*iface_n_ip(0);	global_wins_table[0][0].max_version=0;	global_wins_table[0][0].min_version=0;	global_wins_table[0][0].type=0;	while (partner[j]!=NULL) {		DEBUG(3,("init_wins_partner_table, adding partner: %s\n", partner[j]));				global_wins_table[0][i].address=*interpret_addr2(partner[j]);		global_wins_table[0][i].max_version=0;		global_wins_table[0][i].min_version=0;		global_wins_table[0][i].type=0;		global_wins_table[0][i].last_pull=0;		global_wins_table[0][i].last_push=0;		i++;		j++;	}		for (k=1; k<i;k++)		for (j=0; j<i; j++)			global_wins_table[k][j]=global_wins_table[0][j];		str_list_free (&partner);		return i;}/****************************************************************************read the last ID from the wins tdb file.****************************************************************************/static void get_our_last_id(WINS_OWNER *wins_owner){	TDB_CONTEXT *tdb;	tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);	if (!tdb) {		DEBUG(2,("get_our_last_id: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) ));		return;	}		wins_owner->max_version=((SMB_BIG_UINT)tdb_fetch_int32(tdb, INFO_ID_HIGH))<<32 | 				 (SMB_BIG_UINT)tdb_fetch_int32(tdb, INFO_ID_LOW);	tdb_close(tdb);}/****************************************************************************send the list of wins server we know.****************************************************************************/static void send_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET *r){	int i;	int s_ctx=get_server_assoc(q->header.assoc_ctx);	if (s_ctx==0) {		DEBUG(5, ("send_version_number_map_table: request for a partner not in our table\n"));		stop_packet(q, r, STOP_REASON_USER_REASON);		return;	}	/*	 * return an array of wins servers, we are partner with.	 * each entry contains the IP address and the version info	 * version: ID of the last entry we've got	 */	/* the first wins server must be self */	/*	 * get our last ID from the wins database	 * it can have been updated since last read	 * as nmbd got registration/release.	 */ 	get_our_last_id(&global_wins_table[0][0]);	r->rep.avmt_rep.wins_owner=talloc_array(mem_ctx, WINS_OWNER, partner_count);	if (r->rep.avmt_rep.wins_owner==NULL) {		stop_packet(q, r, STOP_REASON_USER_REASON);		return;	}		DEBUG(5,("send_version_number_map_table: partner_count: %d\n", partner_count));	for (i=0; i<partner_count; i++) {		DEBUG(5,("send_version_number_map_table, partner: %d -> %s, \n", i, inet_ntoa(global_wins_table[0][i].address)));		r->rep.avmt_rep.wins_owner[i]=global_wins_table[0][i];	}		r->rep.msg_type=1;	r->rep.avmt_rep.partner_count=partner_count;	r->rep.avmt_rep.initiating_wins_server.s_addr=0; /* blatant lie, NT4/w2K do the same ! */	fill_header(r, OPCODE_NON_NBT, s_ctx, MESSAGE_TYPE_REPLICATE);}/****************************************************************************for a given partner, ask it to send entries we don't have.****************************************************************************/static BOOL check_partners_and_send_entries(GENERIC_PACKET *q, GENERIC_PACKET *r, int partner){	int server;	int other;	SMB_BIG_UINT temp;	SMB_BIG_UINT current;	/*	 * we check if our partner has more records than us.	 * we need to check more than our direct partners as	 * we can have this case:	 * us: A, partners: B,C, indirect partner: D	 * A<->B, A<->C, B<->D, C<->D	 *	 * So if we're talking to B, we need to check if between	 * B and C, which one have more records about D.	 * and also check if we don't already have the records.	 */	 /* check all servers even indirect */	 for (server=1; global_wins_table[0][server].address.s_addr!=0; server++) {		current = global_wins_table[partner][server].max_version;				temp=0;				for (other=1; other<partner_count; other++) {			/* skip the partner itself */			if (other==partner)				continue;			if (global_wins_table[other][server].max_version > temp)				temp=global_wins_table[other][server].max_version;		}				if (current >= temp && current > global_wins_table[0][server].max_version) {			/* 			 * it has more records than every body else and more than us,			 * ask it the difference between what we have and what it has			 */			fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);			r->rep.msg_type=MESSAGE_REP_SEND_ENTRIES_REQUEST;			r->rep.se_rq.wins_owner.address=global_wins_table[partner][server].address;						r->rep.se_rq.wins_owner.max_version=global_wins_table[partner][server].max_version;			r->rep.se_rq.wins_owner.min_version=global_wins_table[0][server].max_version;			r->rep.se_rq.wins_owner.type=0;						write_server_assoc_table(q->header.assoc_ctx, global_wins_table[0][partner].address, global_wins_table[partner][server].address);						/*			 * and we update our version for this server			 * as we can't use the IDs returned in the send_entries function			 * the max ID can be larger than the largest ID returned			 */						global_wins_table[0][server].max_version=global_wins_table[partner][server].max_version;			return True;		}	}	return False;}	/****************************************************************************receive the list of wins server we know.****************************************************************************/static void receive_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET *r){	fstring peer;	struct in_addr addr;	int i,j,k,l;	int s_ctx=get_server_assoc(q->header.assoc_ctx);	if (s_ctx==0) {		DEBUG(5, ("receive_version_number_map_table: request for a partner not in our table\n"));		stop_packet(q, r, STOP_REASON_USER_REASON);		return;	}	fstrcpy(peer,get_peer_addr(q->fd));	addr=*interpret_addr2(peer);	get_our_last_id(&global_wins_table[0][0]);		DEBUG(5,("receive_version_number_map_table: received a map of %d server from: %s\n", 	          q->rep.avmt_rep.partner_count ,inet_ntoa(q->rep.avmt_rep.initiating_wins_server)));	DEBUG(5,("real peer is: %s\n", peer));	for (i=0; global_wins_table[0][i].address.s_addr!=addr.s_addr && i<partner_count;i++)		;	if (i==partner_count) {		DEBUG(5,("receive_version_number_map_table: unknown partner: %s\n", peer));		stop_packet(q, r, STOP_REASON_USER_REASON);		return;	}	for (j=0; j<q->rep.avmt_rep.partner_count;j++) {		/*		 * search if we already have this entry or if it's a new one		 * it can be a new one in case of propagation		 */		for (k=0; global_wins_table[0][k].address.s_addr!=0 && 			  global_wins_table[0][k].address.s_addr!=q->rep.avmt_rep.wins_owner[j].address.s_addr; k++);		global_wins_table[i][k].address.s_addr=q->rep.avmt_rep.wins_owner[j].address.s_addr;		global_wins_table[i][k].max_version=q->rep.avmt_rep.wins_owner[j].max_version;		global_wins_table[i][k].min_version=q->rep.avmt_rep.wins_owner[j].min_version;		global_wins_table[i][k].type=q->rep.avmt_rep.wins_owner[j].type;				/*		 * in case it's a new one, rewrite the address for all the partner		 * to reserve the slot.		 */		for(l=0; l<partner_count; l++)			global_wins_table[l][k].address.s_addr=q->rep.avmt_rep.wins_owner[j].address.s_addr;	}	dump_global_table();	/*	 * if this server have newer records than what we have	 * for several wins servers, we need to ask it.	 * Alas a send entry request is only on one server.	 * So in the send entry reply, we'll ask for the next server if required.	 */	if (check_partners_and_send_entries(q, r, i))		return;	/* it doesn't have more entries than us */	stop_packet(q, r, STOP_REASON_USER_REASON);}/****************************************************************************add an entry to the wins list we'll send.****************************************************************************/static BOOL add_record_to_winsname(WINS_NAME **wins_name, int *max_names, char *name, int type, int wins_flags, int id, struct in_addr *ip_list, int num_ips){	WINS_NAME *temp_list;	int i;	int current=*max_names;	temp_list=talloc_realloc(mem_ctx, *wins_name, WINS_NAME, current + 1);	if (temp_list==NULL)		return False;	temp_list[current].name_len=0x11;		safe_strcpy(temp_list[current].name, name, 15);	temp_list[current].type=type;	temp_list[current].empty=0;	temp_list[current].name_flag=wins_flags;	if ( (wins_flags&0x03) == 1 || (wins_flags&0x03)==2)		temp_list[current].group_flag=0x01000000;	else		temp_list[current].group_flag=0x00000000;		temp_list[current].id=id;		temp_list[current].owner.s_addr=ip_list[0].s_addr;	if (temp_list[current].name_flag & 2) {		temp_list[current].num_ip=num_ips;		temp_list[current].others=talloc_array(mem_ctx, struct in_addr, num_ips);		if (temp_list[current].others==NULL)			return False;			for (i=0; i<num_ips; i++)			temp_list[current].others[i].s_addr=ip_list[i].s_addr;	} else 		temp_list[current].num_ip=1;	temp_list[current].foo=0xffffffff;	*wins_name=temp_list;		return True;}/****************************************************************************send the list of name we have.****************************************************************************/static void send_entry_request(GENERIC_PACKET *q, GENERIC_PACKET *r){	int max_names=0;	int i;	time_t time_now = time(NULL);	WINS_OWNER *wins_owner;	TDB_CONTEXT *tdb;	TDB_DATA kbuf, dbuf, newkey;	int s_ctx=get_server_assoc(q->header.assoc_ctx);	int num_interfaces = iface_count();	if (s_ctx==0) {		DEBUG(1, ("send_entry_request: request for a partner not in our table\n"));		stop_packet(q, r, STOP_REASON_USER_REASON);		return;	}	wins_owner=&q->rep.se_rq.wins_owner;	r->rep.se_rp.wins_name=NULL;	DEBUG(3,("send_entry_request: we have been asked to send the list of wins records\n"));	DEBUGADD(3,("owned by: %s and between min: %d and max: %d\n", inet_ntoa(wins_owner->address),		    (int)wins_owner->min_version, (int)wins_owner->max_version));	/*	 * if we are asked to send records owned by us	 * we overwrite the wins ip with 0.0.0.0	 * to make it easy in case of multihomed	 */	for (i=0; i<num_interfaces; i++)		if (ip_equal(wins_owner->address, *iface_n_ip(i))) {			wins_owner->address=*interpret_addr2("0.0.0.0");			break;		}	tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);

⌨️ 快捷键说明

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