From 20b6203dac4bbb43e4e7bea0b214496d76d679d9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 2 Oct 1996 14:09:22 +0000 Subject: [PATCH] - a huge pile of changes from Luke which implement the browse.conf stuff and also fix a pile of nmbd bugs. Unfortunately I found it very hard to disentangle the new features from the bug fixes so I am putting in the new code. I hope this is the last big pile of changes to the 1.9.16 series! --- source/client/client.c | 16 +- source/client/clitar.c | 2 +- source/include/nameserv.h | 80 ++-- source/include/proto.h | 171 +++++---- source/include/smb.h | 6 +- source/lib/system.c | 9 + source/lib/util.c | 2 +- source/libsmb/nmblib.c | 2 +- source/nameannounce.c | 486 +++++++++++++----------- source/namebrowse.c | 57 +-- source/nameconf.c | 116 +++--- source/namedbname.c | 283 +++++++------- source/namedbresp.c | 12 +- source/namedbserver.c | 89 +++-- source/namedbsubnet.c | 189 +++++----- source/namedbwork.c | 133 +++---- source/nameelect.c | 347 ++++++++++------- source/namelogon.c | 31 +- source/namepacket.c | 346 ++++++++--------- source/nameresp.c | 395 +++++++++++--------- source/nameserv.c | 249 +++++++------ source/nameservreply.c | 4 +- source/nameservresp.c | 762 ++++++++++++++++++++------------------ source/namework.c | 465 +++++++++++------------ source/nmbd/nmbd.c | 144 +++---- source/nmbsync.c | 77 ++-- source/param/loadparm.c | 52 +-- source/smbd/ipc.c | 61 ++- source/smbd/pipes.c | 17 +- source/smbd/reply.c | 16 +- source/smbd/server.c | 2 + source/utils/nmblookup.c | 11 +- 32 files changed, 2547 insertions(+), 2085 deletions(-) diff --git a/source/client/client.c b/source/client/client.c index cdf33a14b3d..6db0f4694ec 100644 --- a/source/client/client.c +++ b/source/client/client.c @@ -3787,10 +3787,12 @@ static BOOL list_servers(char *wk_grp) for (i=0;iServerType & SV_TYPE_MASTER_BROWSER) #define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER) -#define AM_DOMCTL(work) (work->ServerType & SV_TYPE_DOMAIN_CTRL) +#define AM_DMBRSE(work) (work->ServerType & SV_TYPE_DOMAIN_MASTER) /* microsoft browser NetBIOS name */ #define MSBROWSE "\001\002__MSBROWSE__\002" @@ -99,19 +112,19 @@ enum master_state enum state_type { - NAME_STATUS_DOM_SRV_CHK, - NAME_STATUS_SRV_CHK, - NAME_REGISTER_CHALLENGE, - NAME_REGISTER, - NAME_RELEASE, - NAME_QUERY_CONFIRM, - NAME_QUERY_ANNOUNCE_HOST, - NAME_QUERY_SYNC_LOCAL, - NAME_QUERY_SYNC_REMOTE, - NAME_QUERY_DOM_SRV_CHK, - NAME_QUERY_SRV_CHK, - NAME_QUERY_FIND_MST, - NAME_QUERY_MST_CHK + NAME_STATUS_DOM_SRV_CHK, + NAME_STATUS_SRV_CHK, + NAME_REGISTER_CHALLENGE, + NAME_REGISTER, + NAME_RELEASE, + NAME_QUERY_CONFIRM, + NAME_QUERY_ANNOUNCE_HOST, + NAME_QUERY_SYNC_LOCAL, + NAME_QUERY_SYNC_REMOTE, + NAME_QUERY_DOM_SRV_CHK, + NAME_QUERY_SRV_CHK, + NAME_QUERY_FIND_MST, + NAME_QUERY_MST_CHK }; /* a netbios name structure */ @@ -121,6 +134,14 @@ struct nmb_name { int name_type; }; +/* A server name and comment. */ +struct server_identity +{ + char *name; + char *comment; + struct server_identity *next; +}; + /* a netbios flags + ip address structure */ /* this is used for multi-homed systems and for internet group names */ struct nmb_ip @@ -148,16 +169,16 @@ struct name_record /* browse and backup server cache for synchronising browse list */ struct browse_cache_record { - struct browse_cache_record *next; - struct browse_cache_record *prev; - - pstring name; - int type; - pstring group; - struct in_addr ip; - time_t sync_time; - BOOL synced; - BOOL local; + struct browse_cache_record *next; + struct browse_cache_record *prev; + + char name[17]; + int type; + char group[17]; + struct in_addr ip; + time_t sync_time; + BOOL synced; + BOOL local; }; /* this is used to hold the list of servers in my domain, and is */ @@ -183,7 +204,7 @@ struct work_record enum master_state state; /* work group info */ - fstring work_group; + char work_group[17]; int token; /* used when communicating with backup browsers */ int ServerType; @@ -214,17 +235,18 @@ struct response_record int fd; int quest_type; struct nmb_name name; - int nb_flags; + struct nmb_ip reply; time_t ttl; + enum name_source source; + int token; /* unique workgroup token id */ int server_type; - fstring my_name; - fstring my_comment; + char my_name[17]; + char my_comment[50]; BOOL bcast; BOOL recurse; struct in_addr send_ip; - struct in_addr reply_to_ip; int num_msgs; diff --git a/source/include/proto.h b/source/include/proto.h index e20238fee42..5f18c488ce7 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -51,7 +51,7 @@ char *smb_errstr(char *inbuf); /*The following definitions come from clitar.c */ -int strslashcmp(const char *s1, const char *s2); +int strslashcmp(char *s1,char *s2); void cmd_block(void); void cmd_tarmode(void); void cmd_setmode(void); @@ -124,6 +124,7 @@ char *lp_smbrun(void); char *lp_configfile(void); char *lp_smb_passwd_file(void); char *lp_serverstring(void); +char *lp_server_comment(void); char *lp_printcapname(void); char *lp_lockdir(void); char *lp_rootdir(void); @@ -146,6 +147,7 @@ char *lp_interfaces(void); char *lp_socket_address(void); BOOL lp_wins_support(void); BOOL lp_wins_proxy(void); +BOOL lp_local_master(void); BOOL lp_domain_master(void); BOOL lp_domain_logons(void); BOOL lp_preferred_master(void); @@ -292,20 +294,22 @@ int reply_sendend(char *inbuf,char *outbuf); /*The following definitions come from nameannounce.c */ void announce_request(struct work_record *work, struct in_addr ip); -void do_announce_request(char *info, char *to_name, int announce_type, - int from, - int to, struct in_addr dest_ip); +void do_announce_request(char *info, char *from_name, char *to_name, + int announce_type, int from, int to, struct in_addr dest_ip); void sync_server(enum state_type state, char *serv_name, char *work_name, - int name_type, - struct in_addr ip); + int name_type, + struct in_addr ip); void do_announce_host(int command, - char *from_name, int from_type, struct in_addr from_ip, - char *to_name , int to_type , struct in_addr to_ip, - time_t announce_interval, - char *server_name, int server_type, char *server_comment); + char *from_name, int from_type, struct in_addr from_ip, + char *to_name , int to_type , struct in_addr to_ip, + time_t announce_interval, + char *server_name, int server_type, + char major_version, char minor_version, + uint16 browse_version, uint16 browse_sig, + char *server_comment); void remove_my_servers(void); void announce_server(struct subnet_record *d, struct work_record *work, - char *name, char *comment, time_t ttl, int server_type); + char *name, char *comment, time_t ttl, int server_type); void announce_host(void); void announce_master(void); void announce_remote(void); @@ -314,9 +318,25 @@ void announce_remote(void); void expire_browse_cache(time_t t); struct browse_cache_record *add_browser_entry(char *name, int type, char *wg, - time_t ttl, struct in_addr ip, BOOL local); + time_t ttl, struct in_addr ip, BOOL local); void do_browser_lists(void); +/*The following definitions come from nameconf.c */ + +int get_num_workgroups(void); +int conf_workgroup_name_to_token(char *workgroup_name,char *default_name); +char *conf_workgroup_name(int token); +int conf_should_preferred_master(int token); +int conf_should_workgroup_member(int token); +int conf_should_local_master(int token); +int conf_should_domain_logon(int token); +int conf_should_domain_master(int token); +char *conf_browsing_alias(int token); +char *conf_browsing_alias_comment(int token); +char *conf_alias_to_workgroup(char *alias); +int conf_alias_to_token(char *alias); +void read_smbbrowse_conf(char *default_name); + /*The following definitions come from namedbname.c */ void set_samba_nb_type(void); @@ -324,24 +344,24 @@ BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2); BOOL ms_browser_name(char *name, int type); void remove_name(struct subnet_record *d, struct name_record *n); struct name_record *find_name(struct name_record *n, - struct nmb_name *name, - int search); + struct nmb_name *name, + int search); struct name_record *find_name_search(struct subnet_record **d, - struct nmb_name *name, - int search, struct in_addr ip); + struct nmb_name *name, + int search, struct in_addr ip); void dump_names(void); void load_netbios_names(void); void remove_netbios_name(struct subnet_record *d, - char *name,int type, enum name_source source, - struct in_addr ip); + char *name,int type, enum name_source source, + struct in_addr ip); struct name_record *add_netbios_entry(struct subnet_record *d, - char *name, int type, int nb_flags, - int ttl, enum name_source source, struct in_addr ip, - BOOL new_only,BOOL wins); -void expire_names(time_t t); + char *name, int type, int nb_flags, + int ttl, enum name_source source, struct in_addr ip, + BOOL new_only,BOOL wins); +void check_expire_names(time_t t); struct name_record *search_for_name(struct subnet_record **d, - struct nmb_name *question, - struct in_addr ip, int Time, int search); + struct nmb_name *question, + struct in_addr ip, int Time, int search); /*The following definitions come from namedbresp.c */ @@ -350,8 +370,9 @@ void add_response_record(struct subnet_record *d, void remove_response_record(struct subnet_record *d, struct response_record *n); struct response_record *make_response_queue_record(enum state_type state, - int id,uint16 fd, - int quest_type, char *name,int type, int nb_flags, time_t ttl, + int id,uint16 fd, int quest_type, + int token, char *name,int type, + enum name_source source, int nb_flags, time_t ttl, int server_type, char *my_name, char *my_comment, BOOL bcast,BOOL recurse, struct in_addr send_ip, struct in_addr reply_to_ip); @@ -361,13 +382,13 @@ struct response_record *find_response_record(struct subnet_record **d, /*The following definitions come from namedbserver.c */ void remove_old_servers(struct work_record *work, time_t t, - BOOL remove_all); + BOOL remove_all); struct server_record *find_server(struct work_record *work, char *name); struct server_record *add_server_entry(struct subnet_record *d, - struct work_record *work, - char *name,int servertype, - int ttl,char *comment, - BOOL replace); + struct work_record *work, + char *name,int servertype, + int ttl,char *comment, + BOOL replace); void expire_servers(time_t t); /*The following definitions come from namedbsubnet.c */ @@ -375,19 +396,21 @@ void expire_servers(time_t t); struct subnet_record *find_subnet(struct in_addr bcast_ip); struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast); void add_subnet_interfaces(void); -void add_my_subnets(char *group); +void add_workgroup_to_subnet(char *group, struct in_addr bcast_ip, + struct in_addr mask_ip); +void add_workgroups_to_subnets(); struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, - struct in_addr mask_ip, - char *name, BOOL add, BOOL lmhosts); + struct in_addr mask_ip, + char *name, BOOL add, BOOL lmhosts); void write_browse_list(void); /*The following definitions come from namedbwork.c */ struct work_record *remove_workgroup(struct subnet_record *d, - struct work_record *work, - BOOL remove_all_servers); + struct work_record *work, + BOOL remove_all_servers); struct work_record *find_workgroupstruct(struct subnet_record *d, - fstring name, BOOL add); + fstring name, BOOL add); void dump_workgroups(void); /*The following definitions come from nameelect.c */ @@ -395,13 +418,14 @@ void dump_workgroups(void); void check_master_browser(void); void browser_gone(char *work_name, struct in_addr ip); void send_election(struct subnet_record *d, char *group,uint32 criterion, - int timeup,char *name); + int timeup,char *name); void name_unregister_work(struct subnet_record *d, char *name, int name_type); -void name_register_work(struct subnet_record *d, char *name, int name_type, - int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast); +void name_register_work(struct subnet_record *d, int token, + char *name, int name_type, enum name_source source, + struct nmb_ip *data, time_t ttl, struct in_addr ip, BOOL bcast); void become_master(struct subnet_record *d, struct work_record *work); void become_nonmaster(struct subnet_record *d, struct work_record *work, - int remove_type); + int remove_type); void run_elections(void); void process_election(struct packet_struct *p,char *buf); BOOL check_elections(void); @@ -413,20 +437,20 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len); /*The following definitions come from namepacket.c */ void debug_browse_data(char *outbuf, int len); -void initiate_netbios_packet(uint16 *id, - int fd,int quest_type,char *name,int name_type, - int nb_flags,BOOL bcast,BOOL recurse, - struct in_addr to_ip); +BOOL initiate_netbios_packet(uint16 id, + int fd,int quest_type,char *name,int name_type, + int nb_flags,BOOL bcast,BOOL recurse, + struct in_addr to_ip); void reply_netbios_packet(struct packet_struct *p1,int trn_id, - int rcode, int rcv_code, int opcode, BOOL recurse, - struct nmb_name *rr_name,int rr_type,int rr_class,int ttl, - char *data,int len); + int rcode, int rcv_code, int opcode, BOOL recurse, + struct nmb_name *rr_name,int rr_type,int rr_class,int ttl, + char *data,int len); void queue_packet(struct packet_struct *packet); void run_packet_queue(); void listen_for_packets(BOOL run_election); BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname, - char *dstname,int src_type,int dest_type, - struct in_addr dest_ip,struct in_addr src_ip); + char *dstname,int src_type,int dest_type, + struct in_addr dest_ip,struct in_addr src_ip); /*The following definitions come from namequery.c */ @@ -439,27 +463,30 @@ BOOL name_query(int fd,char *name,int name_type, /*The following definitions come from nameresp.c */ +void update_name_trn_id(void); void expire_netbios_response_entries(); -struct response_record *queue_netbios_pkt_wins(struct subnet_record *d, - int fd,int quest_type,enum state_type state, - char *name,int name_type,int nb_flags, time_t ttl, - int server_type, char *my_name, char *my_comment, - BOOL bcast,BOOL recurse, - struct in_addr send_ip, struct in_addr reply_to_ip); -struct response_record *queue_netbios_packet(struct subnet_record *d, - int fd,int quest_type,enum state_type state,char *name, - int name_type,int nb_flags, time_t ttl, - int server_type, char *my_name, char *my_comment, - BOOL bcast,BOOL recurse, - struct in_addr send_ip, struct in_addr reply_to_ip); +void queue_netbios_pkt_wins(struct subnet_record *d, + int fd,int quest_type,enum state_type state, + int token, char *name,int name_type, + enum name_source source, int nb_flags, time_t ttl, + int server_type, char *my_name, char *my_comment, + BOOL bcast,BOOL recurse, + struct in_addr send_ip, struct in_addr reply_to_ip); +void queue_netbios_packet(struct subnet_record *d, + int fd,int quest_type,enum state_type state, + int token, char *name, int name_type, + enum name_source source, int nb_flags, time_t ttl, + int server_type, char *my_name, char *my_comment, + BOOL bcast,BOOL recurse, + struct in_addr send_ip, struct in_addr reply_to_ip); /*The following definitions come from nameserv.c */ -void remove_name_entry(struct subnet_record *d, char *name,int type); -void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags); +void remove_name_entry(struct subnet_record *d, int token, char *name,int type); +void add_my_name_entry(struct subnet_record *d, int token, + char *name,int type,int nb_flags); void add_my_names(void); void remove_my_names(); -void refresh_my_names(time_t t); void query_refresh_names(void); /*The following definitions come from nameservreply.c */ @@ -481,13 +508,18 @@ void reply_name_query(struct packet_struct *p); /*The following definitions come from nameservresp.c */ void debug_state_type(int state); +void response_process(struct in_addr ip, struct subnet_record *d, + struct response_record *n, + int rcode, char *nmb_data, struct nmb_name *q_name, + time_t ttl, BOOL bcast, struct nmb_name *ans_name); void response_netbios_packet(struct packet_struct *p); /*The following definitions come from namework.c */ -void reset_server(char *name, int state, struct in_addr ip); +void reset_server(struct work_record *work, char *name, int state, struct in_addr ip); void tell_become_backup(void); BOOL same_context(struct dgram_packet *dgram); +BOOL listening_name(struct work_record *work, struct nmb_name *n); void process_browse_packet(struct packet_struct *p,char *buf,int len); /*The following definitions come from nmbd.c */ @@ -513,7 +545,7 @@ int main(int argc,char *argv[]); char *getsmbpass(char *pass); void sync_browse_lists(struct subnet_record *d, struct work_record *work, - char *name, int nm_type, struct in_addr ip, BOOL local); + char *name, int nm_type, struct in_addr ip, BOOL local); /*The following definitions come from params.c */ @@ -533,7 +565,7 @@ void add_session_user(char *user); void dfs_unlogin(void); BOOL password_check(char *password); BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8); -BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password); +BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd); BOOL user_ok(char *user,int snum); BOOL authorise_login(int snum,char *user,char *password, int pwlen, BOOL *guest,BOOL *force,int vuid); @@ -737,6 +769,7 @@ unsigned int Ucrit_checkPid(int pid); int sys_select(fd_set *fds,struct timeval *tval); int sys_select(fd_set *fds,struct timeval *tval); int sys_unlink(char *fname); +unsigned int sys_random(int max_range); int sys_open(char *fname,int flags,int mode); DIR *sys_opendir(char *dname); int sys_stat(char *fname,struct stat *sbuf); @@ -813,7 +846,7 @@ void set_socket_options(int fd, char *options); void close_sockets(void ); BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups); char *StrCpy(char *dest,char *src); -char *StrnCpy(char *dest,const char *src,int n); +char *StrnCpy(char *dest,char *src,int n); void putip(void *dest,void *src); int name_mangle(char *In,char *Out,char name_type); BOOL file_exist(char *fname,struct stat *sbuf); diff --git a/source/include/smb.h b/source/include/smb.h index f5d35d5261e..56ad8cbacdc 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -380,10 +380,10 @@ typedef struct /* used for server information: client, nameserv and ipc */ struct server_info_struct { - fstring name; + char name[17]; uint32 type; - fstring comment; - fstring domain; /* used ONLY in ipc.c NOT namework.c */ + char comment[50]; + char domain[17]; /* used ONLY in ipc.c NOT namework.c */ BOOL server_added; /* used ONLY in ipc.c NOT namework.c */ }; diff --git a/source/lib/system.c b/source/lib/system.c index 81e9a6679ad..f6b916881bf 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -115,6 +115,15 @@ int sys_unlink(char *fname) } +/******************************************************************* +random number generator +********************************************************************/ +unsigned int sys_random(int max_range) +{ + return(((unsigned int)random()) % max_range); +} + + /******************************************************************* a simple open() wrapper ********************************************************************/ diff --git a/source/lib/util.c b/source/lib/util.c index 31ad3da31cb..86b0016dd28 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -598,7 +598,7 @@ char *StrCpy(char *dest,char *src) /**************************************************************************** line strncpy but always null terminates. Make sure there is room! ****************************************************************************/ -char *StrnCpy(char *dest,const char *src,int n) +char *StrnCpy(char *dest,char *src,int n) { char *d = dest; if (!dest) return(NULL); diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c index 4113b34cab4..ef5c9da434e 100644 --- a/source/libsmb/nmblib.c +++ b/source/libsmb/nmblib.c @@ -65,7 +65,7 @@ static void debug_nmb_res_rec(struct res_rec *res, char *hdr) for (j = 0; j < 16; j++) { if (i+j >= res->rdlength) break; - DEBUG(4, ("%02X", (unsigned char)res->rdata[i+j])); + DEBUG(4, ("%02x", (unsigned char)res->rdata[i+j])); } DEBUG(4, ("\n")); diff --git a/source/nameannounce.c b/source/nameannounce.c index ff2c89df852..c7a52473b66 100644 --- a/source/nameannounce.c +++ b/source/nameannounce.c @@ -23,19 +23,18 @@ 14 jan 96: lkcl@pires.co.uk added multiple workgroup domain master support + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. + */ #include "includes.h" -#define TEST_CODE - extern int DEBUGLEVEL; extern BOOL CanRecurse; extern struct in_addr ipzero; -extern pstring myname; - extern int ClientDGRAM; extern int ClientNMB; @@ -43,14 +42,17 @@ extern int ClientNMB; extern struct subnet_record *subnetlist; extern int updatecount; -extern int workgroup_count; -extern struct in_addr ipgrp; +extern struct in_addr ipgrp; +extern pstring myname; /**************************************************************************** - send a announce request to the local net + Send a announce request to the local net. + + This is called by become_master(). This purpose of this action is to + encourage servers to send us host announcements right away. **************************************************************************/ void announce_request(struct work_record *work, struct in_addr ip) { @@ -62,7 +64,7 @@ void announce_request(struct work_record *work, struct in_addr ip) work->needannounce = True; DEBUG(2,("sending announce request to %s for workgroup %s\n", - inet_ntoa(ip),work->work_group)); + inet_ntoa(ip),work->work_group)); bzero(outbuf,sizeof(outbuf)); p = outbuf; @@ -71,8 +73,7 @@ void announce_request(struct work_record *work, struct in_addr ip) CVAL(p,0) = work->token; /* (local) unique workgroup token id */ p++; - StrnCpy(p,myname,16); - strupper(p); + StrnCpy(p,conf_browsing_alias(work->token),16); p = skip_string(p,1); /* XXXX note: if we sent the announcement request to 0x1d instead @@ -80,16 +81,17 @@ void announce_request(struct work_record *work, struct in_addr ip) us instead of the members of the workgroup. wha-hey! */ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip)); + conf_browsing_alias(work->token),work->work_group, + 0x20, 0x1e, + ip,*iface_ip(ip)); } /**************************************************************************** request an announcement **************************************************************************/ -void do_announce_request(char *info, char *to_name, int announce_type, - int from, - int to, struct in_addr dest_ip) +void do_announce_request(char *info, char *from_name, char *to_name, + int announce_type, int from, int to, struct in_addr dest_ip) { pstring outbuf; char *p; @@ -100,14 +102,15 @@ void do_announce_request(char *info, char *to_name, int announce_type, p++; DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n", - announce_type, info, inet_ntoa(dest_ip),to_name,to)); + announce_type, info, inet_ntoa(dest_ip),to_name,to)); StrnCpy(p,info,16); strupper(p); p = skip_string(p,1); send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,to_name,from,to,dest_ip,*iface_ip(dest_ip)); + from_name,to_name,from,to, + dest_ip,*iface_ip(dest_ip)); } @@ -116,19 +119,23 @@ void do_announce_request(char *info, char *to_name, int announce_type, control ends up back here via response_name_query. **************************************************************************/ void sync_server(enum state_type state, char *serv_name, char *work_name, - int name_type, - struct in_addr ip) -{ + int name_type, + struct in_addr ip) +{ + int token = conf_workgroup_name_to_token(work_name, myname); + /* with a domain master we can get the whole list (not local only list) */ BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK); add_browser_entry(serv_name, name_type, work_name, 0, ip, local_only); - if (state == NAME_STATUS_DOM_SRV_CHK) + if (state == NAME_STATUS_DOM_SRV_CHK && conf_should_local_master(token)) { /* announce ourselves as a master browser to serv_name */ - do_announce_request(myname, serv_name, ANN_MasterAnnouncement, - 0x20, 0, ip); + do_announce_request(conf_browsing_alias(token), /* info */ + conf_browsing_alias(token), /* from */ + serv_name, /* to */ + ANN_MasterAnnouncement, 0x20, 0,ip); } } @@ -137,46 +144,50 @@ void sync_server(enum state_type state, char *serv_name, char *work_name, send a host announcement packet **************************************************************************/ void do_announce_host(int command, - char *from_name, int from_type, struct in_addr from_ip, - char *to_name , int to_type , struct in_addr to_ip, - time_t announce_interval, - char *server_name, int server_type, char *server_comment) + char *from_name, int from_type, struct in_addr from_ip, + char *to_name , int to_type , struct in_addr to_ip, + time_t announce_interval, + char *server_name, int server_type, + char major_version, char minor_version, + uint16 browse_version, uint16 browse_sig, + char *server_comment) { - pstring outbuf; - char *p; + pstring outbuf; + char *p; - bzero(outbuf,sizeof(outbuf)); - p = outbuf+1; + bzero(outbuf,sizeof(outbuf)); + p = outbuf+1; - /* command type */ - CVAL(outbuf,0) = command; + /* command type */ + CVAL(outbuf,0) = command; - /* announcement parameters */ - CVAL(p,0) = updatecount; - SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */ + /* announcement parameters */ + CVAL(p,0) = updatecount; + SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */ - StrnCpy(p+5,server_name,16); - strupper(p+5); + StrnCpy(p+5,server_name,16); + strupper(p+5); - CVAL(p,21) = 0x02; /* major version */ - CVAL(p,22) = 0x02; /* minor version */ + CVAL(p,21) = major_version; + CVAL(p,22) = minor_version; - SIVAL(p,23,server_type); - SSVAL(p,27,0x010f); /* browse version: got from NT/AS 4.00 */ - SSVAL(p,29,0xaa55); /* browse signature */ + SIVAL(p,23,server_type); - strcpy(p+31,server_comment); - p += 31; - p = skip_string(p,1); + SSVAL(p,27,browse_version); + SSVAL(p,29,browse_sig); + + strcpy(p+31,server_comment); + p += 31; + p = skip_string(p,1); debug_browse_data(outbuf, PTR_DIFF(p,outbuf)); - /* send the announcement */ - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf, - PTR_DIFF(p,outbuf), - from_name, to_name, - from_type, to_type, - to_ip, from_ip); + /* send the announcement */ + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf, + PTR_DIFF(p,outbuf), + from_name, to_name, + from_type, to_type, + to_ip, from_ip); } @@ -185,20 +196,23 @@ void do_announce_host(int command, ****************************************************************************/ void remove_my_servers(void) { - struct subnet_record *d; - for (d = subnetlist; d; d = d->next) - { - struct work_record *work; - for (work = d->workgrouplist; work; work = work->next) - { - struct server_record *s; - for (s = work->serverlist; s; s = s->next) - { - if (!strequal(myname,s->serv.name)) continue; - announce_server(d, work, s->serv.name, s->serv.comment, 0, 0); - } - } - } + struct subnet_record *d; + for (d = subnetlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + struct server_record *s; + for (s = work->serverlist; s; s = s->next) + { + if (!strequal(conf_browsing_alias(work->token),s->serv.name)) + { + continue; + } + announce_server(d, work, s->serv.name, s->serv.comment, 0, 0); + } + } + } } @@ -206,9 +220,14 @@ void remove_my_servers(void) announce a server entry ****************************************************************************/ void announce_server(struct subnet_record *d, struct work_record *work, - char *name, char *comment, time_t ttl, int server_type) + char *name, char *comment, time_t ttl, int server_type) { - uint32 domain_type = SV_TYPE_DOMAIN_ENUM|DFLT_SERVER_TYPE; + /* domain type cannot have anything in it that might confuse + a client into thinking that the domain is in fact a server. + (SV_TYPE_SERVER_UNIX, for example) + */ + uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT; + BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp); if (wins_iface && server_type != 0) @@ -216,14 +235,13 @@ void announce_server(struct subnet_record *d, struct work_record *work, /* wins pseudo-ip interface */ if (!AM_MASTER(work)) { - /* non-master announce by unicast to the domain - master */ + /* non-master announce by unicast to the domain master */ if (!lp_wins_support() && *lp_wins_server()) { /* look up the domain master with the WINS server */ queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, NAME_QUERY_ANNOUNCE_HOST, - work->work_group,0x1b,0,ttl*1000, + work->token,work->work_group,0x1b,0,0,ttl*1000, server_type,name,comment, False, False, ipzero, d->bcast_ip); } @@ -239,9 +257,7 @@ void announce_server(struct subnet_record *d, struct work_record *work, /* XXXX any other kinds of announcements we need to consider here? e.g local master browsers... no. local master browsers do - local master announcements to their domain master. they even - use WINS lookup of the domain master if another wins server - is being used! + local master announcements to their domain master. */ } else @@ -252,10 +268,13 @@ void announce_server(struct subnet_record *d, struct work_record *work, inet_ntoa(d->bcast_ip),work->work_group)); do_announce_host(ANN_LocalMasterAnnouncement, - name , 0x00, d->myip, - work->work_group, 0x1e, d->bcast_ip, - ttl*1000, - name, server_type, comment); + name , 0x00, d->myip, + work->work_group, 0x1e, d->bcast_ip, + ttl*1000, + name, server_type, + HOST_MAJOR_VERSION, HOST_MINOR_VERSION, + HOST_BROWSE_VERSION, HOST_BROWSE_SIGNATURE, + comment); DEBUG(3,("sending domain announce to %s for %s\n", inet_ntoa(d->bcast_ip),work->work_group)); @@ -264,11 +283,13 @@ void announce_server(struct subnet_record *d, struct work_record *work, if (server_type != 0) { do_announce_host(ANN_DomainAnnouncement, - name , 0x00, d->myip, - MSBROWSE, 0x01, d->bcast_ip, - ttl*1000, - work->work_group, server_type ? domain_type : 0, - name); + name , 0x00, d->myip, + MSBROWSE, 0x01, d->bcast_ip, + ttl*1000, + work->work_group, server_type ? domain_type : 0, + WG_MAJOR_VERSION, WG_MINOR_VERSION, + WG_BROWSE_VERSION, WG_BROWSE_SIGNATURE, + name); } } else @@ -277,10 +298,13 @@ void announce_server(struct subnet_record *d, struct work_record *work, inet_ntoa(d->bcast_ip),work->work_group)); do_announce_host(ANN_HostAnnouncement, - name , 0x00, d->myip, - work->work_group, 0x1d, d->bcast_ip, - ttl*1000, - name, server_type, comment); + name , 0x00, d->myip, + work->work_group, 0x1d, d->bcast_ip, + ttl*1000, + name, server_type, + HOST_MAJOR_VERSION, HOST_MINOR_VERSION, + HOST_BROWSE_VERSION, HOST_BROWSE_SIGNATURE, + comment); } } } @@ -293,11 +317,6 @@ void announce_host(void) time_t t = time(NULL); struct subnet_record *d; pstring comment; - char *my_name; - - StrnCpy(comment, lp_serverstring(), 43); - - my_name = *myname ? myname : "NoName"; for (d = subnetlist; d; d = d->next) { @@ -306,62 +325,63 @@ void announce_host(void) if (ip_equal(d->bcast_ip, ipgrp)) continue; for (work = d->workgrouplist; work; work = work->next) - { - uint32 stype = work->ServerType; - struct server_record *s; - BOOL announce = False; - + { + uint32 stype = work->ServerType; + struct server_record *s; + + char *my_name = conf_browsing_alias(work->token); + char *my_comment = conf_browsing_alias_comment(work->token); + + StrnCpy(comment, my_comment, 43); + /* must work on the code that does announcements at up to 30 seconds later if a master browser sends us a request announce. */ - if (work->needannounce) { - /* drop back to a max 3 minute announce - this is to prevent a - single lost packet from stuffing things up for too long */ - work->announce_interval = MIN(work->announce_interval, - CHECK_TIME_MIN_HOST_ANNCE*60); - work->lastannounce_time = t - (work->announce_interval+1); - } - - /* announce every minute at first then progress to every 12 mins */ - if (work->lastannounce_time && - (t - work->lastannounce_time) < work->announce_interval) - continue; - - if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60) - work->announce_interval += 60; - - work->lastannounce_time = t; - - for (s = work->serverlist; s; s = s->next) { - if (strequal(myname, s->serv.name)) { - announce = True; - break; - } - } - - if (announce) { - announce_server(d,work,my_name,comment, - work->announce_interval,stype); - } - - if (work->needannounce) - { - work->needannounce = False; - break; - /* sorry: can't do too many announces. do some more later */ - } - } + if (work->needannounce) { + /* drop back to a max 3 minute announce - this is to prevent a + single lost packet from stuffing things up for too long */ + work->announce_interval = MIN(work->announce_interval, + CHECK_TIME_MIN_HOST_ANNCE*60); + work->lastannounce_time = t - (work->announce_interval+1); + } + + /* announce every minute at first then progress to every 12 mins */ + if (work->lastannounce_time && + (t - work->lastannounce_time) < work->announce_interval) + continue; + + if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60) + work->announce_interval += 60; + + work->lastannounce_time = t; + + for (s = work->serverlist; s; s = s->next) { + if (strequal(my_name, s->serv.name)) + { + announce_server(d,work,my_name,comment, + work->announce_interval,stype); + break; + } + } + + if (work->needannounce) + { + work->needannounce = False; + break; + /* sorry: can't do too many announces. do some more later */ + } + } } } /**************************************************************************** - announce myself as a master to all other primary domain conrollers. + announce samba as a master to all other primary domain conrollers. this actually gets done in search_and_sync_workgroups() via the - NAME_QUERY_DOM_SRV_CHK command, if there is a response from the + NAME_QUERY_DOM_SRV_CHK state, if there is a response from the name query initiated here. see response_name_query() **************************************************************************/ void announce_master(void) @@ -373,97 +393,108 @@ void announce_master(void) if (!last) last = t; if (t-last < CHECK_TIME_MST_ANNOUNCE * 60) - return; + return; last = t; for (d = subnetlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) { - struct work_record *work; - for (work = d->workgrouplist; work; work = work->next) - { - if (AM_MASTER(work)) - { - am_master = True; - } - } + if (AM_MASTER(work) || AM_DMBRSE(work)) + { + am_master = True; + } } + } if (!am_master) return; /* only proceed if we are a master browser */ for (d = subnetlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) { - struct work_record *work; - for (work = d->workgrouplist; work; work = work->next) - { - struct server_record *s; - for (s = work->serverlist; s; s = s->next) - { - if (strequal(s->serv.name, myname)) continue; - - /* all DOMs (which should also be master browsers) */ - if (s->serv.type & SV_TYPE_DOMAIN_CTRL) - { - /* check the existence of a pdc for this workgroup, and if - one exists at the specified ip, sync with it and announce - ourselves as a master browser to it */ - - if (!*lp_domain_controller() || - !strequal(lp_domain_controller(), s->serv.name)) - { - if (!lp_wins_support() && *lp_wins_server()) - { - queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, - NAME_QUERY_DOM_SRV_CHK, - work->work_group,0x1b,0,0,0,NULL,NULL, - False, False, ipzero, ipzero); - } - else - { - struct subnet_record *d2; - for (d2 = subnetlist; d2; d2 = d2->next) - { - queue_netbios_packet(d,ClientNMB,NMB_QUERY, - NAME_QUERY_DOM_SRV_CHK, - work->work_group,0x1b,0,0,0,NULL,NULL, - True, False, d2->bcast_ip, d2->bcast_ip); - } - } - } - } - } - - /* now do primary domain controller - the one that's not - necessarily in our browse lists, although it ought to be - this pdc is the one that we get TOLD about through smb.conf. - basically, if it's on a subnet that we know about, it may end - up in our browse lists (which is why it's explicitly excluded - in the code above) */ - - if (*lp_domain_controller()) - { - struct in_addr ip; - BOOL bcast = False; - - ip = *interpret_addr2(lp_domain_controller()); - - if (zero_ip(ip)) { - ip = d->bcast_ip; - bcast = True; - } - - DEBUG(2, ("Searching for DOM %s at %s\n", - lp_domain_controller(), inet_ntoa(ip))); - - /* check the existence of a pdc for this workgroup, and if - one exists at the specified ip, sync with it and announce - ourselves as a master browser to it */ - queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK, - work->work_group,0x1b,0,0,0,NULL,NULL, - bcast, False, ip, ip); - } - } + struct server_record *s; + for (s = work->serverlist; s; s = s->next) + { + if (strequal(s->serv.name, conf_browsing_alias(work->token))) continue; + + /* all master browsers */ + if (s->serv.type & SV_TYPE_DOMAIN_MASTER) + { + /* check the existence of a domain master for this workgroup, + and if one exists at the specified ip, sync with it and + announce ourselves as a local master browser to it */ + + /* exclude lp_domain_controller() from this check if it's + in our browse lists, because it's dealt with separately + */ + if (!*lp_domain_controller() || + !strequal(lp_domain_controller(), s->serv.name)) + { + if (lp_wins_support() || *lp_wins_server()) + { + /* query the WINS server (that may include samba itself) + to find the browse master + */ + queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, + NAME_QUERY_DOM_SRV_CHK, + work->token, + work->work_group,0x1b,0,0,0,0,NULL,NULL, + False, False, ipzero, ipzero); + } + else + { + struct subnet_record *d2; + for (d2 = subnetlist; d2; d2 = d2->next) + { + /* query by broadcast on every local interface + to find the browse master + */ + queue_netbios_packet(d,ClientNMB,NMB_QUERY, + NAME_QUERY_DOM_SRV_CHK, + work->token, work->work_group,0x1b, + 0,0,0,0,NULL,NULL, + True, False, d2->bcast_ip, d2->bcast_ip); + } + } + } + } + } + + /* now do primary domain controller - the one that's not + necessarily in our browse lists, although it ought to be + this pdc is the one that we get TOLD about through smb.conf. + basically, if it's on a subnet that we know about, it may end + up in our browse lists (which is why it's explicitly excluded + in the code above) */ + + if (*lp_domain_controller()) + { + struct in_addr ip; + + ip = *interpret_addr2(lp_domain_controller()); + + /* if the ip is zero, then make the query to samba as a WINS server */ + /* XXXX later, if this also fails, we could also do a broadcast query on + samba's local subnets + */ + + DEBUG(2, ("Searching for DOM %s at %s\n", + lp_domain_controller(), inet_ntoa(ip))); + + /* check the existence of a pdc for this workgroup, and if + one exists at the specified ip, sync with it and announce + ourselves as a master browser to it */ + queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK, + work->token, work->work_group,0x1b, + 0,0,0,0,NULL,NULL, + False, False, ip, ip); + } } + } } @@ -481,6 +512,7 @@ void announce_remote(void) pstring s2; struct in_addr addr; char *comment,*workgroup; + int token; int stype = DFLT_SERVER_TYPE; if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL) @@ -491,13 +523,16 @@ void announce_remote(void) s = lp_remote_announce(); if (!*s) return; - comment = lp_serverstring(); - workgroup = lp_workgroup(); + comment = lp_serverstring(); /* default comment */ + workgroup = lp_workgroup(); /* default workgroup name */ - for (ptr=s; next_token(&ptr,s2,NULL); ) { + for (ptr=s; next_token(&ptr,s2,NULL); ) + { /* the entries are of the form a.b.c.d/WORKGROUP with WORKGROUP being optional */ char *wgroup; + char *my_name; + extern pstring myname; /* samba's default NetBIOS name */ wgroup = strchr(s2,'/'); if (wgroup) *wgroup++ = 0; @@ -506,10 +541,17 @@ void announce_remote(void) addr = *interpret_addr2(s2); - do_announce_host(ANN_HostAnnouncement,myname,0x20,*iface_ip(addr), - wgroup,0x1e,addr, - REMOTE_ANNOUNCE_INTERVAL, - myname,stype,comment); + token = conf_workgroup_name_to_token(wgroup, myname); + my_name = conf_browsing_alias(token); + my_name = my_name ? my_name : myname; + + do_announce_host(ANN_HostAnnouncement, + my_name, 0x20, *iface_ip(addr), + wgroup , 0x1e, addr, + REMOTE_ANNOUNCE_INTERVAL, + my_name,stype, + HOST_MAJOR_VERSION, HOST_MINOR_VERSION, + HOST_BROWSE_VERSION, HOST_BROWSE_SIGNATURE, + comment); } - } diff --git a/source/namebrowse.c b/source/namebrowse.c index b426bc7a150..494315ec81c 100644 --- a/source/namebrowse.c +++ b/source/namebrowse.c @@ -23,6 +23,9 @@ 14 jan 96: lkcl@pires.co.uk added multiple workgroup domain master support + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. + */ #include "includes.h" @@ -71,21 +74,21 @@ void expire_browse_cache(time_t t) for (b = browserlist; b; b = nextb) { if (b->synced && b->sync_time < t) - { - DEBUG(3,("Removing dead cached browser %s\n",b->name)); - nextb = b->next; - - if (b->prev) b->prev->next = b->next; - if (b->next) b->next->prev = b->prev; - - if (browserlist == b) browserlist = b->next; - - free(b); - } + { + DEBUG(3,("Removing dead cached browser %s\n",b->name)); + nextb = b->next; + + if (b->prev) b->prev->next = b->next; + if (b->next) b->next->prev = b->prev; + + if (browserlist == b) browserlist = b->next; + + free(b); + } else - { - nextb = b->next; - } + { + nextb = b->next; + } } } @@ -94,7 +97,7 @@ void expire_browse_cache(time_t t) add a browser entry ****************************************************************************/ struct browse_cache_record *add_browser_entry(char *name, int type, char *wg, - time_t ttl, struct in_addr ip, BOOL local) + time_t ttl, struct in_addr ip, BOOL local) { BOOL newentry=False; @@ -109,9 +112,9 @@ struct browse_cache_record *add_browser_entry(char *name, int type, char *wg, if (b && b->synced) { /* entries get left in the cache for a while. this stops sync'ing too - often if the network is large */ + often if the network is large */ DEBUG(4, ("browser %s %s %s already sync'd at time %d\n", - b->name, b->group, inet_ntoa(b->ip), b->sync_time)); + b->name, b->group, inet_ntoa(b->ip), b->sync_time)); return NULL; } @@ -146,12 +149,12 @@ struct browse_cache_record *add_browser_entry(char *name, int type, char *wg, add_browse_cache(b); DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n", - wg, name, type, inet_ntoa(ip),ttl)); + wg, name, type, inet_ntoa(ip),ttl)); } else { DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n", - wg, name, type, inet_ntoa(ip),ttl)); + wg, name, type, inet_ntoa(ip),ttl)); } return(b); @@ -166,23 +169,23 @@ static void start_sync_browse_entry(struct browse_cache_record *b) struct subnet_record *d; struct work_record *work; - if (!(d = find_subnet(b->ip))) return; - + if( (d = find_subnet(b->ip)) == (struct subnet_record *)NULL ) return; + if (!(work = find_workgroupstruct(d, b->group, False))) return; - + /* only sync if we are the master */ if (AM_MASTER(work)) { - + /* first check whether the group we intend to sync with exists. if it doesn't, the server must have died. o dear. */ - + /* see response_netbios_packet() or expire_netbios_response_entries() */ queue_netbios_packet(d,ClientNMB,NMB_QUERY, b->local?NAME_QUERY_SYNC_LOCAL:NAME_QUERY_SYNC_REMOTE, - b->group,0x20,0,0,0,NULL,NULL, - False,False,b->ip,b->ip); + work->token,b->group,0x20,0,0,0,0,NULL,NULL, + False,False,b->ip,b->ip); } - + b->synced = True; } diff --git a/source/nameconf.c b/source/nameconf.c index 79fa2abe431..2e1bdf5c79a 100644 --- a/source/nameconf.c +++ b/source/nameconf.c @@ -58,10 +58,12 @@ struct smbbrowse char work_name[16]; /* workgroup name */ char browsing_alias[16]; /* alias for our role in this workgroup */ struct server_identity *my_names; /* a list of server name we should appear here as */ - BOOL should_workgroup_member; /* should we try to become a member of this workgroup? */ - BOOL should_local_master; /* should we try to become a master browser? */ - BOOL should_domain_master; /* should we try to become the domain master browser? */ -} ; + BOOL should_workgroup_member; /* should we be a member of this workgroup? */ + BOOL should_local_master; /* should we be a master browser? */ + BOOL should_preferred_master; /* should we initiate attempts to become a master browser? */ + BOOL should_domain_master; /* should we be the domain master browser? */ + BOOL should_domain_logon; /* should we be the domain logon? */ +}; /* The whole list */ static struct smbbrowse *smbbrowse_workgroups = (struct smbbrowse*)NULL; @@ -82,12 +84,12 @@ int get_num_workgroups(void) ** old one as a model. */ static struct smbbrowse *new_workgroup(struct smbbrowse *model, - const char *workgroup_name, - const char *default_name) + char *workgroup_name, + char *default_name) { struct smbbrowse *new; - if( ! (array_size > nexttoken) ) + if ( ! (array_size > nexttoken) ) { array_size += 10; smbbrowse_workgroups = (struct smbbrowse*)realloc(smbbrowse_workgroups, @@ -96,7 +98,7 @@ static struct smbbrowse *new_workgroup(struct smbbrowse *model, new = &smbbrowse_workgroups[nexttoken]; - if(model != (struct smbbrowse *)NULL ) + if (model != (struct smbbrowse *)NULL ) memcpy(new, model, sizeof(struct smbbrowse)); else memset(new, 0, sizeof(struct smbbrowse)); @@ -122,28 +124,27 @@ static struct smbbrowse *new_workgroup(struct smbbrowse *model, ** If the workgroup does not exist a new token is assigned unless ** new workgroups are not allowed. */ -int conf_workgroup_name_to_token(const char *workgroup_name, - const char *default_name) +int conf_workgroup_name_to_token(char *workgroup_name,char *default_name) { int idx; /* Look for an existing instance. */ - for(idx=0; idx < nexttoken; idx++) + for (idx=0; idx < nexttoken; idx++) { - if(strequal(workgroup_name, smbbrowse_workgroups[idx].work_name)) + if (strequal(workgroup_name, smbbrowse_workgroups[idx].work_name)) { return idx; } } /* See if creating new ones in admissable. */ - for(idx=0; idx < nexttoken; idx++) + for (idx=0; idx < nexttoken; idx++) { - if(strequal("*", smbbrowse_workgroups[idx].work_name)) + if (strequal("*", smbbrowse_workgroups[idx].work_name)) { struct smbbrowse *w = new_workgroup(&smbbrowse_workgroups[idx], workgroup_name, default_name); - w->should_workgroup_member = False; + w->should_workgroup_member = True; return (nexttoken - 1); } @@ -159,7 +160,7 @@ int conf_workgroup_name_to_token(const char *workgroup_name, */ static int range_check(int token) { - if(token < 0 || token >= nexttoken) + if (token < 0 || token >= nexttoken) { DEBUG(0, ("range_check(): failed\n")); return True; @@ -173,12 +174,25 @@ static int range_check(int token) */ char *conf_workgroup_name(int token) { - if(range_check(token)) + if (range_check(token)) return (char*)NULL; return smbbrowse_workgroups[token].work_name; } +/* +** Given a token, return True if we should try +** to become a master browser. +*/ +int conf_should_preferred_master(int token) + { + + if (range_check(token)) + return False; + + return smbbrowse_workgroups[token].should_preferred_master; + } + /* ** Given a token, return True if we should try ** to become a master browser. @@ -186,7 +200,7 @@ char *conf_workgroup_name(int token) int conf_should_workgroup_member(int token) { - if(range_check(token)) + if (range_check(token)) return False; return smbbrowse_workgroups[token].should_workgroup_member; @@ -197,12 +211,22 @@ int conf_should_workgroup_member(int token) ** to become a master browser. */ int conf_should_local_master(int token) - { - if(range_check(token)) - return False; +{ + if (range_check(token)) return False; return smbbrowse_workgroups[token].should_local_master; - } +} + +/* +** Given a token, return True if we should try +** to become a domain master browser. +*/ +int conf_should_domain_logon(int token) +{ + if (range_check(token)) return False; + + return smbbrowse_workgroups[token].should_domain_logon; +} /* ** Given a token, return True if we should try @@ -210,7 +234,7 @@ int conf_should_local_master(int token) */ int conf_should_domain_master(int token) { - if(range_check(token)) + if (range_check(token)) return False; return smbbrowse_workgroups[token].should_domain_master; @@ -220,12 +244,12 @@ int conf_should_domain_master(int token) ** Given a token, return the name. */ char *conf_browsing_alias(int token) - { - if(range_check(token)) +{ + if (range_check(token)) return (char*)NULL; return smbbrowse_workgroups[token].browsing_alias; - } +} /* ** Return the server comment which should be used with the @@ -233,27 +257,27 @@ char *conf_browsing_alias(int token) */ char *conf_browsing_alias_comment(int token) { - if(range_check(token)) + if (range_check(token)) return (char*) NULL; - return "Browser"; - } + return lp_server_comment(); +} /* ** Given an alias name for this server, return the name of the workgroup ** for which it is the browsing alias. */ -char *conf_alias_to_workgroup(const char *alias) +char *conf_alias_to_workgroup(char *alias) { int x; DEBUG(4,("alias_to_workgroup: %s", alias)); - for(x=0; x < nexttoken; x++) + for (x=0; x < nexttoken; x++) { DEBUG(4,("%s ", smbbrowse_workgroups[x].browsing_alias)); - if(strequal(alias, smbbrowse_workgroups[x].browsing_alias)) + if (strequal(alias, smbbrowse_workgroups[x].browsing_alias)) { DEBUG(4,("OK\n")); return smbbrowse_workgroups[x].work_name; @@ -267,13 +291,13 @@ char *conf_alias_to_workgroup(const char *alias) ** Given an alias name for this server, return the name of the workgroup ** for which it is the browsing alias. */ -int conf_alias_to_token(const char *alias) +int conf_alias_to_token(char *alias) { int x; - for(x=0; x < nexttoken; x++) + for (x=0; x < nexttoken; x++) { - if(strequal(alias, smbbrowse_workgroups[x].browsing_alias)) + if (strequal(alias, smbbrowse_workgroups[x].browsing_alias)) { return x; } @@ -285,21 +309,25 @@ int conf_alias_to_token(const char *alias) ** Since there is no smbbrowse.conf file, we will fill in ** the structures with information from the smb.conf file. */ -static void default_smbbrowse_conf(const char *default_name) +static void default_smbbrowse_conf(char *default_name) { struct smbbrowse *w; /* The workgroup specified in smb.conf */ w = new_workgroup((struct smbbrowse *)NULL, lp_workgroup(), default_name); - w->should_local_master = lp_preferred_master(); - w->should_domain_master = lp_domain_master(); + w->should_local_master = lp_local_master(); + w->should_domain_master = lp_domain_master(); + w->should_domain_logon = lp_domain_logons(); w->should_workgroup_member = True; - /* default action: allow any new workgroup to be added */ + /* default action: allow any new workgroup to be added. this is + _not_ the same as the old 1.9.14-1.9.15 definition of "*" + */ w = new_workgroup((struct smbbrowse *)NULL, "*", default_name); - w->should_local_master = False; - w->should_domain_master = False; + w->should_local_master = False; + w->should_domain_master = False; w->should_workgroup_member = False; + w->should_domain_logon = False; } /* @@ -332,8 +360,10 @@ void read_smbbrowse_conf(char *default_name) if (count <= 0) continue; w = new_workgroup((struct smbbrowse *)NULL, work_name, default_name); - w->should_local_master = lp_local_master(); - w->should_domain_master = lp_domain_master(); + w->should_local_master = lp_local_master(); + w->should_domain_master = lp_domain_master(); + w->should_preferred_master = lp_preferred_master(); + w->should_domain_logon = lp_domain_logons(); w->should_workgroup_member = True; } diff --git a/source/namedbname.c b/source/namedbname.c index 1f16553b0f4..f084424a294 100644 --- a/source/namedbname.c +++ b/source/namedbname.c @@ -27,6 +27,10 @@ 04 jul 96: lkcl@pires.co.uk created module namedbname containing name database functions + + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. + */ #include "includes.h" @@ -43,6 +47,16 @@ extern struct subnet_record *subnetlist; uint16 nb_type = 0; /* samba's NetBIOS name type */ +static char *source_description[] = +{ + "STATUS_QUERY", + "LMHOSTS", + "REG", + "SELF", + "DNS", + "DNSFAIL" +}; + /**************************************************************************** samba's NetBIOS name type @@ -52,14 +66,14 @@ uint16 nb_type = 0; /* samba's NetBIOS name type */ ****************************************************************************/ void set_samba_nb_type(void) { - if (lp_wins_support() || (*lp_wins_server())) - { - nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */ - } - else - { - nb_type = NB_BFLAG; /* samba is broadcast-only node type */ - } + if (lp_wins_support() || (*lp_wins_server())) + { + nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */ + } + else + { + nb_type = NB_BFLAG; /* samba is broadcast-only node type */ + } } @@ -69,7 +83,7 @@ void set_samba_nb_type(void) BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2) { return n1->name_type == n2->name_type && - strequal(n1->name ,n2->name ) && + strequal(n1->name ,n2->name ) && strequal(n1->scope,n2->scope); } @@ -140,22 +154,22 @@ void remove_name(struct subnet_record *d, struct name_record *n) find a name in a namelist. **************************************************************************/ struct name_record *find_name(struct name_record *n, - struct nmb_name *name, - int search) + struct nmb_name *name, + int search) { - struct name_record *ret; + struct name_record *ret; - for (ret = n; ret; ret = ret->next) - { - if (name_equal(&ret->name,name)) - { - /* self search: self names only */ - if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF) - continue; - - return ret; - } - } + for (ret = n; ret; ret = ret->next) + { + if (name_equal(&ret->name,name)) + { + /* self search: self names only */ + if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF) + continue; + + return ret; + } + } return NULL; } @@ -168,29 +182,31 @@ struct name_record *find_name(struct name_record *n, FIND_WINS - look for names in the WINS record **************************************************************************/ struct name_record *find_name_search(struct subnet_record **d, - struct nmb_name *name, - int search, struct in_addr ip) + struct nmb_name *name, + int search, struct in_addr ip) { - if (d == NULL) return NULL; /* bad error! */ - - if (search & FIND_LOCAL) { - if (*d != NULL) { - struct name_record *n = find_name((*d)->namelist, name, search); - DEBUG(4,("find_name on local: %s %s search %x\n", - namestr(name),inet_ntoa(ip), search)); - if (n) return n; - } + if (d == NULL) return NULL; /* bad error! */ + + if (search & FIND_LOCAL) + { + if (*d != NULL) + { + struct name_record *n = find_name((*d)->namelist, name, search); + DEBUG(4,("find_name on local: %s %s search %x\n", + namestr(name),inet_ntoa(ip), search)); + if (n) return n; + } } - if (!(search & FIND_WINS)) return NULL; + if ((search & FIND_WINS) != FIND_WINS) return NULL; /* find WINS subnet record. */ *d = find_subnet(ipgrp); - + if (*d == NULL) return NULL; - + DEBUG(4,("find_name on WINS: %s %s search %x\n", - namestr(name),inet_ntoa(ip), search)); + namestr(name),inet_ntoa(ip), search)); return find_name((*d)->namelist, name, search); } @@ -228,20 +244,18 @@ void dump_names(void) { int i; - DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip))); - DEBUG(3,("%15s ", inet_ntoa(d->mask_ip))); - DEBUG(3,("%-19s TTL=%ld ", - namestr(&n->name), - n->death_time?n->death_time-t:0)); + DEBUG(3,("%-15s ", inet_ntoa(d->bcast_ip))); + DEBUG(3,("%-19s TTL=%7ld %s ", + namestr(&n->name), + n->death_time?n->death_time-t:0, source_description[n->source])); for (i = 0; i < n->num_ips; i++) { - DEBUG(3,("%15s NB=%2x source=%d", - inet_ntoa(n->ip_flgs[i].ip), - n->ip_flgs[i].nb_flags,n->source)); - + DEBUG(3,("%-15s NB=%2x ", + inet_ntoa(n->ip_flgs[i].ip), + (unsigned char)n->ip_flgs[i].nb_flags)); } - DEBUG(3,("\n")); + DEBUG(3,("\n")); if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER) { @@ -249,16 +263,16 @@ void dump_names(void) anything other than as a hexadecimal number :-) */ fprintf(f, "%s#%02x %ld ", - n->name.name,n->name.name_type, /* XXXX ignore scope for now */ - n->death_time); + n->name.name,n->name.name_type, /* XXXX ignore scope for now */ + n->death_time); for (i = 0; i < n->num_ips; i++) { fprintf(f, "%s %2x ", - inet_ntoa(n->ip_flgs[i].ip), - n->ip_flgs[i].nb_flags); + inet_ntoa(n->ip_flgs[i].ip), + (unsigned char)n->ip_flgs[i].nb_flags); } - fprintf(f, "\n"); + fprintf(f, "\n"); } } @@ -307,12 +321,12 @@ void load_netbios_names(void) int type = 0; unsigned int nb_flags; time_t ttd; - struct in_addr ipaddr; + struct in_addr ipaddr; - enum name_source source; + enum name_source source; char *ptr; - int count = 0; + int count = 0; char *p; @@ -320,20 +334,20 @@ void load_netbios_names(void) if (*line == '#') continue; - ptr = line; + ptr = line; - if (next_token(&ptr,name_str ,NULL)) ++count; - if (next_token(&ptr,ttd_str ,NULL)) ++count; - if (next_token(&ptr,ip_str ,NULL)) ++count; - if (next_token(&ptr,nb_flags_str,NULL)) ++count; + if (next_token(&ptr,name_str ,NULL)) ++count; + if (next_token(&ptr,ttd_str ,NULL)) ++count; + if (next_token(&ptr,ip_str ,NULL)) ++count; + if (next_token(&ptr,nb_flags_str,NULL)) ++count; - if (count <= 0) continue; + if (count <= 0) continue; - if (count != 4) { - DEBUG(0,("Ill formed wins line")); - DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line)); - continue; - } + if (count != 4) { + DEBUG(0,("Ill formed wins line")); + DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line)); + continue; + } /* netbios name. # divides the name from the type (hex): netbios#xx */ strcpy(name,name_str); @@ -341,15 +355,15 @@ void load_netbios_names(void) p = strchr(name,'#'); if (p) { - *p = 0; - sscanf(p+1,"%x",&type); + *p = 0; + sscanf(p+1,"%x",&type); } /* decode the netbios flags (hex) and the time-to-die (seconds) */ - sscanf(nb_flags_str,"%x",&nb_flags); - sscanf(ttd_str,"%ld",&ttd); + sscanf(nb_flags_str,"%x",&nb_flags); + sscanf(ttd_str,"%ld",&ttd); - ipaddr = *interpret_addr2(ip_str); + ipaddr = *interpret_addr2(ip_str); if (ip_equal(ipaddr,ipzero)) { source = SELF; @@ -360,7 +374,7 @@ void load_netbios_names(void) } DEBUG(4, ("add WINS line: %s#%02x %ld %s %2x\n", - name,type, ttd, inet_ntoa(ipaddr), nb_flags)); + name,type, ttd, inet_ntoa(ipaddr), nb_flags)); /* add all entries that have 60 seconds or more to live */ if (ttd - 60 > time(NULL) || ttd == 0) @@ -380,8 +394,8 @@ void load_netbios_names(void) remove an entry from the name list ****************************************************************************/ void remove_netbios_name(struct subnet_record *d, - char *name,int type, enum name_source source, - struct in_addr ip) + char *name,int type, enum name_source source, + struct in_addr ip) { struct nmb_name nn; struct name_record *n; @@ -405,14 +419,22 @@ void remove_netbios_name(struct subnet_record *d, ****************************************************************************/ struct name_record *add_netbios_entry(struct subnet_record *d, - char *name, int type, int nb_flags, - int ttl, enum name_source source, struct in_addr ip, - BOOL new_only,BOOL wins) + char *name, int type, int nb_flags, + int ttl, enum name_source source, struct in_addr ip, + BOOL new_only,BOOL wins) { struct name_record *n; struct name_record *n2=NULL; int search = 0; - BOOL self = source == SELF; + BOOL self; + + if (iface_ip(ip)) + { + source = SELF; + putip(&ip, &ipzero); + } + + self = source == SELF; /* add the name to the WINS list if the name comes from a directed query */ search |= wins ? FIND_WINS : FIND_LOCAL; @@ -465,46 +487,57 @@ struct name_record *add_netbios_entry(struct subnet_record *d, if (!n2) add_name(d,n); DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n", - namestr(&n->name),inet_ntoa(ip),ttl,nb_flags)); + namestr(&n->name),inet_ntoa(ip),ttl,nb_flags)); return(n); } /******************************************************************* - expires old names in the namelist + expires or refreshes old names in the namelist + + if the name is a samba SELF name, it must be refreshed rather than + removed. ******************************************************************/ -void expire_names(time_t t) +void check_expire_names(time_t t) { - struct name_record *n; - struct name_record *next; - struct subnet_record *d; - - /* expire old names */ - for (d = subnetlist; d; d = d->next) - { - for (n = d->namelist; n; n = next) - { - next = n->next; - if (n->death_time && n->death_time < t) - { - if (n->source == SELF) { - DEBUG(3,("not expiring SELF name %s\n", namestr(&n->name))); - n->death_time += 300; - continue; - } - DEBUG(3,("Removing dead name %s\n", namestr(&n->name))); - - if (n->prev) n->prev->next = n->next; - if (n->next) n->next->prev = n->prev; - - if (d->namelist == n) d->namelist = n->next; - - free(n->ip_flgs); - free(n); - } - } - } + struct name_record *n; + struct name_record *next; + struct subnet_record *d; + + /* expire old names */ + for (d = subnetlist; d; d = d->next) + { + for (n = d->namelist; n; n = next) + { + next = n->next; + + if (n->death_time && n->death_time < t) + { + if (n->source == SELF) + { + /* refresh the samba name. if this refresh fails + for any reason, it will be deleted. + */ + DEBUG(3,("Refreshing SELF name %s\n", namestr(&n->name))); + add_my_name_entry(d, -1, + n->name.name, n->name.name_type, + n->ip_flgs[0].nb_flags); + continue; + } + + DEBUG(3,("Removing dead name %s\n", namestr(&n->name))); + + if (n->prev) n->prev->next = n->next; + if (n->next) n->next->prev = n->prev; + + if (d->namelist == n) d->namelist = n->next; + + free(n->ip_flgs); + free(n); + } + } + } } @@ -512,8 +545,8 @@ void expire_names(time_t t) reply to a name query ****************************************************************************/ struct name_record *search_for_name(struct subnet_record **d, - struct nmb_name *question, - struct in_addr ip, int Time, int search) + struct nmb_name *question, + struct in_addr ip, int Time, int search) { int name_type = question->name_type; char *qname = question->name; @@ -538,10 +571,10 @@ struct name_record *search_for_name(struct subnet_record **d, /* only do DNS lookups if the query is for type 0x20 or type 0x0 */ if (!dns_type && name_type != 0x1b) - { - DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n")); - return NULL; - } + { + DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n")); + return NULL; + } /* look it up with DNS */ a = interpret_addr(qname); @@ -549,18 +582,18 @@ struct name_record *search_for_name(struct subnet_record **d, putip((char *)&dns_ip,(char *)&a); if (!a) - { - /* no luck with DNS. We could possibly recurse here XXXX */ - DEBUG(3,("no recursion.\n")); + { + /* no luck with DNS. We could possibly recurse here XXXX */ + DEBUG(3,("no recursion.\n")); /* add the fail to our WINS cache of names. give it 1 hour in the cache */ - add_netbios_entry(*d,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip, - True, True); - return NULL; - } + add_netbios_entry(*d,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip, + True, True); + return NULL; + } /* add it to our WINS cache of names. give it 2 hours in the cache */ n = add_netbios_entry(*d,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip, - True,True); + True,True); /* failed to add it? yikes! */ if (!n) return NULL; diff --git a/source/namedbresp.c b/source/namedbresp.c index d89bfe8ae84..aad6188384f 100644 --- a/source/namedbresp.c +++ b/source/namedbresp.c @@ -92,8 +92,9 @@ void remove_response_record(struct subnet_record *d, create a name query response record **************************************************************************/ struct response_record *make_response_queue_record(enum state_type state, - int id,uint16 fd, - int quest_type, char *name,int type, int nb_flags, time_t ttl, + int id,uint16 fd, int quest_type, + int token, char *name,int type, + enum name_source source, int nb_flags, time_t ttl, int server_type, char *my_name, char *my_comment, BOOL bcast,BOOL recurse, struct in_addr send_ip, struct in_addr reply_to_ip) @@ -109,14 +110,17 @@ struct response_record *make_response_queue_record(enum state_type state, n->state = state; n->fd = fd; n->quest_type = quest_type; + + n->token = token; make_nmb_name(&n->name, name, type, scope); - n->nb_flags = nb_flags; n->ttl = ttl; + n->source = source; n->server_type = server_type; n->bcast = bcast; n->recurse = recurse; + n->reply.nb_flags = nb_flags; + n->reply.ip = reply_to_ip; n->send_ip = send_ip; - n->reply_to_ip = reply_to_ip; StrnCpy(my_name , n->my_name , sizeof(n->my_name )-1); StrnCpy(my_comment, n->my_comment, sizeof(n->my_comment)-1); diff --git a/source/namedbserver.c b/source/namedbserver.c index afb1dc14315..260f8f3475e 100644 --- a/source/namedbserver.c +++ b/source/namedbserver.c @@ -50,7 +50,7 @@ extern BOOL updatedlists; remove_all_servers indicates everybody dies. ******************************************************************/ void remove_old_servers(struct work_record *work, time_t t, - BOOL remove_all) + BOOL remove_all) { struct server_record *s; struct server_record *nexts; @@ -59,23 +59,23 @@ void remove_old_servers(struct work_record *work, time_t t, for (s = work->serverlist; s; s = nexts) { if (remove_all || (s->death_time && (t == -1 || s->death_time < t))) - { - DEBUG(3,("Removing dead server %s\n",s->serv.name)); - updatedlists = True; - nexts = s->next; - - if (s->prev) s->prev->next = s->next; - if (s->next) s->next->prev = s->prev; - - if (work->serverlist == s) - work->serverlist = s->next; - - free(s); - } + { + DEBUG(3,("Removing dead server %s\n",s->serv.name)); + updatedlists = True; + nexts = s->next; + + if (s->prev) s->prev->next = s->next; + if (s->next) s->next->prev = s->prev; + + if (work->serverlist == s) + work->serverlist = s->next; + + free(s); + } else - { - nexts = s->next; - } + { + nexts = s->next; + } } } @@ -107,17 +107,17 @@ static void add_server(struct work_record *work,struct server_record *s) **************************************************************************/ struct server_record *find_server(struct work_record *work, char *name) { - struct server_record *ret; + struct server_record *ret; - if (!work) return NULL; - - for (ret = work->serverlist; ret; ret = ret->next) - { - if (strequal(ret->serv.name,name)) - { - return ret; - } - } + if (!work) return NULL; + + for (ret = work->serverlist; ret; ret = ret->next) + { + if (strequal(ret->serv.name,name)) + { + return ret; + } + } return NULL; } @@ -126,14 +126,15 @@ struct server_record *find_server(struct work_record *work, char *name) add a server entry ****************************************************************************/ struct server_record *add_server_entry(struct subnet_record *d, - struct work_record *work, - char *name,int servertype, - int ttl,char *comment, - BOOL replace) + struct work_record *work, + char *name,int servertype, + int ttl,char *comment, + BOOL replace) { BOOL newentry=False; struct server_record *s; - + int token = conf_workgroup_name_to_token(work->work_group, myname); + if (name[0] == '*') { return (NULL); @@ -160,16 +161,14 @@ struct server_record *add_server_entry(struct subnet_record *d, bzero((char *)s,sizeof(*s)); } - - if (strequal(lp_workgroup(),work->work_group)) - { - if (servertype) - servertype |= SV_TYPE_LOCAL_LIST_ONLY; - } + if (conf_should_workgroup_member(token)) + { + if (servertype) servertype |= SV_TYPE_LOCAL_LIST_ONLY; + } else - { + { servertype &= ~SV_TYPE_LOCAL_LIST_ONLY; - } + } /* update the entry */ StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1); @@ -194,8 +193,8 @@ struct server_record *add_server_entry(struct subnet_record *d, } DEBUG(3,("server entry %s of type %x (%s) to %s %s\n", - name,servertype,comment, - work->work_group,inet_ntoa(d->bcast_ip))); + name,servertype,comment, + work->work_group,inet_ntoa(d->bcast_ip))); return(s); } @@ -213,9 +212,9 @@ void expire_servers(time_t t) struct work_record *work; for (work = d->workgrouplist; work; work = work->next) - { - remove_old_servers(work, t, False); - } + { + remove_old_servers(work, t, False); + } } } diff --git a/source/namedbsubnet.c b/source/namedbsubnet.c index 0bad79246ad..9c7fb1e8dc8 100644 --- a/source/namedbsubnet.c +++ b/source/namedbsubnet.c @@ -26,6 +26,9 @@ 04 jul 96: lkcl@pires.co.uk created module namedbsubnet containing subnet database functions + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. + */ #include "includes.h" @@ -90,16 +93,16 @@ struct subnet_record *find_subnet(struct in_addr bcast_ip) for (d = subnetlist; d; d = d->next) { if (ip_equal(bcast_ip, wins_ip)) - { + { if (ip_equal(bcast_ip, d->bcast_ip)) { return d; } } else if (same_net(bcast_ip, d->bcast_ip, d->mask_ip)) - { - return(d); - } + { + return(d); + } } return (NULL); @@ -154,47 +157,60 @@ static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr ****************************************************************************/ void add_subnet_interfaces(void) { - struct interface *i; - - /* loop on all local interfaces */ - for (i = local_interfaces; i; i = i->next) - { - /* add the interface into our subnet database */ - if (!find_subnet(i->bcast)) - { - make_subnet(i->bcast,i->nmask); - } - } - - /* add the pseudo-ip interface for WINS: 255.255.255.255 */ - if (lp_wins_support() || (*lp_wins_server())) + struct interface *i; + + /* loop on all local interfaces */ + for (i = local_interfaces; i; i = i->next) + { + /* add the interface into our subnet database */ + if (!find_subnet(i->bcast)) + { + make_subnet(i->bcast,i->nmask); + } + } + + /* add the pseudo-ip interface for WINS: 255.255.255.255 */ + if (lp_wins_support() || (*lp_wins_server())) { - struct in_addr wins_bcast = ipgrp; - struct in_addr wins_nmask = ipzero; - make_subnet(wins_bcast, wins_nmask); + struct in_addr wins_bcast = ipgrp; + struct in_addr wins_nmask = ipzero; + make_subnet(wins_bcast, wins_nmask); } } +/**************************************************************************** + add the default workgroups into my domain + **************************************************************************/ +void add_workgroup_to_subnet(char *group, struct in_addr bcast_ip, + struct in_addr mask_ip) +{ + if (group && *group != '*') + { + DEBUG(4,("add_wg_to_subnet: %s %s\n", group, inet_ntoa(bcast_ip))); + add_subnet_entry(bcast_ip,mask_ip,group, True, False); + } +} + + /**************************************************************************** add the default workgroup into my domain **************************************************************************/ -void add_my_subnets(char *group) +void add_workgroups_to_subnets() { struct interface *i; /* add or find domain on our local subnet, in the default workgroup */ - - if (*group == '*') return; - /* the coding choice is up to you, andrew: i can see why you don't want - global access to the local_interfaces structure: so it can't get - messed up! */ - for (i = local_interfaces; i; i = i->next) + for (i = local_interfaces; i; i = i->next) + { + int token; + for (token = 0; token < get_num_workgroups(); token++) { - add_subnet_entry(i->bcast,i->nmask,group, True, False); + add_workgroup_to_subnet(conf_workgroup_name(token),i->bcast,i->nmask); } + } } @@ -203,48 +219,49 @@ void add_my_subnets(char *group) to the named a workgroup. ****************************************************************************/ struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, - struct in_addr mask_ip, - char *name, BOOL add, BOOL lmhosts) + struct in_addr mask_ip, + char *name, BOOL add, BOOL lmhosts) { struct subnet_record *d; - /* XXXX andrew: struct in_addr ip appears not to be referenced at all except - in the DEBUG comment. i assume that the DEBUG comment below actually - intends to refer to bcast_ip? i don't know. + DEBUG(4,("add_subnet_entry: %s %\n", name,inet_ntoa(bcast_ip))); - struct in_addr ip = ipgrp; - - */ - - if (zero_ip(bcast_ip)) - bcast_ip = *iface_bcast(bcast_ip); + if (zero_ip(bcast_ip)) bcast_ip = *iface_bcast(bcast_ip); /* add the domain into our domain database */ - if ((d = find_subnet(bcast_ip)) || - (d = make_subnet(bcast_ip, mask_ip))) - { - struct work_record *w = find_workgroupstruct(d, name, add); + if ((d = find_subnet(bcast_ip)) || (d = make_subnet(bcast_ip, mask_ip))) + { + struct work_record *work = find_workgroupstruct(d, name, add); - if (!w) return NULL; - - /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database - or register with WINS server, if it's our workgroup */ - if (strequal(lp_workgroup(), name)) - { - add_my_name_entry(d,name,0x1e,nb_type|NB_ACTIVE|NB_GROUP); - add_my_name_entry(d,name,0x0 ,nb_type|NB_ACTIVE|NB_GROUP); - } - /* add samba server name to workgroup list. don't add - lmhosts server entries to local interfaces */ - if (strequal(lp_workgroup(), name)) - { - add_server_entry(d,w,myname,w->ServerType,0,lp_serverstring(),True); + if (!work) return NULL; + + if (conf_should_workgroup_member(work->token)) + { + /* add samba server name to workgroup list. don't add + lmhosts server entries to local interfaces */ + + pstring comment; + char *my_name = conf_browsing_alias (work->token); + char *my_comment = conf_browsing_alias_comment(work->token); + + StrnCpy(comment, my_comment, 43); + + add_server_entry(d,work,my_name, + work->ServerType | SV_TYPE_LOCAL_LIST_ONLY, + 0,comment,True); + DEBUG(3,("Added server name entry %s at %s\n", name,inet_ntoa(bcast_ip))); - } - - return d; + + /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database + or register with WINS server, if it's our workgroup */ + add_my_name_entry(d,work->token,name,0x1e,nb_type|NB_ACTIVE|NB_GROUP); + add_my_name_entry(d,work->token,name,0x0 ,nb_type|NB_ACTIVE|NB_GROUP); } + + return d; + } + return NULL; } @@ -290,31 +307,31 @@ void write_browse_list(void) { struct work_record *work; for (work = d->workgrouplist; work ; work = work->next) - { - struct server_record *s; - for (s = work->serverlist; s ; s = s->next) - { - fstring tmp; - - /* don't list domains I don't have a master for */ - if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0]) - { - continue; - } - - /* output server details, plus what workgroup/domain - they're in. without the domain information, the - combined list of all servers in all workgroups gets - sent to anyone asking about any workgroup! */ - - sprintf(tmp, "\"%s\"", s->serv.name); - fprintf(f, "%-25s ", tmp); - fprintf(f, "%08x ", s->serv.type); - sprintf(tmp, "\"%s\" ", s->serv.comment); - fprintf(f, "%-30s", tmp); - fprintf(f, "\"%s\"\n", work->work_group); - } - } + { + struct server_record *s; + for (s = work->serverlist; s ; s = s->next) + { + fstring tmp; + + /* don't list domains I don't have a master for */ + if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0]) + { + continue; + } + + /* output server details, plus what workgroup/domain + they're in. without the domain information, the + combined list of all servers in all workgroups gets + sent to anyone asking about any workgroup! */ + + sprintf(tmp, "\"%s\"", s->serv.name); + fprintf(f, "%-25s ", tmp); + fprintf(f, "%08x ", s->serv.type); + sprintf(tmp, "\"%s\" ", s->serv.comment); + fprintf(f, "%-30s", tmp); + fprintf(f, "\"%s\"\n", work->work_group); + } + } } fclose(f); diff --git a/source/namedbwork.c b/source/namedbwork.c index 04f2103254b..dd4bd881754 100644 --- a/source/namedbwork.c +++ b/source/namedbwork.c @@ -26,6 +26,9 @@ 04 jul 96: lkcl@pires.co.uk created module namedbwork containing workgroup database functions + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. + */ #include "includes.h" @@ -40,9 +43,7 @@ extern struct subnet_record *subnetlist; extern struct in_addr ipgrp; -int workgroup_count = 0; /* unique index key: one for each workgroup */ - - +extern pstring myname; /**************************************************************************** add a workgroup into the domain list @@ -75,11 +76,17 @@ static void add_workgroup(struct work_record *work, struct subnet_record *d) static struct work_record *make_workgroup(char *name) { struct work_record *work; - struct subnet_record *d; int t = -1; if (!name || !name[0]) return NULL; + /* conf_workgroup_name_to_token() gets or creates a unique index for the workgroup name */ + if ((t = conf_workgroup_name_to_token(name, myname)) == -1) + { + DEBUG(3, ("work_record(\"%s\"): conf_workgroup_name_to_token() refuses to allow workgroup\n", name)); + return (struct work_record *)NULL; + } + work = (struct work_record *)malloc(sizeof(*work)); if (!work) return(NULL); @@ -92,34 +99,16 @@ static struct work_record *make_workgroup(char *name) work->needelection = False; work->needannounce = True; work->state = MST_NONE; - - /* make sure all token representations of workgroups are unique */ - - for (d = subnetlist; d && t == -1; d = d->next) - { - struct work_record *w; - for (w = d->workgrouplist; w && t == -1; w = w->next) - { - if (strequal(w->work_group, work->work_group)) t = w->token; - } - } - - if (t == -1) - { - work->token = ++workgroup_count; - } - else - { - work->token = t; - } - + work->token = t; /* WfWg uses 01040b01 */ /* Win95 uses 01041501 */ /* NTAS uses ???????? */ work->ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8); work->ElectionCriterion |= (lp_os_level() << 24); - if (lp_domain_master()) { + + if (conf_should_domain_master(work->token)) + { work->ElectionCriterion |= 0x80; } @@ -131,8 +120,8 @@ static struct work_record *make_workgroup(char *name) remove workgroups ******************************************************************/ struct work_record *remove_workgroup(struct subnet_record *d, - struct work_record *work, - BOOL remove_all_servers) + struct work_record *work, + BOOL remove_all_servers) { struct work_record *ret_work = NULL; @@ -165,7 +154,7 @@ struct work_record *remove_workgroup(struct subnet_record *d, lmhosts file to be added. **************************************************************************/ struct work_record *find_workgroupstruct(struct subnet_record *d, - fstring name, BOOL add) + fstring name, BOOL add) { struct work_record *ret, *work; @@ -174,39 +163,51 @@ struct work_record *find_workgroupstruct(struct subnet_record *d, DEBUG(4, ("workgroup search for %s: ", name)); if (strequal(name, "*")) - { + { +#if 0 /* XXXX this is being called too many times */ + DEBUG(2,("add any workgroups: initiating browser search on %s\n", - inet_ntoa(d->bcast_ip))); + inet_ntoa(d->bcast_ip))); queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, NAME_QUERY_FIND_MST, - MSBROWSE,0x1,0,0,0,NULL,NULL, - True,False, d->bcast_ip, d->bcast_ip); + -1,MSBROWSE,0x1,0,0,0,0,NULL,NULL, + True,False, d->bcast_ip, d->bcast_ip); + +#endif return NULL; - } + } - for (ret = d->workgrouplist; ret; ret = ret->next) { - if (!strcmp(ret->work_group,name)) { + for (ret = d->workgrouplist; ret; ret = ret->next) + { + if (!strcmp(ret->work_group,name)) + { DEBUG(4, ("found\n")); return(ret); } } - if (!add) { + if (!add) + { DEBUG(4, ("not found\n")); return NULL; } DEBUG(4,("not found: creating\n")); - if ((work = make_workgroup(name))) + if ((work = make_workgroup(name)) != NULL) + { + DEBUG(4,("bcast_ip:%s preferred master=%s local_master=%s\n", + inet_ntoa(d->bcast_ip), + BOOLSTR(conf_should_preferred_master(work->token)), + BOOLSTR(conf_should_local_master(work->token)) )); + + if (!ip_equal(d->bcast_ip, ipgrp) && + conf_should_preferred_master(work->token) && + conf_should_local_master (work->token)) { - if (!ip_equal(d->bcast_ip, ipgrp) && - lp_preferred_master() && - strequal(lp_workgroup(), name)) - { - DEBUG(3, ("preferred master startup for %s\n", work->work_group)); - work->needelection = True; - work->ElectionCriterion |= (1<<3); - } + DEBUG(3, ("preferred master startup for %s\n", work->work_group)); + work->needelection = True; + work->ElectionCriterion |= (1<<3); + } add_workgroup(work, d); return(work); } @@ -224,25 +225,25 @@ void dump_workgroups(void) for (d = subnetlist; d; d = d->next) { if (d->workgrouplist) - { - struct work_record *work; - - DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip))); - DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip))); - - for (work = d->workgrouplist; work; work = work->next) - { - DEBUG(4,("\t%s(%d)\n", work->work_group, work->token)); - if (work->serverlist) - { - struct server_record *s; - for (s = work->serverlist; s; s = s->next) - { - DEBUG(4,("\t\t%s %8x (%s)\n", - s->serv.name, s->serv.type, s->serv.comment)); - } - } - } - } + { + struct work_record *work; + + DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip))); + DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip))); + + for (work = d->workgrouplist; work; work = work->next) + { + DEBUG(4,("\t%s(%d)\n", work->work_group, work->token)); + if (work->serverlist) + { + struct server_record *s; + for (s = work->serverlist; s; s = s->next) + { + DEBUG(4,("\t\t%s %8x (%s)\n", + s->serv.name, s->serv.type, s->serv.comment)); + } + } + } + } } } diff --git a/source/nameelect.c b/source/nameelect.c index 07429013e0d..6c8a4751f43 100644 --- a/source/nameelect.c +++ b/source/nameelect.c @@ -28,10 +28,12 @@ 04 jul 96: lkcl@pires.co.uk added system to become a master browser by stages. + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. */ -#include "includes.h" +#include "includes.h" extern int ClientNMB; extern int ClientDGRAM; @@ -39,7 +41,6 @@ extern int ClientDGRAM; extern int DEBUGLEVEL; extern pstring scope; -extern pstring myname; extern struct in_addr ipzero; extern struct in_addr ipgrp; @@ -51,6 +52,9 @@ extern struct subnet_record *subnetlist; extern uint16 nb_type; /* samba's NetBIOS name type */ +extern pstring myname; + + /******************************************************************* occasionally check to see if the master browser is around ******************************************************************/ @@ -68,22 +72,22 @@ void check_master_browser(void) dump_workgroups(); for (d = subnetlist; d; d = d->next) + { + struct work_record *work; + + for (work = d->workgrouplist; work; work = work->next) { - struct work_record *work; + /* if we are not the browse master of a workgroup, and we can't + find a browser on the subnet, do something about it. */ - for (work = d->workgrouplist; work; work = work->next) - { - /* if we are not the browse master of a workgroup, and we can't - find a browser on the subnet, do something about it. */ - - if (!AM_MASTER(work)) - { - queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK, - work->work_group,0x1d,0,0,0,NULL,NULL, - True,False,d->bcast_ip,d->bcast_ip); - } - } + if (!AM_MASTER(work)) + { + queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK, + work->token, work->work_group,0x1d,REGISTER,0,0,0,NULL,NULL, + True,False,d->bcast_ip,d->bcast_ip); + } } + } } @@ -102,11 +106,10 @@ void browser_gone(char *work_name, struct in_addr ip) if (ip_equal(d->bcast_ip,ipgrp)) return; - if (strequal(work->work_group, lp_workgroup())) + if (conf_should_local_master(work->token)) { - DEBUG(2,("Forcing election on %s %s\n", - work->work_group,inet_ntoa(d->bcast_ip))); + work->work_group,inet_ntoa(d->bcast_ip))); /* we can attempt to become master browser */ work->needelection = True; @@ -114,10 +117,10 @@ void browser_gone(char *work_name, struct in_addr ip) else { /* local interfaces: force an election */ - send_election(d, work->work_group, 0, 0, myname); + send_election(d, work->work_group, 0, 0, conf_browsing_alias(work->token)); /* only removes workgroup completely on a local interface - persistent lmhosts entries on a local interface _will_ be removed). + persistent lmhosts entries on a local interface _will_ be removed. */ remove_workgroup(d, work,True); } @@ -128,7 +131,7 @@ void browser_gone(char *work_name, struct in_addr ip) send an election packet **************************************************************************/ void send_election(struct subnet_record *d, char *group,uint32 criterion, - int timeup,char *name) + int timeup,char *name) { pstring outbuf; char *p; @@ -136,7 +139,7 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion, if (!d) return; DEBUG(2,("Sending election to %s for workgroup %s\n", - inet_ntoa(d->bcast_ip),group)); + inet_ntoa(d->bcast_ip),group)); bzero(outbuf,sizeof(outbuf)); p = outbuf; @@ -152,7 +155,7 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion, p = skip_string(p,1); send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip)); + name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip)); } @@ -172,8 +175,10 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type) if (!(work = find_workgroupstruct(d, name, False))) return; + if (!AM_MASTER(work) && !AM_DMBRSE(work)) return; + if (ms_browser_name(name, name_type) || - (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 && + (conf_should_workgroup_member(work->token) && (name_type == 0x1d || name_type == 0x1b))) { int remove_type = 0; @@ -184,7 +189,7 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type) remove_type = SV_TYPE_MASTER_BROWSER; if (name_type == 0x1b) remove_type = SV_TYPE_DOMAIN_MASTER; - + become_nonmaster(d, work, remove_type); } } @@ -197,17 +202,17 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type) whether to proceed to the next stage in samba becoming a master browser. **************************************************************************/ -void name_register_work(struct subnet_record *d, char *name, int name_type, - int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast) +void name_register_work(struct subnet_record *d, int token, + char *name, int name_type, enum name_source source, + struct nmb_ip *data, time_t ttl, struct in_addr ip, BOOL bcast) { - enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ? - SELF : REGISTER; - if (source == SELF) { - struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False); + char *work_name = conf_workgroup_name(token); + struct work_record *work = find_workgroupstruct(d, work_name, False); - add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast); + add_netbios_entry(d,name,name_type,data->nb_flags, + ttl,source,data->ip,True,!bcast); if (work) { @@ -249,13 +254,35 @@ void name_register_work(struct subnet_record *d, char *name, int name_type, ******************************************************************/ void become_master(struct subnet_record *d, struct work_record *work) { - uint32 domain_type = SV_TYPE_DOMAIN_ENUM|DFLT_SERVER_TYPE| - SV_TYPE_POTENTIAL_BROWSER; + pstring comment; + + /* domain type must be limited to domain enum + server type. it must + not have SV_TYPE_SERVER or anything else with SERVER in it, else + clients get confused and start thinking this entry is a server + not a workgroup + */ + uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT; + + char *my_name ; + char *my_comment; if (!work) return; + my_name = conf_browsing_alias(work->token); + my_comment = conf_browsing_alias_comment(work->token); + + StrnCpy(comment, my_comment, 43); + + if (!conf_should_local_master(work->token)) + { + DEBUG(1,("Should not become master for %s %s\n", + work->work_group,inet_ntoa(d->bcast_ip))); + work->state = MST_NONE; + return; + } + DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n", - work->work_group,inet_ntoa(d->bcast_ip),work->state)); + work->work_group,inet_ntoa(d->bcast_ip),work->state)); switch (work->state) { @@ -268,10 +295,10 @@ void become_master(struct subnet_record *d, struct work_record *work) /* update our server status */ work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); + add_server_entry(d,work,my_name,work->ServerType,0,comment,True); /* add special browser name */ - add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP); + add_my_name_entry(d,work->token,MSBROWSE,0x01,nb_type|NB_ACTIVE|NB_GROUP); /* DON'T do anything else after calling add_my_name_entry() */ return; @@ -282,10 +309,11 @@ void become_master(struct subnet_record *d, struct work_record *work) work->state = MST_MSB; /* ... registering MSBROWSE was successful */ /* add server entry on successful registration of MSBROWSE */ - add_server_entry(d,work,work->work_group,domain_type,0,myname,True); + add_server_entry(d,work,work->work_group, + domain_type,0,conf_browsing_alias(work->token),True); /* add master name */ - add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE); + add_my_name_entry(d,work->token,work->work_group,0x1d,nb_type|NB_ACTIVE); /* DON'T do anything else after calling add_my_name_entry() */ return; @@ -297,7 +325,8 @@ void become_master(struct subnet_record *d, struct work_record *work) /* update our server status */ work->ServerType |= SV_TYPE_MASTER_BROWSER; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); + add_server_entry(d,work,conf_browsing_alias(work->token), + work->ServerType,0,comment,True); if (work->serverlist == NULL) /* no servers! */ { @@ -317,13 +346,14 @@ void become_master(struct subnet_record *d, struct work_record *work) case MST_DOMAIN_NONE: { - if (lp_domain_master()) + if (conf_should_domain_master(work->token)) { work->state = MST_DOMAIN_MEM; /* ... become domain member */ DEBUG(3,("domain first stage: register as domain member\n")); /* add domain member name */ - add_my_name_entry(d,work->work_group,0x1e,nb_type|NB_ACTIVE|NB_GROUP); + add_my_name_entry(d,work->token,work->work_group,0x1e, + nb_type|NB_ACTIVE|NB_GROUP); /* DON'T do anything else after calling add_my_name_entry() */ return; @@ -338,19 +368,20 @@ void become_master(struct subnet_record *d, struct work_record *work) case MST_DOMAIN_MEM: { - if (lp_domain_master()) + if (conf_should_domain_master(work->token)) { work->state = MST_DOMAIN_TST; /* ... possibly become domain master */ DEBUG(3,("domain second stage: register as domain master\n")); - if (lp_domain_logons()) - { + if (conf_should_domain_logon(work->token)) + { work->ServerType |= SV_TYPE_DOMAIN_MEMBER; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); + add_server_entry(d,work,my_name,work->ServerType,0,comment,True); } /* add domain master name */ - add_my_name_entry(d,work->work_group,0x1b,nb_type|NB_ACTIVE ); + add_my_name_entry(d,work->token,work->work_group,0x1b, + nb_type|NB_ACTIVE ); /* DON'T do anything else after calling add_my_name_entry() */ return; @@ -366,10 +397,10 @@ void become_master(struct subnet_record *d, struct work_record *work) case MST_DOMAIN_TST: /* while we were still a master browser... */ { /* update our server status */ - if (lp_domain_master()) + if (conf_should_domain_master(work->token)) { struct subnet_record *d1; - uint32 update_type = 0; + uint32 update_type = 0; DEBUG(3,("domain third stage: samba is now a domain master.\n")); work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */ @@ -377,30 +408,30 @@ void become_master(struct subnet_record *d, struct work_record *work) update_type |= DFLT_SERVER_TYPE | SV_TYPE_DOMAIN_MASTER | SV_TYPE_POTENTIAL_BROWSER; - work->ServerType |= update_type; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); - - for (d1 = subnetlist; d1; d1 = d1->next) - { - struct work_record *w; - if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue; - - for (w = d1->workgrouplist; w; w = w->next) - { - struct server_record *s = find_server(w, myname); - if (strequal(w->work_group, work->work_group)) - { - w->ServerType |= update_type; - } - if (s) - { - s->serv.type |= update_type; - DEBUG(4,("found server %s on %s: update to %8x\n", - s->serv.name, inet_ntoa(d1->bcast_ip), - s->serv.type)); - } - } - } + work->ServerType |= update_type; + add_server_entry(d,work,my_name,work->ServerType,0,comment,True); + + for (d1 = subnetlist; d1; d1 = d1->next) + { + struct work_record *w; + if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue; + + for (w = d1->workgrouplist; w; w = w->next) + { + struct server_record *s = find_server(w, my_name); + if (strequal(w->work_group, work->work_group)) + { + w->ServerType |= update_type; + } + if (s) + { + s->serv.type |= update_type; + DEBUG(4,("found server %s on %s: update to %8x\n", + s->serv.name, inet_ntoa(d1->bcast_ip), + s->serv.type)); + } + } + } } break; @@ -421,11 +452,25 @@ void become_master(struct subnet_record *d, struct work_record *work) names, and tells the world that we are no longer a master browser. ******************************************************************/ void become_nonmaster(struct subnet_record *d, struct work_record *work, - int remove_type) + int remove_type) { int new_server_type = work->ServerType; - DEBUG(2,("Becoming non-master for %s\n",work->work_group)); + pstring comment; + + char *my_name ; + char *my_comment; + BOOL wins = ip_equal(d->bcast_ip, ipgrp); + enum master_state state; + + if (!work) return; + + my_name = conf_browsing_alias (work->token); + my_comment = conf_browsing_alias_comment(work->token); + + StrnCpy(comment, my_comment, 43); + + DEBUG(2,("Becoming non-master for %s alias %s\n",work->work_group, my_name)); /* can only remove master or domain types with this function */ remove_type &= SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER; @@ -435,6 +480,7 @@ void become_nonmaster(struct subnet_record *d, struct work_record *work, remove_type |= SV_TYPE_DOMAIN_MASTER; new_server_type &= ~remove_type; + state = work->state; if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER))) { @@ -444,25 +490,40 @@ void become_nonmaster(struct subnet_record *d, struct work_record *work, work->ElectionCriterion &= ~0x4; work->state = MST_NONE; - /* announce ourselves as no longer active as a master browser. */ - announce_server(d, work, work->work_group, myname, 0, 0); - remove_name_entry(d,MSBROWSE ,0x01); + remove_name_entry(d,work->token,MSBROWSE,0x01); } work->ServerType = new_server_type; if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER)) { - if (work->state == MST_DOMAIN) - work->state = MST_BROWSER; - remove_name_entry(d,work->work_group,0x1b); + if (state == MST_DOMAIN) + { + if (wins) + work->state = MST_NONE; + else + work->state = MST_BROWSER; + } + remove_name_entry(d,work->token,work->work_group,0x1b); } if (!(work->ServerType & SV_TYPE_MASTER_BROWSER)) { - if (work->state >= MST_BROWSER) + if (state >= MST_BROWSER) work->state = MST_NONE; - remove_name_entry(d,work->work_group,0x1d); + remove_name_entry(d,work->token,work->work_group,0x1d); + } + + /* update our internal records with our new server state */ + add_server_entry(d, work, my_name, work->ServerType, 0, my_comment, True); + + /* announce change in status on local interface */ + if (!wins) + { + /* XXXX do we need also to do an announce with a time of zero + if we are no longer a local master browser? + */ + work->needannounce = True; } } @@ -486,25 +547,27 @@ void run_elections(void) { struct work_record *work; for (work = d->workgrouplist; work; work = work->next) - { - if (work->RunningElection) - { - send_election(d,work->work_group, work->ElectionCriterion, - t-StartupTime,myname); - - if (work->ElectionCount++ >= 4) - { - /* I won! now what :-) */ - DEBUG(2,(">>> Won election on %s %s <<<\n", - work->work_group,inet_ntoa(d->bcast_ip))); - - work->RunningElection = False; - work->state = MST_NONE; - - become_master(d, work); - } - } - } + { + if (work->RunningElection) + { + char *alias = conf_browsing_alias(work->token); + + send_election(d,work->work_group, work->ElectionCriterion, + t-StartupTime,alias); + + if (work->ElectionCount++ >= 4) + { + /* I won! now what :-) */ + DEBUG(2,(">>> Won election for %s as %s on %s <<<\n", + work->work_group,alias,inet_ntoa(d->bcast_ip))); + + work->RunningElection = False; + work->state = MST_NONE; + + become_master(d, work); + } + } + } } } @@ -513,7 +576,7 @@ void run_elections(void) work out if I win an election ******************************************************************/ static BOOL win_election(struct work_record *work,int version,uint32 criterion, - int timeup,char *name) + int timeup,char *name) { int mytimeup = time(NULL) - StartupTime; uint32 mycriterion = work->ElectionCriterion; @@ -533,7 +596,7 @@ static BOOL win_election(struct work_record *work,int version,uint32 criterion, if (timeup > mytimeup) return(False); if (timeup < mytimeup) return(True); - if (strcasecmp(myname,name) > 0) return(False); + if (strcasecmp(conf_browsing_alias(work->token),name) > 0) return(False); return(True); } @@ -571,30 +634,38 @@ void process_election(struct packet_struct *p,char *buf) if (same_context(dgram)) return; for (work = d->workgrouplist; work; work = work->next) + { + if (!conf_should_local_master(work->token)) continue; + + if (win_election(work, version,criterion,timeup,name)) { - if (!strequal(work->work_group, lp_workgroup())) - continue; - - if (win_election(work, version,criterion,timeup,name)) { - if (!work->RunningElection) { - work->needelection = True; - work->ElectionCount=0; - work->state = MST_NONE; - } - } else { - work->needelection = False; - - if (work->RunningElection || AM_MASTER(work)) { - work->RunningElection = False; - DEBUG(3,(">>> Lost election on %s %s <<<\n", - work->work_group,inet_ntoa(d->bcast_ip))); - if (AM_MASTER(work)) - become_nonmaster(d, work, - SV_TYPE_MASTER_BROWSER| - SV_TYPE_DOMAIN_MASTER); - } - } + if (!work->RunningElection) + { + work->needelection = True; + work->ElectionCount=0; + work->state = MST_NONE; + } } + else + { + work->needelection = False; + + if (work->RunningElection || AM_MASTER(work)) + { + work->RunningElection = False; + DEBUG(3,(">>> Lost election on %s %s <<<\n", + work->work_group,inet_ntoa(d->bcast_ip))); + + /* if we are the master then remove our masterly names */ + if (AM_MASTER(work)) + { + become_nonmaster(d, work, + SV_TYPE_MASTER_BROWSER| + SV_TYPE_DOMAIN_MASTER); + } + } + } + } } @@ -615,18 +686,18 @@ BOOL check_elections(void) { struct work_record *work; for (work = d->workgrouplist; work; work = work->next) - { - run_any_election |= work->RunningElection; - - if (work->needelection && !work->RunningElection) - { - DEBUG(3,(">>> Starting election on %s %s <<<\n", - work->work_group,inet_ntoa(d->bcast_ip))); - work->ElectionCount = 0; - work->RunningElection = True; - work->needelection = False; - } - } + { + run_any_election |= work->RunningElection; + + if (work->needelection && !work->RunningElection) + { + DEBUG(3,(">>> Starting election on %s %s <<<\n", + work->work_group,inet_ntoa(d->bcast_ip))); + work->ElectionCount = 0; + work->RunningElection = True; + work->needelection = False; + } + } } return run_any_election; } diff --git a/source/namelogon.c b/source/namelogon.c index aacf32c2804..6b3b2e01ed1 100644 --- a/source/namelogon.c +++ b/source/namelogon.c @@ -21,7 +21,11 @@ Revision History: 14 jan 96: lkcl@pires.co.uk - added multiple workgroup domain master support + added domain master browser support + + 30 aug 96: lkcl@pires.co.uk + added multiple domain logon support, using extensions to David Chappell's + multiple domain master browser code. */ @@ -29,13 +33,8 @@ extern int ClientDGRAM; -#define TEST_CODE /* want to debug unknown browse packets */ - extern int DEBUGLEVEL; -extern pstring myname; - - /**************************************************************************** process a domain logon packet @@ -54,14 +53,18 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len) pstring outbuf; int code,reply_code; struct work_record *work; - + char *my_name; + if (!d) return; if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) return; - if (!lp_domain_logons()) { - DEBUG(3,("No domain logons\n")); + if ((my_name = conf_browsing_alias(work->token)) == NULL) return; + + if (!conf_should_domain_logon(work->token)) + { + DEBUG(3,("No domain logons for %s (%s)\n", work->work_group, my_name)); return; } @@ -73,7 +76,7 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len) char *user = skip_string(machine,1); logname = skip_string(user,1); reply_code = 6; - strcpy(reply_name,myname); + strcpy(reply_name, my_name); strupper(reply_name); add_slashes = True; DEBUG(3,("Domain login request from %s(%s) user=%s\n", @@ -87,7 +90,7 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len) reply_code = 7; strcpy(reply_name,lp_domain_controller()); if (!*reply_name) { - strcpy(reply_name,myname); + strcpy(reply_name,my_name); reply_code = 0xC; } strupper(reply_name); @@ -121,8 +124,8 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len) PutUniCode(q,reply_name); q += 2*(strlen(reply_name) + 1); - PutUniCode(q,lp_workgroup()); - q += 2*(strlen(lp_workgroup()) + 1); + PutUniCode(q,work->work_group); + q += 2*(strlen(work->work_group) + 1); SIVAL(q,0,1); q += 4; @@ -134,6 +137,6 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len) q += 2; send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf), - myname,&dgram->source_name.name[0],0x20,0,p->ip, + my_name,&dgram->source_name.name[0],0x20,0,p->ip, *iface_ip(p->ip)); } diff --git a/source/namepacket.c b/source/namepacket.c index 5bfa55d4f16..121cf26eb00 100644 --- a/source/namepacket.c +++ b/source/namepacket.c @@ -38,90 +38,165 @@ BOOL CanRecurse = True; extern pstring scope; extern struct in_addr ipgrp; -static uint16 name_trn_id=0; +extern uint16 name_trn_id; -/*************************************************************************** - updates the unique transaction identifier - **************************************************************************/ -void debug_browse_data(char *outbuf, int len) +/**************************************************************************** + process a nmb packet + ****************************************************************************/ +static void process_nmb(struct packet_struct *p) { - int i,j; - for (i = 0; i < len; i+= 16) + struct nmb_packet *nmb = &p->packet.nmb; + + debug_nmb_packet(p); + + switch (nmb->header.opcode) + { + case 8: /* what is this?? */ + case NMB_REG: + case NMB_REG_REFRESH: + { + if (nmb->header.response) + { + if (nmb->header.ancount==0) break; + response_netbios_packet(p); + } + else + { + if (nmb->header.qdcount==0 || nmb->header.arcount==0) break; + reply_name_reg(p); + } + break; + } + + case 0: + { + if (nmb->header.response) + { + switch (nmb->question.question_type) + { + case 0x0: + { + response_netbios_packet(p); + break; + } + } + return; + } + else if (nmb->header.qdcount>0) { - DEBUG(4, ("%3x char ", i)); - - for (j = 0; j < 16; j++) - { - unsigned char x = outbuf[i+j]; - if (x < 32 || x > 127) x = '.'; - - if (i+j >= len) break; - DEBUG(4, ("%c", x)); - } - - DEBUG(4, (" hex ", i)); - - for (j = 0; j < 16; j++) - { - if (i+j >= len) break; - DEBUG(4, (" %02x", outbuf[i+j])); - } - - DEBUG(4, ("\n")); + switch (nmb->question.question_type) + { + case NMB_QUERY: + { + reply_name_query(p); + break; + } + case NMB_STATUS: + { + reply_name_status(p); + break; + } + } + return; + } + break; + } + + case NMB_REL: + { + if (nmb->header.qdcount==0 || nmb->header.arcount==0) + { + DEBUG(2,("netbios release packet rejected\n")); + break; } + if (nmb->header.response) + { + if (nmb->header.ancount==0) break; + response_netbios_packet(p); + } + else + { + reply_name_release(p); + } + break; + } + } } /*************************************************************************** updates the unique transaction identifier **************************************************************************/ -static void update_name_trn_id(void) +void debug_browse_data(char *outbuf, int len) { - if (!name_trn_id) - { - name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100); - } - name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; + int i,j; + for (i = 0; i < len; i+= 16) + { + DEBUG(4, ("%3x char ", i)); + + for (j = 0; j < 16; j++) + { + unsigned char x = outbuf[i+j]; + if (x < 32 || x > 127) x = '.'; + + if (i+j >= len) break; + DEBUG(4, ("%c", x)); + } + + DEBUG(4, (" hex ", i)); + + for (j = 0; j < 16; j++) + { + if (i+j >= len) break; + DEBUG(4, (" %02x", (unsigned char)outbuf[i+j])); + } + + DEBUG(4, ("\n")); + } + } /**************************************************************************** initiate a netbios packet + + if we are making queries to samba, then the ip must be zero. in this + instance, the packet is constructed and then dealt with immediately. + + netbios packets sent to an ip of zero are dealt with immediately by calling + process_nmb(), in order to allow, for example, querying of samba's WINS + records. at first, this seems like a really dumb thing to do. but then + again, the packet_struct created contains _exactly_ the information + required. the alternative is to take packet_struct out of the loop, + which is a fairly messy operation. ****************************************************************************/ -void initiate_netbios_packet(uint16 *id, - int fd,int quest_type,char *name,int name_type, - int nb_flags,BOOL bcast,BOOL recurse, - struct in_addr to_ip) +BOOL initiate_netbios_packet(uint16 id, + int fd,int quest_type,char *name,int name_type, + int nb_flags,BOOL bcast,BOOL recurse, + struct in_addr to_ip) { struct packet_struct p; struct nmb_packet *nmb = &p.packet.nmb; struct res_rec additional_rec; - char *packet_type = "unknown"; + char *pkt_type = "unknown"; int opcode = -1; - if (!id) return; - - if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; } - if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; } - if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; } - if (quest_type == NMB_REG_REFRESH ) { packet_type = "nmb_reg_refresh"; opcode = 9; } - if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; } + if (quest_type == NMB_STATUS) { pkt_type = "nmb_status"; opcode = 0; } + if (quest_type == NMB_QUERY ) { pkt_type = "nmb_query"; opcode = 0; } + if (quest_type == NMB_REG ) { pkt_type = "nmb_reg"; opcode = 5; } + if (quest_type == NMB_REG_REFRESH) { pkt_type="nmb_reg_refresh"; opcode=9; } + if (quest_type == NMB_REL ) { pkt_type = "nmb_rel"; opcode = 6; } DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n", - packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip))); + pkt_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip))); - if (opcode == -1) return; + if (opcode == -1) return False; bzero((char *)&p,sizeof(p)); - if (*id == 0xffff) { - update_name_trn_id(); - *id = name_trn_id; /* allow resending with same id */ - } - - nmb->header.name_trn_id = *id; + nmb->header.name_trn_id = id; nmb->header.opcode = opcode; nmb->header.response = False; @@ -162,7 +237,7 @@ void initiate_netbios_packet(uint16 *id, nmb->additional->rdlength = 6; nmb->additional->rdata[0] = nb_flags; putip(&nmb->additional->rdata[2],(char *)iface_ip(to_ip)); - } + } p.ip = to_ip; p.port = NMB_PORT; @@ -170,12 +245,21 @@ void initiate_netbios_packet(uint16 *id, p.timestamp = time(NULL); p.packet_type = NMB_PACKET; - if (!send_packet(&p)) { - DEBUG(3,("send_packet to %s %d failed\n",inet_ntoa(p.ip),p.port)); - *id = 0xffff; + if (zero_ip(to_ip)) /* samba's own ip */ + { + DEBUG(4,("process packet ourselves\n")); + /* respond internally to the packet. */ + process_nmb(&p); } - - return; + else + { + if (!send_packet(&p)) { + DEBUG(3,("send_packet to %s %d failed\n",inet_ntoa(p.ip),p.port)); + return False; + } + } + + return True; } @@ -183,9 +267,9 @@ void initiate_netbios_packet(uint16 *id, reply to a netbios name packet ****************************************************************************/ void reply_netbios_packet(struct packet_struct *p1,int trn_id, - int rcode, int rcv_code, int opcode, BOOL recurse, - struct nmb_name *rr_name,int rr_type,int rr_class,int ttl, - char *data,int len) + int rcode, int rcv_code, int opcode, BOOL recurse, + struct nmb_name *rr_name,int rr_type,int rr_class,int ttl, + char *data,int len) { struct packet_struct p; struct nmb_packet *nmb = &p.packet.nmb; @@ -198,31 +282,31 @@ void reply_netbios_packet(struct packet_struct *p1,int trn_id, switch (rcv_code) { case NMB_STATUS: - { + { packet_type = "nmb_status"; recursion_desired = True; break; } case NMB_QUERY: - { + { packet_type = "nmb_query"; recursion_desired = True; break; } case NMB_REG: - { + { packet_type = "nmb_reg"; recursion_desired = True; break; } case NMB_REL: - { + { packet_type = "nmb_rel"; recursion_desired = False; break; } case NMB_WAIT_ACK: - { + { packet_type = "nmb_wack"; recursion_desired = False; break; @@ -230,14 +314,14 @@ void reply_netbios_packet(struct packet_struct *p1,int trn_id, default: { DEBUG(1,("replying netbios packet: %s %s\n", - packet_type, namestr(rr_name), inet_ntoa(p.ip))); + packet_type, namestr(rr_name), inet_ntoa(p.ip))); return; } } DEBUG(4,("replying netbios packet: %s %s\n", - packet_type, namestr(rr_name), inet_ntoa(p.ip))); + packet_type, namestr(rr_name), inet_ntoa(p.ip))); nmb->header.name_trn_id = trn_id; nmb->header.opcode = opcode; @@ -265,16 +349,25 @@ void reply_netbios_packet(struct packet_struct *p1,int trn_id, nmb->answers->ttl = ttl; if (data && len) - { - nmb->answers->rdlength = len; - memcpy(nmb->answers->rdata, data, len); - } + { + nmb->answers->rdlength = len; + memcpy(nmb->answers->rdata, data, len); + } p.packet_type = NMB_PACKET; debug_nmb_packet(&p); - send_packet(&p); + if (zero_ip(p.ip)) /* samba's own ip */ + { + DEBUG(4,("process response packet ourselves\n")); + /* respond internally to the packet. */ + process_nmb(&p); + } + else + { + send_packet(&p); + } } @@ -352,7 +445,7 @@ static void process_dgram(struct packet_struct *p) buf = &dgram->data[0]; buf -= 4; /* XXXX for the pseudo tcp length - - someday I need to get rid of this */ + someday I need to get rid of this */ if (CVAL(buf,smb_com) != SMBtrans) return; @@ -360,8 +453,8 @@ static void process_dgram(struct packet_struct *p) buf2 = smb_base(buf) + SVAL(buf,smb_vwv12); DEBUG(4,("datagram from %s to %s for %s of type %d len=%d\n", - namestr(&dgram->source_name),namestr(&dgram->dest_name), - smb_buf(buf),CVAL(buf2,0),len)); + namestr(&dgram->source_name),namestr(&dgram->dest_name), + smb_buf(buf),CVAL(buf2,0),len)); if (len <= 0) return; @@ -379,83 +472,6 @@ static void process_dgram(struct packet_struct *p) } } -/**************************************************************************** - process a nmb packet - ****************************************************************************/ -static void process_nmb(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - - debug_nmb_packet(p); - - switch (nmb->header.opcode) - { - case 8: /* what is this?? */ - case NMB_REG: - case NMB_REG_REFRESH: - { - if (nmb->header.qdcount==0 || nmb->header.arcount==0) break; - if (nmb->header.response) - response_netbios_packet(p); /* response to registration dealt - with here */ - else - reply_name_reg(p); - break; - } - - case 0: - { - if (nmb->header.response) - { - switch (nmb->question.question_type) - { - case 0x0: - { - response_netbios_packet(p); - break; - } - } - return; - } - else if (nmb->header.qdcount>0) - { - switch (nmb->question.question_type) - { - case NMB_QUERY: - { - reply_name_query(p); - break; - } - case NMB_STATUS: - { - reply_name_status(p); - break; - } - } - return; - } - break; - } - - case NMB_REL: - { - if (nmb->header.qdcount==0 || nmb->header.arcount==0) - { - DEBUG(2,("netbios release packet rejected\n")); - break; - } - - if (nmb->header.response) - response_netbios_packet(p); /* response to reply dealt with - in here */ - else - reply_name_release(p); - break; - } - } -} - - /******************************************************************* run elements off the packet queue till its empty ******************************************************************/ @@ -466,15 +482,15 @@ void run_packet_queue() while ((p=packet_queue)) { switch (p->packet_type) - { - case NMB_PACKET: - process_nmb(p); - break; - - case DGRAM_PACKET: - process_dgram(p); - break; - } + { + case NMB_PACKET: + process_nmb(p); + break; + + case DGRAM_PACKET: + process_dgram(p); + break; + } packet_queue = packet_queue->next; if (packet_queue) packet_queue->prev = NULL; @@ -550,8 +566,8 @@ try_again: wrong things to do! I should send to the requestors port. XXX **************************************************************************/ BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname, - char *dstname,int src_type,int dest_type, - struct in_addr dest_ip,struct in_addr src_ip) + char *dstname,int src_type,int dest_type, + struct in_addr dest_ip,struct in_addr src_ip) { struct packet_struct p; struct dgram_packet *dgram = &p.packet.dgram; diff --git a/source/nameresp.c b/source/nameresp.c index 7fcb41e79f0..bd64fba2b63 100644 --- a/source/nameresp.c +++ b/source/nameresp.c @@ -35,15 +35,30 @@ extern pstring scope; extern struct in_addr ipzero; extern struct in_addr ipgrp; +uint16 name_trn_id=0; + + +/*************************************************************************** + updates the unique transaction identifier + **************************************************************************/ +void update_name_trn_id(void) +{ + if (!name_trn_id) + { + name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100); + } + name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; +} + /*************************************************************************** deals with an entry before it dies **************************************************************************/ static void dead_netbios_entry(struct subnet_record *d, - struct response_record *n) + struct response_record *n) { DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n", - inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs)); + inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs)); debug_state_type(n->state); @@ -51,118 +66,118 @@ static void dead_netbios_entry(struct subnet_record *d, { case NAME_QUERY_CONFIRM: { - if (!lp_wins_support()) return; /* only if we're a WINS server */ + if (!lp_wins_support()) return; /* only if we're a WINS server */ - if (n->num_msgs == 0) + if (n->num_msgs == 0) { - /* oops. name query had no response. check that the name is - unique and then remove it from our WINS database */ - - /* IMPORTANT: see query_refresh_names() */ - - if ((!NAME_GROUP(n->nb_flags))) - { - struct subnet_record *d1 = find_subnet(ipgrp); - if (d1) - { - /* remove the name that had been registered with us, - and we're now getting no response when challenging. - see rfc1001.txt 15.5.2 - */ - remove_netbios_name(d1, n->name.name, n->name.name_type, - REGISTER, n->send_ip); - } - } - } - break; + /* oops. name query had no response. check that the name is + unique and then remove it from our WINS database */ + + /* IMPORTANT: see query_refresh_names() */ + + if ((!NAME_GROUP(n->reply.nb_flags))) + { + struct subnet_record *d1 = find_subnet(ipgrp); + if (d1) + { + /* remove the name that had been registered with us, + and we're now getting no response when challenging. + see rfc1001.txt 15.5.2 + */ + remove_netbios_name(d1, n->name.name, n->name.name_type, + REGISTER, n->send_ip); + } + } + } + break; } - case NAME_QUERY_MST_CHK: - { - /* if no response received, the master browser must have gone - down on that subnet, without telling anyone. */ - - /* IMPORTANT: see response_netbios_packet() */ - - if (n->num_msgs == 0) - browser_gone(n->name.name, n->send_ip); - break; - } - - case NAME_RELEASE: - { - /* if no response received, it must be OK for us to release the - name. nobody objected (including a potentially dead or deaf - WINS server) */ - - /* IMPORTANT: see response_name_release() */ - - if (ismyip(n->send_ip)) - { - name_unregister_work(d,n->name.name,n->name.name_type); - } - if (!n->bcast) - { - DEBUG(0,("WINS server did not respond to name release!\n")); + case NAME_QUERY_MST_CHK: + { + /* if no response received, the master browser must have gone + down on that subnet, without telling anyone. */ + + /* IMPORTANT: see response_netbios_packet() */ + + if (n->num_msgs == 0) + browser_gone(n->name.name, n->send_ip); + break; + } + + case NAME_RELEASE: + { + /* if no response received, it must be OK for us to release the + name. nobody objected (including a potentially dead or deaf + WINS server) */ + + /* IMPORTANT: see response_name_release() */ + + if (ismyip(n->send_ip)) + { + name_unregister_work(d,n->name.name,n->name.name_type); + } + if (!n->bcast) + { + DEBUG(0,("WINS server did not respond to name release!\n")); /* XXXX whoops. we have problems. must deal with this */ - } - break; - } - - case NAME_REGISTER_CHALLENGE: - { - /* name challenge: no reply. we can reply to the person that - wanted the unique name and tell them that they can have it - */ - - add_name_respond(d,n->fd,d->myip, n->response_id ,&n->name, - n->nb_flags, GET_TTL(0), - n->reply_to_ip, False, n->reply_to_ip); - - if (!n->bcast) - { - DEBUG(1,("WINS server did not respond to name registration!\n")); + } + break; + } + + case NAME_REGISTER_CHALLENGE: + { + /* name challenge: no reply. we can reply to the person that + wanted the unique name and tell them that they can have it + */ + + add_name_respond(d,n->fd,d->myip, n->response_id ,&n->name, + n->reply.nb_flags, GET_TTL(0), + n->reply.ip, False, n->reply.ip); + + if (!n->bcast) + { + DEBUG(1,("WINS server did not respond to name registration!\n")); /* XXXX whoops. we have problems. must deal with this */ - } + } break; - } - - case NAME_REGISTER: - { - /* if no response received, and we are using a broadcast registration - method, it must be OK for us to register the name: nobody objected - on that subnet. if we are using a WINS server, then the WINS - server must be dead or deaf. - */ - if (n->bcast) - { - /* broadcast method: implicit acceptance of the name registration - by not receiving any objections. */ - - /* IMPORTANT: see response_name_reg() */ - - name_register_work(d,n->name.name,n->name.name_type, - n->nb_flags, n->ttl, n->reply_to_ip, n->bcast); - } - else - { - /* received no response. rfc1001.txt states that after retrying, - we should assume the WINS server is dead, and fall back to - broadcasting (see bits about M nodes: can't find any right + } + + case NAME_REGISTER: + { + /* if no response received, and we are using a broadcast registration + method, it must be OK for us to register the name: nobody objected + on that subnet. if we are using a WINS server, then the WINS + server must be dead or deaf. + */ + if (n->bcast) + { + /* broadcast method: implicit acceptance of the name registration + by not receiving any objections. */ + + /* IMPORTANT: see response_name_reg() */ + + name_register_work(d,n->token,n->name.name,n->name.name_type, + n->source, &n->reply, n->ttl, n->reply.ip, n->bcast); + } + else + { + /* received no response. rfc1001.txt states that after retrying, + we should assume the WINS server is dead, and fall back to + broadcasting (see bits about M nodes: can't find any right now) */ - - DEBUG(1,("WINS server did not respond to name registration!\n")); + + DEBUG(1,("WINS server did not respond to name registration!\n")); /* XXXX whoops. we have problems. must deal with this */ - } - break; - } - - default: - { - /* nothing to do but delete the dead expected-response structure */ - /* this is normal. */ - break; - } + } + break; + } + + default: + { + /* nothing to do but delete the dead expected-response structure */ + /* this is normal. */ + break; + } } } @@ -184,81 +199,52 @@ void expire_netbios_response_entries() for (n = d->responselist; n; n = nextn) { - nextn = n->next; + nextn = n->next; if (n->repeat_time <= time(NULL)) - { - if (n->repeat_count > 0) - { - /* resend the entry */ - initiate_netbios_packet(&n->response_id, n->fd, n->quest_type, - n->name.name, n->name.name_type, - n->nb_flags, n->bcast, n->recurse, n->send_ip); + { + if (n->repeat_count > 0) + { + /* resend the entry */ + initiate_netbios_packet(n->response_id, n->fd, n->quest_type, + n->name.name, n->name.name_type, + n->reply.nb_flags, n->bcast, n->recurse, n->send_ip); n->repeat_time += n->repeat_interval; /* XXXX ms needed */ n->repeat_count--; - } - else - { + } + else + { DEBUG(4,("timeout response %d for %s %s\n", - n->response_id, namestr(&n->name), + n->response_id, namestr(&n->name), inet_ntoa(n->send_ip))); - dead_netbios_entry (d,n); /* process the non-response */ + dead_netbios_entry (d,n); /* process the non-response */ remove_response_record(d,n); /* remove the non-response */ - continue; - } - } + continue; + } + } } } } /**************************************************************************** - wrapper function to override a broadcast message and send it to the WINS - name server instead, if it exists. if wins is false, and there has been no - WINS server specified, the packet will NOT be sent. ****************************************************************************/ -struct response_record *queue_netbios_pkt_wins(struct subnet_record *d, - int fd,int quest_type,enum state_type state, - char *name,int name_type,int nb_flags, time_t ttl, - int server_type, char *my_name, char *my_comment, - BOOL bcast,BOOL recurse, - struct in_addr send_ip, struct in_addr reply_to_ip) +void queue_netbios_pkt_wins(struct subnet_record *d, + int fd,int quest_type,enum state_type state, + int token, char *name,int name_type, + enum name_source source, int nb_flags, time_t ttl, + int server_type, char *my_name, char *my_comment, + BOOL bcast,BOOL recurse, + struct in_addr send_ip, struct in_addr reply_to_ip) { - /* XXXX note: please see rfc1001.txt section 10 for details on this - function: it is currently inappropriate to use this - it will do - for now - once there is a clarification of B, M and P nodes and - which one samba is supposed to be - */ - - if ((!lp_wins_support()) && (*lp_wins_server())) - { - /* samba is not a WINS server, and we are using a WINS server */ - struct in_addr wins_ip; - wins_ip = *interpret_addr2(lp_wins_server()); - - if (!zero_ip(wins_ip)) - { - bcast = False; - send_ip = wins_ip; - } - else - { - /* oops. smb.conf's wins server parameter MUST be a host_name - or an ip_address. */ - DEBUG(0,("invalid smb.conf parameter 'wins server'\n")); - } - } - - if (zero_ip(send_ip)) return NULL; - - return queue_netbios_packet(d,fd, quest_type, state, - name, name_type, nb_flags, ttl, + queue_netbios_packet(d,fd, quest_type, state, + token, name, name_type, source, nb_flags, ttl, server_type,my_name,my_comment, - bcast, recurse, send_ip, reply_to_ip); + bcast, recurse, send_ip, reply_to_ip); } @@ -267,36 +253,83 @@ struct response_record *queue_netbios_pkt_wins(struct subnet_record *d, this is intended to be used (not exclusively) for broadcasting to master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get complete lists across a wide area network + + a broadcast message will be over-ridden if the packet it sent to an + ip of zero, and the packet will be sent to the WINS name server instead, + if it exists. if samba is configured to be a WINS server, then the + packet will be dealt with _as if_ it had been sent on the network, + but in fact the function process_nmb() is called. ****************************************************************************/ -struct response_record *queue_netbios_packet(struct subnet_record *d, - int fd,int quest_type,enum state_type state,char *name, - int name_type,int nb_flags, time_t ttl, - int server_type, char *my_name, char *my_comment, - BOOL bcast,BOOL recurse, - struct in_addr send_ip, struct in_addr reply_to_ip) +void queue_netbios_packet(struct subnet_record *d, + int fd,int quest_type,enum state_type state, + int token, char *name, int name_type, + enum name_source source, int nb_flags, time_t ttl, + int server_type, char *my_name, char *my_comment, + BOOL bcast,BOOL recurse, + struct in_addr send_ip, struct in_addr reply_to_ip) { - struct in_addr wins_ip = ipgrp; struct response_record *n; - uint16 id = 0xffff; /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */ - if (ip_equal(wins_ip, send_ip)) return NULL; + if (ip_equal(send_ip, ipgrp)) return; - initiate_netbios_packet(&id, fd, quest_type, name, name_type, - nb_flags, bcast, recurse, send_ip); + /* XXXX note: please see rfc1001.txt section 10 for details on this + function: it is currently inappropriate to use this - it will do + for now - once there is a clarification of B, M and P nodes and + which one samba is supposed to be + */ - if (id == 0xffff) { - DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip))); - return NULL; + if ((!lp_wins_support()) && (*lp_wins_server())) + { + /* samba is not a WINS server, and we are using a WINS server */ + struct in_addr wins_ip; + wins_ip = *interpret_addr2(lp_wins_server()); + + if (!zero_ip(wins_ip)) + { + bcast = False; + send_ip = wins_ip; + } + else + { + /* oops. smb.conf's wins server parameter MUST be a host_name + or an ip_address. */ + DEBUG(0,("invalid smb.conf parameter 'wins server'\n")); + } } - if ((n = make_response_queue_record(state,id,fd, - quest_type,name,name_type,nb_flags,ttl, - server_type,my_name, my_comment, - bcast,recurse,send_ip,reply_to_ip))) + if (zero_ip(send_ip)) + { + /* doing a netbios query to samba as a WINS server, internally */ + if (lp_wins_support()) /* samba is a WINS server */ + { + DEBUG(4,("queue netbios packet with ourselves...\n")); + bcast = False; + } + else { - add_response_record(d,n); - return n; + return; } - return NULL; + } + + update_name_trn_id(); + + /* queue the response expected because if we do a query with an ip + of zero, we are expecting to hear from ourself immediately */ + if ((n = make_response_queue_record(state, name_trn_id, fd, quest_type, + token, name, name_type, source, nb_flags, ttl, + server_type, my_name, my_comment, + bcast, recurse, send_ip, reply_to_ip))) + { + add_response_record(d,n); + } + + if (!initiate_netbios_packet(name_trn_id, fd, quest_type, name, name_type, + nb_flags, bcast, recurse, send_ip)) + { + /* packet wasn't sent - not expecting a response */ + DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip))); + remove_response_record(d, n); + return; + } } diff --git a/source/nameserv.c b/source/nameserv.c index c8bbb528116..6bdc95896f2 100644 --- a/source/nameserv.c +++ b/source/nameserv.c @@ -51,7 +51,7 @@ extern uint16 nb_type; /* samba's NetBIOS type */ XXXX at present, the name is removed _even_ if a WINS server says keep it. ****************************************************************************/ -void remove_name_entry(struct subnet_record *d, char *name,int type) +void remove_name_entry(struct subnet_record *d, int token, char *name,int type) { /* XXXX BUG: if samba is offering WINS support, it should still broadcast a de-registration packet to the local subnet before removing the @@ -80,17 +80,18 @@ void remove_name_entry(struct subnet_record *d, char *name,int type) don't really own */ remove_netbios_name(d,name,type,SELF,n2->ip_flgs[0].ip); - if (ip_equal(d->bcast_ip, ipgrp)) { - if (!lp_wins_support()) { - /* not a WINS server: we have to release them on the network */ + if (ip_equal(d->bcast_ip, ipgrp)) + { + /* use WINS. this function can now be used to _either_ + do the release on samba's own database _or_ release + the name with an arbitrary WINS server */ queue_netbios_pkt_wins(d,ClientNMB,NMB_REL,NAME_RELEASE, - name, type, 0, 0,0,NULL,NULL, + token, name, type, SELF, 0, 0,0,NULL,NULL, False, True, ipzero, ipzero); - } } else { /* local interface: release them on the network */ queue_netbios_packet(d,ClientNMB,NMB_REL,NAME_RELEASE, - name, type, 0, 0,0,NULL,NULL, + token, name, type, SELF, 0, 0,0,NULL,NULL, True, True, d->bcast_ip, d->bcast_ip); } } @@ -103,7 +104,8 @@ void remove_name_entry(struct subnet_record *d, char *name,int type) it's just a matter of when this will be done (e.g after a time-out). ****************************************************************************/ -void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) +void add_my_name_entry(struct subnet_record *d, int token, + char *name,int type,int nb_flags) { BOOL re_reg = False; struct nmb_name n; @@ -115,7 +117,7 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) make_nmb_name(&n, name, type, scope); if (find_name(d->namelist, &n, SELF)) - re_reg = True; + re_reg = True; /* XXXX BUG: if samba is offering WINS support, it should still add the name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28 @@ -123,6 +125,7 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) if (ip_equal(d->bcast_ip, ipgrp)) { +#if 0 if (lp_wins_support()) { /* we are a WINS server. */ @@ -131,26 +134,38 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) actually be true */ + struct nmb_ip data; + + data.nb_flags = nb_flags; + putip(&data.ip, ipzero); + DEBUG(4,("samba as WINS server adding: ")); /* this will call add_netbios_entry() */ - name_register_work(d, name, type, nb_flags,0, ipzero, False); + + name_register_work(d,token,name,type,SELF,&data,GET_TTL(0),ipzero,False); } else { +#endif + /* ipzero when not using an arbitrary wins server results in the + netbios packet being short-circuited to process_nmb() + */ /* a time-to-live allows us to refresh this name with the WINS server. */ - queue_netbios_pkt_wins(d,ClientNMB, - re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER, - name, type, nb_flags, GET_TTL(0),0,NULL,NULL, - False, True, ipzero, ipzero); + queue_netbios_pkt_wins(d,ClientNMB, + re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER, + token, name, type, SELF, nb_flags, GET_TTL(0),0,NULL,NULL, + False, True, ipzero, ipzero); +#if 0 } +#endif } else { /* broadcast the packet, but it comes from ipzero */ - queue_netbios_packet(d,ClientNMB, - re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER, - name, type, nb_flags, GET_TTL(0),0,NULL,NULL, - True, True, d->bcast_ip, ipzero); + queue_netbios_packet(d,ClientNMB, + re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER, + token, name, type, SELF, nb_flags, GET_TTL(0),0,NULL,NULL, + True, True, d->bcast_ip, ipzero); } } @@ -161,6 +176,8 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) void add_my_names(void) { struct subnet_record *d; + int token; + /* each subnet entry, including WINS pseudo-subnet, has SELF names */ /* XXXX if there was a transport layer added to samba (ipx/spx etc) then @@ -169,32 +186,56 @@ void add_my_names(void) for (d = subnetlist; d; d = d->next) { - BOOL wins = lp_wins_support() && ip_equal(d->bcast_ip,ipgrp); + BOOL wins = ip_equal(d->bcast_ip,ipgrp); + + for (token = 0; token < get_num_workgroups(); token++) + { + char *my_name = conf_browsing_alias(token); + char *wg_name = conf_workgroup_name(token); + + if (my_name) + { + add_my_name_entry(d, token, my_name,0x20,nb_type|NB_ACTIVE); + add_my_name_entry(d, token, my_name,0x03,nb_type|NB_ACTIVE); + add_my_name_entry(d, token, my_name,0x00,nb_type|NB_ACTIVE); + add_my_name_entry(d, token, my_name,0x1f,nb_type|NB_ACTIVE); + } + + if (wg_name && conf_should_domain_logon(token)) + { + /* the 0x1c is to do with domain logons */ + add_my_name_entry(d, token, wg_name,0x1c,nb_type|NB_ACTIVE|NB_GROUP); + } + } - add_my_name_entry(d, myname,0x20,nb_type|NB_ACTIVE); - add_my_name_entry(d, myname,0x03,nb_type|NB_ACTIVE); - add_my_name_entry(d, myname,0x00,nb_type|NB_ACTIVE); - add_my_name_entry(d, myname,0x1f,nb_type|NB_ACTIVE); - /* these names are added permanently (ttl of zero) and will NOT be refreshed with the WINS server */ + add_netbios_entry(d,"*",0x0,nb_type|NB_ACTIVE,0,SELF,d->myip,False,wins); - add_netbios_entry(d,"*",0x20,nb_type|NB_ACTIVE,0,SELF,d->myip,False,wins); add_netbios_entry(d,"__SAMBA__",0x20,nb_type|NB_ACTIVE,0,SELF,d->myip,False,wins); add_netbios_entry(d,"__SAMBA__",0x00,nb_type|NB_ACTIVE,0,SELF,d->myip,False,wins); - - if (lp_domain_logons()) { - /* XXXX the 0x1c is apparently something to do with domain logons */ - add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP); - } + } - if (lp_domain_master() && (d = find_subnet(ipgrp))) + + /* check becoming a domain master under all browser aliases */ + + if ((d = find_subnet(ipgrp))) { - struct work_record *work = find_workgroupstruct(d, lp_workgroup(), True); - if (work && work->state == MST_NONE) + for (token = 0; token < get_num_workgroups(); token++) { - work->state = MST_DOMAIN_NONE; - become_master(d, work); + if (conf_should_domain_master(token)) + { + char *work_name = conf_workgroup_name(token); + if (work_name) + { + struct work_record *work = find_workgroupstruct(d,work_name,True); + if (work && work->state == MST_NONE) + { + work->state = MST_DOMAIN_NONE; + become_master(d, work); + } + } + } } } } @@ -205,52 +246,24 @@ void add_my_names(void) **************************************************************************/ void remove_my_names() { - struct subnet_record *d; - - for (d = subnetlist; d; d = d->next) - { - struct name_record *n, *next; - - for (n = d->namelist; n; n = next) - { - next = n->next; - if (n->source == SELF) - { - /* get all SELF names removed from the WINS server's database */ - /* XXXX note: problem occurs if this removes the wrong one! */ - - remove_name_entry(d,n->name.name, n->name.name_type); - } - } - } -} - - -/******************************************************************* - refresh my own names - ******************************************************************/ -void refresh_my_names(time_t t) -{ - struct subnet_record *d; + struct subnet_record *d; - for (d = subnetlist; d; d = d->next) - { - struct name_record *n; - - for (n = d->namelist; n; n = n->next) + for (d = subnetlist; d; d = d->next) { - /* each SELF name has an individual time to be refreshed */ - if (n->source == SELF && n->refresh_time < time(NULL) && - n->death_time != 0) - { - add_my_name_entry(d,n->name.name,n->name.name_type, - n->ip_flgs[0].nb_flags); - /* they get a new lease on life :-) */ - n->death_time += GET_TTL(0); - n->refresh_time += GET_TTL(0); - } + struct name_record *n, *next; + + for (n = d->namelist; n; n = next) + { + next = n->next; + if (n->source == SELF) + { + /* get all SELF names removed from the WINS server's database */ + /* XXXX note: problem occurs if this removes the wrong one! */ + + remove_name_entry(d, -1, n->name.name, n->name.name_type); + } + } } - } } @@ -265,55 +278,55 @@ void refresh_my_names(time_t t) ******************************************************************/ void query_refresh_names(void) { - struct name_record *n; - struct subnet_record *d = find_subnet(ipgrp); + struct name_record *n; + struct subnet_record *d = find_subnet(ipgrp); - static time_t lasttime = 0; - time_t t = time(NULL); + static time_t lasttime = 0; + time_t t = time(NULL); - int count = 0; - int name_refresh_time = NAME_POLL_REFRESH_TIME; - int max_count = name_refresh_time * 2 / NAME_POLL_INTERVAL; - if (max_count > 10) max_count = 10; + int count = 0; + int name_refresh_time = NAME_POLL_REFRESH_TIME; + int max_count = name_refresh_time * 2 / NAME_POLL_INTERVAL; + if (max_count > 10) max_count = 10; - name_refresh_time = NAME_POLL_INTERVAL * max_count / 2; + name_refresh_time = NAME_POLL_INTERVAL * max_count / 2; - /* if (!lp_poll_wins()) return; polling of registered names allowed */ + /* if (!lp_poll_wins()) return; polling of registered names allowed */ - if (!d) return; + if (!d) return; if (!lasttime) lasttime = t; - if (t - lasttime < NAME_POLL_INTERVAL) return; + if (t - lasttime < NAME_POLL_INTERVAL) return; lasttime = time(NULL); - for (n = d->namelist; n; n = n->next) - { - /* only do unique, registered names */ - - if (n->source != REGISTER) continue; - if (!NAME_GROUP(n->ip_flgs[0].nb_flags)) continue; - - if (n->refresh_time < t) - { - DEBUG(3,("Polling name %s\n", namestr(&n->name))); - - queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_CONFIRM, - n->name.name, n->name.name_type, - 0,0,0,NULL,NULL, - False,False,n->ip_flgs[0].ip,n->ip_flgs[0].ip); - count++; - } - - if (count >= max_count) - { - /* don't do too many of these at once, but do enough to - cover everyone in the list */ - return; - } - - /* this name will be checked on again, if it's not removed */ - n->refresh_time += name_refresh_time; - } + for (n = d->namelist; n; n = n->next) + { + /* only do unique, registered names. */ + + if (n->source != REGISTER) continue; + if (!NAME_GROUP(n->ip_flgs[0].nb_flags)) continue; + + if (n->refresh_time < t) + { + DEBUG(3,("Polling name %s\n", namestr(&n->name))); + + queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_CONFIRM, + -1,n->name.name, n->name.name_type, + n->source,0,0,0,NULL,NULL, + False,False,n->ip_flgs[0].ip,n->ip_flgs[0].ip); + count++; + } + + if (count >= max_count) + { + /* don't do too many of these at once, but do enough to + cover everyone in the list */ + return; + } + + /* this name will be checked on again, if it's not removed */ + n->refresh_time += name_refresh_time; + } } diff --git a/source/nameservreply.c b/source/nameservreply.c index b01c2c25b4c..f5811925d40 100644 --- a/source/nameservreply.c +++ b/source/nameservreply.c @@ -294,8 +294,8 @@ void reply_name_reg(struct packet_struct *p) /* initiate some enquiries to the current owner. */ queue_netbios_packet(d,ClientNMB,NMB_QUERY, NAME_REGISTER_CHALLENGE, - reply_name->name,reply_name->name_type, - nb_flags,0,0,NULL,NULL, + -1,reply_name->name,reply_name->name_type, + n->source, nb_flags,0,0,NULL,NULL, False, False, n->ip_flgs[0].ip, p->ip); } else diff --git a/source/nameservresp.c b/source/nameservresp.c index a4cda7cdfb5..9676776e81d 100644 --- a/source/nameservresp.c +++ b/source/nameservresp.c @@ -46,38 +46,29 @@ extern struct in_addr ipzero; response for a reg release received. samba has asked a WINS server if it could release a name. **************************************************************************/ -static void response_name_release(struct subnet_record *d, - struct packet_struct *p) +static void response_name_release(struct nmb_ip *data, struct nmb_name *name, + struct subnet_record *d) { - struct nmb_packet *nmb = &p->packet.nmb; - char *name = nmb->question.question_name.name; - int type = nmb->question.question_name.name_type; - DEBUG(4,("response name release received\n")); - if (nmb->header.rcode == 0 && nmb->answers->rdata) + if (data) { /* IMPORTANT: see expire_netbios_response_entries() */ - struct in_addr found_ip; - putip((char*)&found_ip,&nmb->answers->rdata[2]); - /* NOTE: we only release our own names at present */ - if (ismyip(found_ip)) + if (ismyip(data->ip)) { - name_unregister_work(d,name,type); + name_unregister_work(d, name->name, name->name_type); } else { DEBUG(2,("name release for different ip! %s %s\n", - inet_ntoa(found_ip), - namestr(&nmb->question.question_name))); + inet_ntoa(data->ip),namestr(name))); } } else { - DEBUG(2,("name release for %s rejected!\n", - namestr(&nmb->question.question_name))); + DEBUG(2,("name release for %s rejected!\n",namestr(name))); /* XXXX PANIC! what to do if it's one of samba's own names? */ @@ -91,34 +82,25 @@ static void response_name_release(struct subnet_record *d, /**************************************************************************** response for a reg request received **************************************************************************/ -static void response_name_reg(struct subnet_record *d, struct packet_struct *p) +static void response_name_reg(struct nmb_ip *data, struct nmb_name *name, + time_t ttl, BOOL bcast, struct in_addr source_ip, + struct subnet_record *d, enum name_source source, int token) { - struct nmb_packet *nmb = &p->packet.nmb; - char *name = nmb->question.question_name.name; - int type = nmb->question.question_name.name_type; - BOOL bcast = nmb->header.nm_flags.bcast; - DEBUG(4,("response name registration received!\n")); - if (nmb->header.rcode == 0 && nmb->answers->rdata) + if (data) { /* IMPORTANT: see expire_netbios_response_entries() */ - int nb_flags = nmb->answers->rdata[0]; - int ttl = nmb->answers->ttl; - struct in_addr found_ip; - - putip((char*)&found_ip,&nmb->answers->rdata[2]); - - name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast); + name_register_work(d, token, name->name,name->name_type, + source, data, ttl, source_ip, bcast); } else { - DEBUG(1,("name registration for %s rejected!\n", - namestr(&nmb->question.question_name))); + DEBUG(1,("name registration for %s rejected!\n", namestr(name))); - /* oh dear. we have problems. possibly unbecome a master browser. */ - name_unregister_work(d,name,type); + /* oh dear. we have problems. possibly unbecome a master browser. */ + name_unregister_work(d,name->name,name->name_type); } } @@ -127,58 +109,56 @@ static void response_name_reg(struct subnet_record *d, struct packet_struct *p) response from a name query announce host NAME_QUERY_ANNOUNCE_HOST is dealt with here ****************************************************************************/ -static void response_announce_host(struct nmb_name *ans_name, - struct nmb_packet *nmb, - struct response_record *n, struct subnet_record *d) +static void response_announce_host(struct nmb_ip *data, + struct nmb_name *ans_name, + struct response_record *n, struct subnet_record *d) { - DEBUG(4, ("Name query at %s ip %s - ", - namestr(&n->name), inet_ntoa(n->send_ip))); - - if (!name_equal(&n->name, ans_name)) - { - /* someone gave us the wrong name as a reply. oops. */ - /* XXXX should say to them 'oi! release that name!' */ - - DEBUG(4,("unexpected name received: %s\n", namestr(ans_name))); - return; - } - - if (nmb->header.rcode == 0 && nmb->answers->rdata) - { - /* we had sent out a name query to the current owner - of a name because someone else wanted it. now they - have responded saying that they still want the name, - so the other host can't have it. - */ - - /* first check all the details are correct */ - - int nb_flags = nmb->answers->rdata[0]; - struct in_addr found_ip; - - putip((char*)&found_ip,&nmb->answers->rdata[2]); - - if (nb_flags != n->nb_flags) - { - /* someone gave us the wrong nb_flags as a reply. oops. */ - /* XXXX should say to them 'oi! release that name!' */ - - DEBUG(4,("expected nb_flags: %d\n", n->nb_flags)); - DEBUG(4,("unexpected nb_flags: %d\n", nb_flags)); - return; - } - - /* do an announce host */ - do_announce_host(ANN_HostAnnouncement, - n->my_name , 0x00, d->myip, - n->name.name, 0x1d, found_ip, - n->ttl, - n->my_name, n->server_type, n->my_comment); - } - else - { - /* XXXX negative name query response. no master exists. oops */ - } + DEBUG(4, ("Name query at %s ip %s - ", + namestr(&n->name), inet_ntoa(n->send_ip))); + + if (!name_equal(&n->name, ans_name)) + { + /* someone gave us the wrong name as a reply. oops. */ + /* XXXX should say to them 'oi! release that name!' */ + + DEBUG(4,("unexpected name received: %s\n", namestr(ans_name))); + return; + } + + if (data) + { + /* we had sent out a name query to the current owner + of a name because someone else wanted it. now they + have responded saying that they still want the name, + so the other host can't have it. + */ + + /* first check all the details are correct */ + + if (data->nb_flags != n->reply.nb_flags) + { + /* someone gave us the wrong nb_flags as a reply. oops. */ + /* XXXX should say to them 'oi! release that name!' */ + + DEBUG(4,("expected nb_flags: %d\n", n->reply.nb_flags)); + DEBUG(4,("unexpected nb_flags: %d\n", data->nb_flags)); + return; + } + + /* do an announce host */ + do_announce_host(ANN_HostAnnouncement, + n->my_name , 0x00, d->myip, + n->name.name, 0x1d, data->ip, + n->ttl, + n->my_name, n->server_type, + HOST_MAJOR_VERSION, HOST_MINOR_VERSION, + HOST_BROWSE_VERSION, HOST_BROWSE_SIGNATURE, + n->my_comment); + } + else + { + /* XXXX negative name query response. no master exists. oops */ + } } @@ -187,18 +167,18 @@ static void response_announce_host(struct nmb_name *ans_name, NAME_QUERY_SRV_CHK, and NAME_QUERY_FIND_MST dealt with here. ****************************************************************************/ static void response_server_check(struct nmb_name *ans_name, - struct response_record *n, struct subnet_record *d) + struct response_record *n, struct subnet_record *d) { /* issue another state: this time to do a name status check */ enum state_type cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ? - NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK; + NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK; /* initiate a name status check on the server that replied */ queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd, - ans_name->name, ans_name->name_type, - 0,0,0,NULL,NULL, - False,False,n->send_ip,n->reply_to_ip); + -1,ans_name->name, ans_name->name_type, + 0,0,0,0,NULL,NULL, + False,False,n->send_ip,n->reply.ip); } @@ -208,8 +188,8 @@ static void response_server_check(struct nmb_name *ans_name, add all the names it finds into the namelist. ****************************************************************************/ static BOOL interpret_node_status(struct subnet_record *d, - char *p, struct nmb_name *name,int t, - char *serv_name, struct in_addr ip, BOOL bcast) + char *p, struct nmb_name *name,int t, + char *serv_name, struct in_addr ip, BOOL bcast) { int level = t==0x20 ? 4 : 0; int numnames = CVAL(p,0); @@ -252,44 +232,44 @@ static BOOL interpret_node_status(struct subnet_record *d, /* might as well update our namelist while we're at it */ if (add) - { - struct in_addr nameip; - enum name_source src; - - if (ismyip(ip)) { - nameip = ipzero; - src = SELF; - } else { - nameip = ip; - src = STATUS_QUERY; - } - add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast); - } + { + struct in_addr nameip; + enum name_source src; + + if (ismyip(ip)) { + nameip = ipzero; + src = SELF; + } else { + nameip = ip; + src = STATUS_QUERY; + } + add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast); + } /* we want the server name */ if (serv_name && !*serv_name && !group && t == 0) - { - StrnCpy(serv_name,qname,15); - serv_name[15] = 0; - } + { + StrnCpy(serv_name,qname,15); + serv_name[15] = 0; + } /* looking for a name and type? */ if (name && !found && (t == type)) - { - /* take a guess at some of the name types we're going to ask for. - evaluate whether they are group names or no... */ - if (((t == 0x1b || t == 0x1d ) && !group) || - ((t == 0x20 || t == 0x1c || t == 0x1e) && group)) - { - found = True; - make_nmb_name(name,qname,type,scope); - } - } + { + /* take a guess at some of the name types we're going to ask for. + evaluate whether they are group names or no... */ + if (((t == 0x1b || t == 0x1d ) && !group) || + ((t == 0x20 || t == 0x1c || t == 0x1e) && group)) + { + found = True; + make_nmb_name(name,qname,type,scope); + } + } DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags)); } DEBUG(level,("num_good_sends=%d num_good_receives=%d\n", - IVAL(p,20),IVAL(p,24))); + IVAL(p,20),IVAL(p,24))); return found; } @@ -299,28 +279,26 @@ static BOOL interpret_node_status(struct subnet_record *d, and NAME_STATUS_SRV_CHK dealt with here. ****************************************************************************/ static void response_name_status_check(struct in_addr ip, - struct nmb_packet *nmb, BOOL bcast, - struct response_record *n, struct subnet_record *d) + char *data, BOOL bcast, + struct response_record *n, struct subnet_record *d) { - /* NMB_STATUS arrives: contains workgroup name and server name required. + /* NMB_STATUS arrives: contains workgroup name and server name required. amongst other things. */ - struct nmb_name name; - fstring serv_name; - - if (interpret_node_status(d,nmb->answers->rdata, - &name,name.name_type,serv_name,ip,bcast)) - { - if (*serv_name) - { - sync_server(n->state,serv_name, - name.name,name.name_type, n->send_ip); - } - } - else - { - DEBUG(1,("No 0x1d name type in interpret_node_status()\n")); - } + struct nmb_name name; + fstring serv_name; + + if (interpret_node_status(d,data,&name,name.name_type,serv_name,ip,bcast)) + { + if (*serv_name) + { + sync_server(n->state,serv_name,name.name,name.name_type,n->send_ip); + } + } + else + { + DEBUG(1,("No 0x1d name type in interpret_node_status()\n")); + } } @@ -328,79 +306,74 @@ static void response_name_status_check(struct in_addr ip, response from a name query for secured WINS registration. a state of NAME_REGISTER_CHALLENGE is dealt with here. ****************************************************************************/ -static void response_name_query_register(struct nmb_packet *nmb, - struct nmb_name *ans_name, - struct response_record *n, struct subnet_record *d) +static void response_name_query_register(struct nmb_ip *data, + struct nmb_name *ans_name, + struct response_record *n, struct subnet_record *d) { - struct in_addr register_ip; - BOOL new_owner; - - DEBUG(4, ("Name query at %s ip %s - ", - namestr(&n->name), inet_ntoa(n->send_ip))); - - if (!name_equal(&n->name, ans_name)) - { - /* someone gave us the wrong name as a reply. oops. */ - /* XXXX should say to them 'oi! release that name!' */ - - DEBUG(4,("unexpected name received: %s\n", namestr(ans_name))); - return; - } - - if (nmb->header.rcode == 0 && nmb->answers->rdata) - { - /* we had sent out a name query to the current owner - of a name because someone else wanted it. now they - have responded saying that they still want the name, - so the other host can't have it. - */ - - /* first check all the details are correct */ - - int nb_flags = nmb->answers->rdata[0]; - struct in_addr found_ip; - - putip((char*)&found_ip,&nmb->answers->rdata[2]); - - if (nb_flags != n->nb_flags) - { - /* someone gave us the wrong nb_flags as a reply. oops. */ - /* XXXX should say to them 'oi! release that name!' */ - - DEBUG(4,("expected nb_flags: %d\n", n->nb_flags)); - DEBUG(4,("unexpected nb_flags: %d\n", nb_flags)); - return; - } - - if (!ip_equal(n->send_ip, found_ip)) - { - /* someone gave us the wrong ip as a reply. oops. */ - /* XXXX should say to them 'oi! release that name!' */ - - DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip))); - DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip))); - return; - } - - DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip))); - - /* fine: now tell the other host they can't have the name */ - register_ip = n->send_ip; - new_owner = False; - } - else - { - DEBUG(4, (" NEGATIVE RESPONSE!\n")); - - /* the owner didn't want the name: the other host can have it */ - register_ip = n->reply_to_ip; - new_owner = True; - } - - /* register the old or the new owners' ip */ - add_name_respond(d, n->fd, d->myip, n->response_id,&n->name,n->nb_flags, - GET_TTL(0), register_ip, - new_owner, n->reply_to_ip); + struct in_addr register_ip; + BOOL new_owner; + + DEBUG(4, ("Name query at %s ip %s - ", + namestr(&n->name), inet_ntoa(n->send_ip))); + + if (!name_equal(&n->name, ans_name)) + { + /* someone gave us the wrong name as a reply. oops. */ + /* XXXX should say to them 'oi! release that name!' */ + + DEBUG(4,("unexpected name received: %s\n", namestr(ans_name))); + return; + } + + if (data) + { + /* we had sent out a name query to the current owner + of a name because someone else wanted it. now they + have responded saying that they still want the name, + so the other host can't have it. + */ + + /* first check all the details are correct */ + + if (data->nb_flags != n->reply.nb_flags) + { + /* someone gave us the wrong nb_flags as a reply. oops. */ + /* XXXX should say to them 'oi! release that name!' */ + + DEBUG(4,("expected nb_flags: %d\n", n->reply.nb_flags)); + DEBUG(4,("unexpected nb_flags: %d\n", data->nb_flags)); + return; + } + + if (!ip_equal(n->send_ip, data->ip)) + { + /* someone gave us the wrong ip as a reply. oops. */ + /* XXXX should say to them 'oi! release that name!' */ + + DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip))); + DEBUG(4,("unexpected ip: %s\n", inet_ntoa(data->ip))); + return; + } + + DEBUG(4, (" OK: %s\n", inet_ntoa(data->ip))); + + /* fine: now tell the other host they can't have the name */ + register_ip = n->send_ip; + new_owner = False; + } + else + { + DEBUG(4, (" NEGATIVE RESPONSE!\n")); + + /* the owner didn't want the name: the other host can have it */ + register_ip = n->reply.ip; + new_owner = True; + } + + /* register the old or the new owners' ip */ + add_name_respond(d, n->fd, d->myip, n->response_id,&n->name, + n->reply.nb_flags, GET_TTL(0), register_ip, + new_owner, n->reply.ip); } @@ -408,73 +381,68 @@ static void response_name_query_register(struct nmb_packet *nmb, response from a name query to sync browse lists or to update our netbios entry. states of type NAME_QUERY_SYNC and NAME_QUERY_CONFIRM ****************************************************************************/ -static void response_name_query_sync(struct nmb_packet *nmb, - struct nmb_name *ans_name, BOOL bcast, - struct response_record *n, struct subnet_record *d) +static void response_name_query_sync(struct nmb_ip *data, + struct nmb_name *ans_name, BOOL bcast, + struct response_record *n, struct subnet_record *d) { - DEBUG(4, ("Name query at %s ip %s - ", - namestr(&n->name), inet_ntoa(n->send_ip))); - - if (!name_equal(&n->name, ans_name)) - { - /* someone gave us the wrong name as a reply. oops. */ - DEBUG(4,("unexpected name received: %s\n", namestr(ans_name))); - return; - } - - if (nmb->header.rcode == 0 && nmb->answers->rdata) - { - int nb_flags = nmb->answers->rdata[0]; - struct in_addr found_ip; - - putip((char*)&found_ip,&nmb->answers->rdata[2]); - - if (!ip_equal(n->send_ip, found_ip)) - { - /* someone gave us the wrong ip as a reply. oops. */ - DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip))); - DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip))); - return; - } - - DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip))); - - if (n->state == NAME_QUERY_SYNC_LOCAL || - n->state == NAME_QUERY_SYNC_REMOTE) - { - struct work_record *work = NULL; - if ((work = find_workgroupstruct(d, ans_name->name, False))) - { - BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL; - - /* the server is there: sync quick before it (possibly) dies! */ - sync_browse_lists(d, work, ans_name->name, ans_name->name_type, - found_ip, local_list_only); - } - } - else - { - /* update our netbios name list (re-register it if necessary) */ - add_netbios_entry(d, ans_name->name, ans_name->name_type, - nb_flags,GET_TTL(0),REGISTER, - found_ip,False,!bcast); - } - } - else - { - DEBUG(4, (" NEGATIVE RESPONSE!\n")); - - if (n->state == NAME_QUERY_CONFIRM) - { - /* XXXX remove_netbios_entry()? */ - /* lots of things we ought to do, here. if we get here, - then we're in a mess: our name database doesn't match - reality. sort it out + DEBUG(4, ("Name query at %s ip %s - ", + namestr(&n->name), inet_ntoa(n->send_ip))); + + if (!name_equal(&n->name, ans_name)) + { + /* someone gave us the wrong name as a reply. oops. */ + DEBUG(4,("unexpected name received: %s\n", namestr(ans_name))); + return; + } + + if (data) + { + if (!ip_equal(n->send_ip, data->ip)) + { + /* someone gave us the wrong ip as a reply. oops. */ + DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip))); + DEBUG(4,("unexpected ip: %s\n", inet_ntoa(data->ip))); + return; + } + + DEBUG(4, (" OK: %s\n", inet_ntoa(data->ip))); + + if (n->state == NAME_QUERY_SYNC_LOCAL || + n->state == NAME_QUERY_SYNC_REMOTE) + { + struct work_record *work = NULL; + if ((work = find_workgroupstruct(d, ans_name->name, False))) + { + BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL; + + /* the server is there: sync quick before it (possibly) dies! */ + sync_browse_lists(d, work, ans_name->name, ans_name->name_type, + data->ip, local_list_only); + } + } + else + { + /* update our netbios name list (re-register it if necessary) */ + add_netbios_entry(d, ans_name->name, ans_name->name_type, + data->nb_flags,GET_TTL(0),REGISTER, + data->ip,False,!bcast); + } + } + else + { + DEBUG(4, (" NEGATIVE RESPONSE!\n")); + + if (n->state == NAME_QUERY_CONFIRM) + { + /* XXXX remove_netbios_entry()? */ + /* lots of things we ought to do, here. if we get here, + then we're in a mess: our name database doesn't match + reality. sort it out */ - remove_netbios_name(d,n->name.name, n->name.name_type, - REGISTER,n->send_ip); - } - } + remove_netbios_name(d,n->name.name, n->name.name_type, + REGISTER,n->send_ip); + } + } } @@ -486,9 +454,9 @@ static void debug_rr_type(int rr_type) switch (rr_type) { case NMB_STATUS: DEBUG(3,("Name status ")); break; - case NMB_QUERY : DEBUG(3,("Name query ")); break; - case NMB_REG : DEBUG(3,("Name registration ")); break; - case NMB_REL : DEBUG(3,("Name release ")); break; + case NMB_QUERY : DEBUG(3,("Name query ")); break; + case NMB_REG : DEBUG(3,("Name registration ")); break; + case NMB_REL : DEBUG(3,("Name release ")); break; default : DEBUG(1,("wrong response packet type received")); break; } } @@ -528,7 +496,7 @@ void debug_state_type(int state) (responses for certain types of operations are only expected from one host) ****************************************************************************/ static BOOL response_problem_check(struct response_record *n, - struct nmb_packet *nmb, char *qname) + struct nmb_packet *nmb, char *qname) { switch (nmb->answers->rr_type) { @@ -556,21 +524,21 @@ static BOOL response_problem_check(struct response_record *n, { if (n->num_msgs > 1) { - if (nmb->header.rcode == 0 && nmb->answers->rdata) - { - int nb_flags = nmb->answers->rdata[0]; - - if ((!NAME_GROUP(nb_flags))) - { - /* oh dear. more than one person responded to a unique name. - there is either a network problem, a configuration problem - or a server is mis-behaving */ - - /* XXXX mark the name as in conflict, and then let the - person who just responded know that they must also mark it - as in conflict, and therefore must NOT use it. + if (nmb->header.rcode == 0 && nmb->answers->rdata) + { + int nb_flags = nmb->answers->rdata[0]; + + if ((!NAME_GROUP(nb_flags))) + { + /* oh dear. more than one person responded to a unique name. + there is either a network problem, a configuration problem + or a server is mis-behaving */ + + /* XXXX mark the name as in conflict, and then let the + person who just responded know that they must also mark it + as in conflict, and therefore must NOT use it. see rfc1001.txt 15.1.3.5 */ - + /* this may cause problems for some early versions of nmbd */ switch (n->state) @@ -580,35 +548,35 @@ static BOOL response_problem_check(struct response_record *n, /* query for ^1^2__MSBROWSE__^2^1 expect lots of responses */ return False; } - case NAME_QUERY_ANNOUNCE_HOST: - case NAME_QUERY_DOM_SRV_CHK: + case NAME_QUERY_ANNOUNCE_HOST: + case NAME_QUERY_DOM_SRV_CHK: case NAME_QUERY_SRV_CHK: case NAME_QUERY_MST_CHK: { - if (!strequal(qname,n->name.name)) - { - /* one subnet, one master browser per workgroup */ - /* XXXX force an election? */ - - DEBUG(3,("more than one master browser replied!\n")); - return True; - } + if (!strequal(qname,n->name.name)) + { + /* one subnet, one master browser per workgroup */ + /* XXXX force an election? */ + + DEBUG(3,("more than one master browser replied!\n")); + return True; + } break; } default: break; } DEBUG(3,("Unique Name conflict detected!\n")); - return True; - } - } - else - { + return True; + } + } + else + { /* we have received a negative reply, having already received at least one response (pos/neg). something's really wrong! */ - DEBUG(3,("wierd name query problem detected!\n")); - return True; - } + DEBUG(3,("wierd name query problem detected!\n")); + return True; + } } } } @@ -619,27 +587,30 @@ static BOOL response_problem_check(struct response_record *n, check that the response received is compatible with the response record ****************************************************************************/ static BOOL response_compatible(struct response_record *n, - struct nmb_packet *nmb) + struct nmb_packet *nmb) { switch (n->state) { case NAME_RELEASE: { - if (nmb->answers->rr_type != NMB_REL) - { - DEBUG(1,("Name release reply has wrong answer rr_type\n")); - return False; - } + if (nmb->answers->rr_type != NMB_REL) + { + DEBUG(1,("Name release reply has wrong answer rr_type\n")); + return False; + } break; } case NAME_REGISTER: { - if (nmb->answers->rr_type != NMB_REG) - { - DEBUG(1,("Name register reply has wrong answer rr_type\n")); - return False; - } +/* rfc1002.txt states that nmb->answers->rr_type must equal 0x20 */ +#if 0 + if (nmb->answers->rr_type != NMB_REG) + { + DEBUG(1,("Name register reply has wrong answer rr_type\n")); + return False; + } +#endif break; } @@ -653,29 +624,29 @@ static BOOL response_compatible(struct response_record *n, case NAME_QUERY_FIND_MST: case NAME_QUERY_MST_CHK: { - if (nmb->answers->rr_type != NMB_QUERY) - { - DEBUG(1,("Name query reply has wrong answer rr_type\n")); - return False; - } - break; + if (nmb->answers->rr_type != NMB_QUERY) + { + DEBUG(1,("Name query reply has wrong answer rr_type\n")); + return False; + } + break; } case NAME_STATUS_DOM_SRV_CHK: case NAME_STATUS_SRV_CHK: { - if (nmb->answers->rr_type != NMB_STATUS) - { - DEBUG(1,("Name status reply has wrong answer rr_type\n")); - return False; - } - break; + if (nmb->answers->rr_type != NMB_STATUS) + { + DEBUG(1,("Name status reply has wrong answer rr_type\n")); + return False; + } + break; } default: { - DEBUG(1,("unknown state type received in response_netbios_packet\n")); - return False; + DEBUG(1,("unknown state type received in response_netbios_packet\n")); + return False; } } return True; @@ -685,27 +656,62 @@ static BOOL response_compatible(struct response_record *n, /**************************************************************************** process the response packet received ****************************************************************************/ -static void response_process(struct subnet_record *d, struct packet_struct *p, - struct response_record *n, struct nmb_packet *nmb, - BOOL bcast, struct nmb_name *ans_name) +void response_process(struct in_addr ip, struct subnet_record *d, + struct response_record *n, + int rcode, char *nmb_data, struct nmb_name *q_name, + time_t ttl, BOOL bcast, struct nmb_name *ans_name) { switch (n->state) { case NAME_RELEASE: { - response_name_release(d, p); + struct nmb_ip found; + struct nmb_ip *data = NULL; + + if (rcode == 0 && nmb_data) + { + /* copy the netbios flags and the ip address out of the reply data */ + found.nb_flags = nmb_data[0]; + putip((char*)&found.ip,&nmb_data[2]); + + data = &found; + } + response_name_release(data, q_name, d); break; } case NAME_REGISTER: { - response_name_reg(d, p); + struct nmb_ip found; + struct nmb_ip *data = NULL; + + if (rcode == 0 && nmb_data) + { + /* copy the netbios flags and the ip address out of the reply data */ + found.nb_flags = nmb_data[0]; + putip((char*)&found.ip,&nmb_data[2]); + + data = &found; + } + + response_name_reg(data,ans_name,ttl,bcast,ip,d,n->source,n->token); break; } case NAME_REGISTER_CHALLENGE: { - response_name_query_register(nmb, ans_name, n, d); + struct nmb_ip found; + struct nmb_ip *data = NULL; + + if (rcode == 0 && nmb_data) + { + /* copy the netbios flags and the ip address out of the reply data */ + found.nb_flags = nmb_data[0]; + putip((char*)&found.ip,&nmb_data[2]); + + data = &found; + } + response_name_query_register(data, ans_name, n, d); break; } @@ -713,44 +719,66 @@ static void response_process(struct subnet_record *d, struct packet_struct *p, case NAME_QUERY_SRV_CHK: case NAME_QUERY_FIND_MST: { - response_server_check(ans_name, n, d); - break; + response_server_check(ans_name, n, d); + break; } case NAME_STATUS_DOM_SRV_CHK: case NAME_STATUS_SRV_CHK: { - response_name_status_check(p->ip, nmb, bcast, n, d); - break; + response_name_status_check(ip,nmb_data,bcast,n,d); + break; } case NAME_QUERY_ANNOUNCE_HOST: { - response_announce_host(ans_name, nmb, n, d); - break; + struct nmb_ip found; + struct nmb_ip *data = NULL; + + if (rcode == 0 && nmb_data) + { + /* copy the netbios flags and the ip address out of the reply data */ + found.nb_flags = nmb_data[0]; + putip((char*)&found.ip,&nmb_data[2]); + + data = &found; + } + response_announce_host(data, ans_name, n, d); + break; } case NAME_QUERY_CONFIRM: case NAME_QUERY_SYNC_LOCAL: case NAME_QUERY_SYNC_REMOTE: { - response_name_query_sync(nmb, ans_name, bcast, n, d); - break; + struct nmb_ip found; + struct nmb_ip *data = NULL; + + if (rcode == 0 && nmb_data) + { + /* copy the netbios flags and the ip address out of the reply data */ + found.nb_flags = nmb_data[0]; + putip((char*)&found.ip,&nmb_data[2]); + + data = &found; + } + response_name_query_sync(data,ans_name,bcast,n,d); + break; } case NAME_QUERY_MST_CHK: { - /* no action required here. it's when NO responses are received - that we need to do something. see expire_name_query_entries() */ - - DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n", - namestr(&n->name), inet_ntoa(n->send_ip))); - break; + /* no action required here. it's when NO responses are received + that we need to do something. see expire_name_query_entries() */ + + DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n", + namestr(&n->name), inet_ntoa(n->send_ip))); + break; } default: { - DEBUG(1,("unknown state type received in response_netbios_packet\n")); - break; + DEBUG(1,("unknown state type received in response_netbios_packet\n")); + break; } } } @@ -780,7 +808,9 @@ void response_netbios_packet(struct packet_struct *p) return; } - /* args wrong way round: spotted by ccm@shentel.net */ + DEBUG(4,("response packet received: %s %d\n", + inet_ntoa(p->ip),n->response_id)); + if (!same_net(d->bcast_ip, p->ip, d->mask_ip)) /* copes with WINS 'subnet' */ { DEBUG(2,("response from %s. ", inet_ntoa(p->ip))); @@ -792,13 +822,13 @@ void response_netbios_packet(struct packet_struct *p) { /* hm. the packet received was a response, but with no answer. wierd! */ DEBUG(2,("NMB packet response from %s (bcast=%s) - UNKNOWN\n", - inet_ntoa(p->ip), BOOLSTR(bcast))); + inet_ntoa(p->ip), BOOLSTR(bcast))); return; } ans_name = &nmb->answers->rr_name; DEBUG(3,("response for %s from %s (bcast=%s)\n", - namestr(ans_name), inet_ntoa(p->ip), BOOLSTR(bcast))); + namestr(ans_name), inet_ntoa(p->ip), BOOLSTR(bcast))); debug_rr_type(nmb->answers->rr_type); @@ -816,7 +846,13 @@ void response_netbios_packet(struct packet_struct *p) return; /* now deal with the current state */ - response_process(d, p, n, nmb, bcast, ans_name); + response_process(p->ip, d, n, + nmb->header.rcode, + nmb->answers->rdata, + question, + nmb->answers->ttl, bcast, ans_name); + + remove_response_record(d, n); } diff --git a/source/namework.c b/source/namework.c index 0380c1460af..630f3dea12a 100644 --- a/source/namework.c +++ b/source/namework.c @@ -23,6 +23,9 @@ 14 jan 96: lkcl@pires.co.uk added multiple workgroup domain master support + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. + */ #include "includes.h" @@ -30,41 +33,34 @@ extern int ClientNMB; extern int ClientDGRAM; -#define TEST_CODE /* want to debug unknown browse packets */ - extern int DEBUGLEVEL; extern pstring scope; extern BOOL CanRecurse; -extern pstring myname; - extern int ClientNMB; extern int ClientDGRAM; extern struct in_addr ipzero; -extern int workgroup_count; /* total number of workgroups we know about */ - /* this is our domain/workgroup/server database */ extern struct subnet_record *subnetlist; extern int updatecount; -/* backup request types: which servers are to be included */ -#define MASTER_TYPE (SV_TYPE_MASTER_BROWSER) -#define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL ) - extern time_t StartupTime; extern BOOL updatedlists; +extern pstring myname; + + /**************************************************************************** tell a server to become a backup browser state - 0x01 become backup instead of master - 0x02 remove all entries in browse list and become non-master - 0x04 stop master browser service altogether. NT ignores this **************************************************************************/ -void reset_server(char *name, int state, struct in_addr ip) +void reset_server(struct work_record *work, char *name, int state, struct in_addr ip) { char outbuf[20]; char *p; @@ -77,10 +73,10 @@ void reset_server(char *name, int state, struct in_addr ip) p += 2; DEBUG(2,("sending reset to %s %s of state %d\n", - name,inet_ntoa(ip),state)); + name,inet_ntoa(ip),state)); send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,name,0x20,0x1d,ip,*iface_ip(ip)); + conf_browsing_alias(work->token),name,0x20,0x1d,ip,*iface_ip(ip)); } @@ -99,47 +95,47 @@ void tell_become_backup(void) { struct work_record *work; for (work = d->workgrouplist; work; work = work->next) - { - struct server_record *s; - int num_servers = 0; - int num_backups = 0; - - for (s = work->serverlist; s; s = s->next) - { - if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; - - num_servers++; - - if (strequal(myname, s->serv.name)) continue; - - if (s->serv.type & SV_TYPE_BACKUP_BROWSER) { - num_backups++; - continue; - } - - if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue; - - if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue; - - DEBUG(3,("num servers: %d num backups: %d\n", - num_servers, num_backups)); - - /* make first server a backup server. thereafter make every - tenth server a backup server */ - if (num_backups != 0 && (num_servers+9) / num_backups > 10) - { - continue; - } - - DEBUG(2,("sending become backup to %s %s for %s\n", - s->serv.name, inet_ntoa(d->bcast_ip), - work->work_group)); - - /* type 11 request from MYNAME(20) to WG(1e) for SERVER */ - do_announce_request(s->serv.name, work->work_group, - ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip); - } - } + { + struct server_record *s; + int num_servers = 0; + int num_backups = 0; + + for (s = work->serverlist; s; s = s->next) + { + if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; + + num_servers++; + + if (strequal(conf_browsing_alias(work->token), s->serv.name)) continue; + + if (s->serv.type & SV_TYPE_BACKUP_BROWSER) { + num_backups++; + continue; + } + + if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue; + + if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue; + + DEBUG(3,("num servers: %d num backups: %d\n", + num_servers, num_backups)); + + /* make first server a backup server. thereafter make every + tenth server a backup server */ + if (num_backups != 0 && (num_servers+9) / num_backups > 10) + { + continue; + } + + DEBUG(2,("sending become backup to %s %s for %s\n", + s->serv.name, inet_ntoa(d->bcast_ip), + work->work_group)); + + /* type 11 request from conf_browsing_alias(work->token)(20) to WG(1e) for SERVER */ + do_announce_request(s->serv.name, s->serv.name, work->work_group, + ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip); + } + } } } @@ -150,8 +146,23 @@ void tell_become_backup(void) ******************************************************************/ BOOL same_context(struct dgram_packet *dgram) { - if (!strequal(dgram->dest_name .scope,scope )) return(True); - if ( strequal(dgram->source_name.name ,myname)) return(True); + if (!strequal(dgram->dest_name .scope,scope )) return True; + + return False; +} + + +/******************************************************************* + am I listening on a name. XXXX check the type of name as well. + ******************************************************************/ +BOOL listening_name(struct work_record *work, struct nmb_name *n) +{ + if (strequal(n->name,conf_browsing_alias(work->token)) || + strequal(n->name,work->work_group) || + strequal(n->name,MSBROWSE)) + { + return(True); + } return(False); } @@ -197,8 +208,8 @@ static void process_announce(struct packet_struct *p,uint16 command,char *buf) DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15])); DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n", - namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor, - servertype,browse_type,browse_sig,comment)); + namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor, + servertype,browse_type,browse_sig,comment)); name[15] = 0; @@ -213,7 +224,7 @@ static void process_announce(struct packet_struct *p,uint16 command,char *buf) dgram->dest_name.name_type != 0x1)) { DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n", - command, inet_ntoa(ip), namestr(&dgram->dest_name))); + command, inet_ntoa(ip), namestr(&dgram->dest_name))); return; } @@ -265,7 +276,7 @@ static void process_announce(struct packet_struct *p,uint16 command,char *buf) if (command == ANN_LocalMasterAnnouncement) { add_browser_entry(serv_name,dgram->dest_name.name_type, - work->work_group,30,ip,True); + work->work_group,30,ip,True); } } @@ -278,26 +289,40 @@ static void process_master_announce(struct packet_struct *p,char *buf) struct in_addr ip = dgram->header.source_ip; struct subnet_record *d = find_subnet(ip); struct subnet_record *mydomain = find_subnet(*iface_bcast(ip)); + char *to_name = dgram->dest_name.name; /* our primary name or an alias */ + char *name = buf; - struct work_record *work; + char *work_name; + int token; name[15] = 0; - DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip))); + DEBUG(3,("Master Announce from %s (%s)\n", name, inet_ntoa(ip))); if (same_context(dgram)) return; if (!d || !mydomain) return; - if (!lp_domain_master()) return; - - for (work = mydomain->workgrouplist; work; work = work->next) + token = conf_alias_to_token(to_name); + + if (token == -1) { - if (AM_MASTER(work)) - { - /* merge browse lists with them */ - add_browser_entry(name,0x1b, work->work_group,30,ip,True); - } + DEBUG(4, ("alias %s not known\n", to_name)); + return; } + + /* carry on only if we are a domain master under the server alias */ + if (!conf_should_domain_master(token)) return; + + /* Convert the server name by which the master browser + called this server to the workgroup name. */ + if ((work_name = conf_workgroup_name(token)) == (char*)NULL) + { + DEBUG(4, ("process_master_announce(): no alias for \"%s\"\n", to_name)); + return; + } + + /* merge browse lists with them */ + add_browser_entry(name, 0x1b, work_name,30,ip,True); } /******************************************************************* @@ -318,62 +343,44 @@ static void process_rcv_backup_list(struct packet_struct *p,char *buf) struct dgram_packet *dgram = &p->packet.dgram; struct in_addr ip = dgram->header.source_ip; int count = CVAL(buf,0); + unsigned int pick; uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */ char *buf1; DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n", - namestr(&dgram->dest_name), inet_ntoa(ip), - count, info)); + namestr(&dgram->dest_name), inet_ntoa(ip), + count, info)); if (same_context(dgram)) return; if (count <= 0) return; + pick = sys_random(count); + /* go through the list of servers attempting to sync browse lists */ for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count) { - struct in_addr back_ip; struct subnet_record *d; - DEBUG(4,("Searching for backup browser %s at %s...\n", - buf1, inet_ntoa(ip))); - - /* XXXX assume name is a DNS name NOT a netbios name. a more complete - approach is to use reply_name_query functionality to find the name */ + if (count != pick) continue; - back_ip = *interpret_addr2(buf1); - - if (zero_ip(back_ip)) - { - DEBUG(4,("Failed to find backup browser server using DNS\n")); - continue; - } + DEBUG(4,("Searching for backup browser %s...\n", buf1)); - DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip))); - DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n")); - - /* XXXX function needs work */ - continue; - - if ((d = find_subnet(back_ip))) - { - struct subnet_record *d1; - for (d1 = subnetlist; d1; d1 = d1->next) - { - struct work_record *work; - for (work = d1->workgrouplist; work; work = work->next) - { - if (work->token == 0 /* token */) - { - queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK, - work->work_group,0x1d, - 0,0,0,NULL,NULL, - False,False,back_ip,back_ip); - return; - } - } - } - } + if ((d = find_subnet(ip)) != NULL) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + if (work->token == 0 /* token */) + { + queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK, + work->token,work->work_group,0x1d, + 0,0,0,0,NULL,NULL, + False,False,ipzero,ipzero); + return; + } + } + } } } @@ -381,9 +388,9 @@ static void process_rcv_backup_list(struct packet_struct *p,char *buf) /**************************************************************************** send a backup list response. **************************************************************************/ -static void send_backup_list(char *work_name, struct nmb_name *src_name, - int token, uint32 info, - int name_type, struct in_addr ip) +static void send_backup_list(struct work_record *work, struct nmb_name *src_name, + int token, uint32 info, + int name_type, struct in_addr ip) { char outbuf[1024]; char *p, *countptr, *nameptr; @@ -391,8 +398,8 @@ static void send_backup_list(char *work_name, struct nmb_name *src_name, char *theirname = src_name->name; DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", - work_name, inet_ntoa(ip), - myname,0x0,theirname,0x0)); + work->work_group, inet_ntoa(ip), + conf_browsing_alias(work->token),0x0,theirname,0x0)); if (name_type == 0x1d) { @@ -424,62 +431,51 @@ static void send_backup_list(char *work_name, struct nmb_name *src_name, #if 0 - for (d = subnetlist; d; d = d->next) - { - struct work_record *work; + struct server_record *s; - for (work = d->workgrouplist; work; work = work->next) - { - struct server_record *s; - - if (!strequal(work->work_group, work_name)) continue; - - for (s = work->serverlist; s; s = s->next) - { - BOOL found = False; - char *n; - - if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; - - for (n = nameptr; n < p; n = skip_string(n, 1)) - { - if (strequal(n, s->serv.name)) found = True; - } - - if (found) continue; /* exclude names already added */ - - /* workgroup request: include all backup browsers in the list */ - /* domain request: include all domain members in the list */ - - if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) || - (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE))) - { - DEBUG(4, ("%s ", s->serv.name)); - - count++; - strcpy(p,s->serv.name); - strupper(p); - p = skip_string(p,1); - } - } - } + for (s = work->serverlist; s; s = s->next) + { + BOOL found = False; + char *n; + + if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; + + for (n = nameptr; n < p; n = skip_string(n, 1)) + { + if (strequal(n, s->serv.name)) found = True; + } + + if (found) continue; /* exclude names already added */ + + /* workgroup request: include all backup browsers in the list */ + /* domain request: include all domain members in the list */ + + if ((name_type == 0x1d && (s->serv.type & SV_TYPE_MASTER_BROWSER)) || + (name_type == 0x1b && (s->serv.type & SV_TYPE_DOMAIN_BROWSER))) + { + DEBUG(4, ("%s ", s->serv.name)); + + count++; + strcpy(p,s->serv.name); + strupper(p); + p = skip_string(p,1); + } } - #endif - count++; - strcpy(p,myname); - strupper(p); - p = skip_string(p,1); + count++; + strcpy(p,conf_browsing_alias(work->token)); + strupper(p); + p = skip_string(p,1); if (count == 0) - { + { DEBUG(4, ("none\n")); - } + } else - { + { DEBUG(4, (" - count %d\n", count)); - } + } CVAL(countptr, 0) = count; @@ -488,7 +484,7 @@ static void send_backup_list(char *work_name, struct nmb_name *src_name, debug_browse_data(outbuf, len); } send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,theirname,0x0,0x0,ip,*iface_ip(ip)); + conf_browsing_alias(work->token),theirname,0x0,0x0,ip,*iface_ip(ip)); } @@ -519,24 +515,24 @@ static void process_send_backup_list(struct packet_struct *p,char *buf) if (name_type != 0x1b && name_type != 0x1d) { DEBUG(0,("backup request to wrong type %d from %s\n", - name_type,inet_ntoa(ip))); + name_type,inet_ntoa(ip))); return; } for (d = subnetlist; d; d = d->next) { for (work = d->workgrouplist; work; work = work->next) - { - if (strequal(work->work_group, dgram->dest_name.name)) - { - DEBUG(2,("sending backup list to %s %s id=%x\n", - namestr(&dgram->dest_name),inet_ntoa(ip),info)); - - send_backup_list(work->work_group,&dgram->source_name, - token,info,name_type,ip); - return; - } - } + { + if (strequal(work->work_group, dgram->dest_name.name)) + { + DEBUG(2,("sending backup list to %s %s id=%x\n", + namestr(&dgram->dest_name),inet_ntoa(ip),info)); + + send_backup_list(work,&dgram->source_name, + token,info,name_type,ip); + return; + } + } } } @@ -556,23 +552,23 @@ static void process_reset_browser(struct packet_struct *p,char *buf) int state = CVAL(buf,0); DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n", - namestr(&dgram->dest_name), state)); + namestr(&dgram->dest_name), state)); /* stop being a master but still deal with being a backup browser */ if (state & 0x1) { struct subnet_record *d; for (d = subnetlist; d; d = d->next) - { - struct work_record *work; - for (work = d->workgrouplist; work; work = work->next) - { - if (AM_MASTER(work)) - { - become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER); - } - } - } + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + if (AM_MASTER(work)) + { + become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER); + } + } + } } /* XXXX documentation inconsistency: the above description does not @@ -581,21 +577,24 @@ static void process_reset_browser(struct packet_struct *p,char *buf) /* totally delete all servers and start afresh */ if (state & 0x2) + { + /* remove all workgroups (and their servers) from database */ + struct subnet_record *d; + for (d = subnetlist; d; d = d->next) { - struct subnet_record *d; - for (d = subnetlist; d; d = d->next) - { - struct work_record *work; - for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True)); - } - add_my_subnets(lp_workgroup()); + struct work_record *work; + for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True)); } + + /* add all known workgroups back into database */ + add_workgroups_to_subnets(); + } /* stop browsing altogether. i don't think this is a good idea! */ if (state & 0x4) - { + { DEBUG(1,("ignoring request to stop being a browser. sorry!\n")); - } + } } /******************************************************************* @@ -611,39 +610,43 @@ static void process_announce_request(struct packet_struct *p,char *buf) struct in_addr ip = dgram->header.source_ip; struct subnet_record *d = find_subnet(ip); int token = CVAL(buf,0); + int wg_token = 0; char *name = buf+1; - + char *samba_alias; + name[15] = 0; DEBUG(3,("Announce request from %s to %s token=0x%X\n", - name,namestr(&dgram->dest_name), token)); + name,namestr(&dgram->dest_name), token)); - if (strequal(dgram->source_name.name,myname)) return; - - /* XXXX BUG or FEATURE?: need to ensure that we are a member of - this workgroup before announcing, particularly as we only - respond on local interfaces anyway. + /* look up the index for this workgroup */ + wg_token = conf_workgroup_name_to_token(dgram->dest_name.name,myname); + if (wg_token == -1) return; - if (strequal(dgram->dest_name, lp_workgroup()) return; ??? - */ + /* check that samba is participating in this workgroup */ + if (!conf_should_workgroup_member(wg_token)) return; + + /* find samba's NetBIOS alias it operates under in this workgroup */ + if ((samba_alias = conf_browsing_alias(wg_token)) == (char*)NULL) return; + /* ignore announce requests from samba under its own alias. + this should no longer happen because code has been added to + discard packets from ourself. */ + if (strequal(dgram->source_name.name,samba_alias)) return; + if (!d) return; - for (work = d->workgrouplist; work; work = work->next) - { - /* XXXX BUG: the destination name type should also be checked, - not just the name. e.g if the name is WORKGROUP(0x1d) then - we should only respond if we own that name */ + /* XXXX BUG: the destination name type should also be checked, + not just the name. e.g if the name is WORKGROUP(0x1d) then + we should only respond if we own that name */ - if (strequal(dgram->dest_name.name,work->work_group)) - { - work->needannounce = True; - } - } + for (work = d->workgrouplist; work; work = work->next) + { + if (wg_token == work->token) work->needannounce = True; + } } - /**************************************************************************** process a browse frame ****************************************************************************/ @@ -657,27 +660,27 @@ void process_browse_packet(struct packet_struct *p,char *buf,int len) case ANN_LocalMasterAnnouncement: { debug_browse_data(buf, len); - process_announce(p,command,buf+1); - break; + process_announce(p,command,buf+1); + break; } case ANN_AnnouncementRequest: { - process_announce_request(p,buf+1); - break; + process_announce_request(p,buf+1); + break; } case ANN_Election: { - process_election(p,buf+1); - break; + process_election(p,buf+1); + break; } case ANN_GetBackupListReq: { debug_browse_data(buf, len); - process_send_backup_list(p,buf+1); - break; + process_send_backup_list(p,buf+1); + break; } case ANN_GetBackupListResp: @@ -689,22 +692,22 @@ void process_browse_packet(struct packet_struct *p,char *buf,int len) case ANN_ResetBrowserState: { - process_reset_browser(p, buf+1); - break; + process_reset_browser(p, buf+1); + break; } case ANN_MasterAnnouncement: { - process_master_announce(p,buf+1); - break; + process_master_announce(p,buf+1); + break; } default: { - struct dgram_packet *dgram = &p->packet.dgram; - DEBUG(4,("ignoring browse packet %d from %s %s to %s\n", - command, namestr(&dgram->source_name), - inet_ntoa(p->ip), namestr(&dgram->dest_name))); + struct dgram_packet *dgram = &p->packet.dgram; + DEBUG(4,("ignoring browse packet %d from %s %s to %s\n", + command, namestr(&dgram->source_name), + inet_ntoa(p->ip), namestr(&dgram->dest_name))); } } } diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c index 5b3fd19491d..54f4254d51d 100644 --- a/source/nmbd/nmbd.c +++ b/source/nmbd/nmbd.c @@ -23,6 +23,10 @@ 14 jan 96: lkcl@pires.co.uk added multiple workgroup domain master support + + 30 July 96: David.Chappell@mail.trincoll.edu + Expanded multiple workgroup domain master browser support. + */ #include "includes.h" @@ -165,10 +169,10 @@ static void expire_names_and_servers(void) time_t t = time(NULL); if (!lastrun) lastrun = t; - if (t < lastrun + 5) return; + if (t < lastrun + 15) return; /* give samba time to check its names */ lastrun = t; - expire_names(t); + check_expire_names(t); /* this checks samba's NetBIOS names */ expire_servers(t); } @@ -187,10 +191,10 @@ BOOL reload_services(BOOL test) pstring fname; strcpy(fname,lp_configfile()); if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) - { - strcpy(servicesf,fname); - test = False; - } + { + strcpy(servicesf,fname); + test = False; + } } if (test && !lp_file_list_changed()) @@ -251,32 +255,32 @@ static void load_hosts_file(char *fname) if (count <= 0) continue; if (count > 0 && count < 2) { - DEBUG(0,("Ill formed hosts line [%s]\n",line)); - continue; + DEBUG(0,("Ill formed hosts line [%s]\n",line)); + continue; } if (count >= 4) { - DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname)); - continue; + DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname)); + continue; } DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags)); if (strchr(flags,'G') || strchr(flags,'S')) { - DEBUG(0,("group flag in %s ignored (obsolete)\n",fname)); - continue; + DEBUG(0,("group flag in %s ignored (obsolete)\n",fname)); + continue; } if (strchr(flags,'M')) { - source = SELF; - strcpy(myname,name); + source = SELF; + strcpy(myname,name); } ipaddr = *interpret_addr2(ip); d = find_subnet(ipaddr); if (d) { - add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True); - add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True); + add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True); + add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True); } } @@ -292,8 +296,7 @@ static void process(void) BOOL run_election; while (True) - { - time_t t = time(NULL); + { run_election = check_elections(); listen_for_packets(run_election); @@ -310,12 +313,11 @@ static void process(void) expire_names_and_servers(); expire_netbios_response_entries(); - refresh_my_names(t); write_browse_list(); do_browser_lists(); check_master_browser(); - } + } } @@ -435,50 +437,50 @@ static void usage(char *pname) while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF) { switch (opt) - { - case 's': - strcpy(servicesf,optarg); - break; - case 'N': - case 'B': - case 'I': - case 'C': - case 'G': - DEBUG(0,("Obsolete option '%c' used\n",opt)); - break; - case 'H': - strcpy(host_file,optarg); - break; - case 'n': - strcpy(myname,optarg); - strupper(myname); - break; - case 'l': - sprintf(debugf,"%s.nmb",optarg); - break; - case 'i': - strcpy(scope,optarg); - strupper(scope); - break; - case 'D': - is_daemon = True; - break; - case 'd': - DEBUGLEVEL = atoi(optarg); - break; - case 'p': - port = atoi(optarg); - break; - case 'h': - usage(argv[0]); - exit(0); - break; - default: - if (!is_a_socket(0)) { - usage(argv[0]); - } - break; - } + { + case 's': + strcpy(servicesf,optarg); + break; + case 'N': + case 'B': + case 'I': + case 'C': + case 'G': + DEBUG(0,("Obsolete option '%c' used\n",opt)); + break; + case 'H': + strcpy(host_file,optarg); + break; + case 'n': + strcpy(myname,optarg); + strupper(myname); + break; + case 'l': + sprintf(debugf,"%s.nmb",optarg); + break; + case 'i': + strcpy(scope,optarg); + strupper(scope); + break; + case 'D': + is_daemon = True; + break; + case 'd': + DEBUGLEVEL = atoi(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case 'h': + usage(argv[0]); + exit(0); + break; + default: + if (!is_a_socket(0)) { + usage(argv[0]); + } + break; + } } DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION)); @@ -487,10 +489,18 @@ static void usage(char *pname) get_myname(myhostname,NULL); if (!reload_services(False)) - return(-1); - + return(-1); + init_structs(); + /* reads the smbbrowse.conf file. this is an alias mapping between + workgroups and samba NetBIOS aliases. samba can therefore be + a member of multiple workgroups, a local master browser of + multiple workgroups, or a domain master browser of multiple + workgroups, via each NetBIOS name alias. the aliases MUST + be unique for this to work. */ + read_smbbrowse_conf(myname); + reload_services(True); set_samba_nb_type(); @@ -520,7 +530,7 @@ static void usage(char *pname) DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n")); } - add_my_subnets(lp_workgroup()); + add_workgroups_to_subnets(); DEBUG(3,("Checked names\n")); diff --git a/source/nmbsync.c b/source/nmbsync.c index 2efb364bcae..5a4d93f1a00 100644 --- a/source/nmbsync.c +++ b/source/nmbsync.c @@ -48,7 +48,7 @@ fudge for getpass function ****************************************************************************/ char *getsmbpass(char *pass) { - return "dummy"; /* return anything: it should be ignored anyway */ + return "dummy"; /* return anything: it should be ignored anyway */ } /**************************************************************************** @@ -84,43 +84,46 @@ static BOOL add_info(struct subnet_record *d, struct work_record *work, int serv p = skip_string(p,1); if (cli_call_api(PTR_DIFF(p,param),0, 8,10000, - &rprcnt,&rdrcnt, param,NULL, - &rparam,&rdata)) + &rprcnt,&rdrcnt, param,NULL, + &rparam,&rdata)) { int res = SVAL(rparam,0); int converter=SVAL(rparam,2); int i; if (res == 0) - { - count=SVAL(rparam,4); - p = rdata; - - for (i = 0;i < count;i++, p += 26) - { - char *sname = p; - uint32 stype = IVAL(p,18); - int comment_offset = IVAL(p,22) & 0xFFFF; - char *cmnt = comment_offset?(rdata+comment_offset-converter):""; - - struct work_record *w = work; - - DEBUG(4, ("\t%-16.16s %08x %s\n", sname, stype, cmnt)); - - if (stype & SV_TYPE_DOMAIN_ENUM) - { - /* creates workgroup on remote subnet */ - if ((w = find_workgroupstruct(d,sname,True))) - { - announce_request(w, d->bcast_ip); - } - } - - if (w) - add_server_entry(d,w,sname,stype,lp_max_ttl(),cmnt,False); - } - } + { + count=SVAL(rparam,4); + p = rdata; + + for (i = 0;i < count;i++, p += 26) + { + char *sname = p; + uint32 stype = IVAL(p,18); + int comment_offset = IVAL(p,22) & 0xFFFF; + char *cmnt = comment_offset?(rdata+comment_offset-converter):""; + + struct work_record *w = work; + + DEBUG(4, ("\t%-16.16s %08x %s\n", sname, stype, cmnt)); + + if (stype & SV_TYPE_DOMAIN_ENUM) + { + /* creates workgroup on remote subnet */ + if ((w = find_workgroupstruct(d,sname,True))) + { + announce_request(w, d->bcast_ip); + } + } + + if (w) + { + add_server_entry(d,w,sname,stype & ~SV_TYPE_LOCAL_LIST_ONLY, + lp_max_ttl(),cmnt,False); + } + } } + } if (rparam) free(rparam); if (rdata) free(rdata); @@ -136,7 +139,7 @@ static BOOL add_info(struct subnet_record *d, struct work_record *work, int serv do a NetServerEnum and update our server and workgroup databases. ******************************************************************/ void sync_browse_lists(struct subnet_record *d, struct work_record *work, - char *name, int nm_type, struct in_addr ip, BOOL local) + char *name, int nm_type, struct in_addr ip, BOOL local) { uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0; @@ -151,7 +154,7 @@ void sync_browse_lists(struct subnet_record *d, struct work_record *work, got_pass = True; DEBUG(4,("sync browse lists with %s for %s %s\n", - work->work_group, name, inet_ntoa(ip))); + work->work_group, name, inet_ntoa(ip))); strcpy(workgroup,work->work_group); strcpy(desthost,name); @@ -170,11 +173,11 @@ void sync_browse_lists(struct subnet_record *d, struct work_record *work, if (cli_open_sockets(SMB_PORT)) { if (cli_send_login(NULL,NULL,True,True)) - { - add_info(d, work, local_type|SV_TYPE_DOMAIN_ENUM); - add_info(d, work, local_type|(SV_TYPE_ALL& + { + add_info(d, work, local_type|SV_TYPE_DOMAIN_ENUM); + add_info(d, work, local_type|(SV_TYPE_ALL& ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY))); - } + } close_sockets(); } diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 87209d1bb7c..2a76ce70f77 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -106,33 +106,34 @@ extern int coding_system; */ typedef struct { - char *szPrintcapname; - char *szLockDir; - char *szRootdir; + char *szAutoServices; + char *szCharacterSet; + char *szConfigFile; char *szDefaultService; char *szDfree; - char *szMsgCommand; + char *szDomainController; char *szHostsEquiv; - char *szServerString; - char *szAutoServices; - char *szPasswdProgram; - char *szPasswdChat; + char *szInterfaces; + char *szLockDir; char *szLogFile; - char *szConfigFile; - char *szSMBPasswdFile; + char *szLogonScript; + char *szMsgCommand; + char *szPasswdChat; + char *szPasswdProgram; char *szPasswordServer; + char *szPrintcapname; + char *szRemoteAnnounce; + char *szRootdir; + char *szServerComment; + char *szServerString; + char *szSmbrun; + char *szSMBPasswdFile; + char *szSocketAddress; char *szSocketOptions; - char *szValidChars; - char *szWorkGroup; - char *szDomainController; char *szUsernameMap; - char *szCharacterSet; - char *szLogonScript; - char *szSmbrun; + char *szValidChars; char *szWINSserver; - char *szInterfaces; - char *szRemoteAnnounce; - char *szSocketAddress; + char *szWorkGroup; int max_log_size; int mangled_stack; int max_xmit; @@ -152,6 +153,7 @@ typedef struct BOOL bWINSsupport; BOOL bWINSproxy; BOOL bPreferredMaster; + BOOL bLocalMaster; BOOL bDomainMaster; BOOL bDomainLogons; BOOL bEncryptPasswords; @@ -382,6 +384,7 @@ struct parm_struct {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL}, {"preload", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL}, {"auto services", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL}, + {"server comment", P_STRING, P_GLOBAL, &Globals.szServerComment, NULL}, {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL}, {"printcap name", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL}, {"printcap", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL}, @@ -425,6 +428,7 @@ struct parm_struct {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL}, {"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL}, {"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL}, + {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL}, {"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL}, {"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL}, {"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, NULL}, @@ -560,6 +564,9 @@ static void init_globals(void) string_set(&Globals.szSocketAddress, "0.0.0.0"); sprintf(s,"Samba %s",VERSION); string_set(&Globals.szServerString,s); + strcpy(s,"Samba %v"); /* samba comment */ + string_sub(s,"%v",VERSION); + string_set(&Globals.szServerComment,s); Globals.bLoadPrinters = True; Globals.bUseRhosts = False; Globals.max_packet = 65535; @@ -584,8 +591,9 @@ static void init_globals(void) Globals.bSyslogOnly = False; Globals.os_level = 0; Globals.max_ttl = 60*60*4; /* 2 hours default */ - Globals.bPreferredMaster = True; - Globals.bDomainMaster = False; + Globals.bPreferredMaster = True; /* force election on startup */ + Globals.bLocalMaster = True; /* master browser on local subnet */ + Globals.bDomainMaster = False; /* maintain wide area network browse list */ Globals.bDomainLogons = False; Globals.bBrowseList = True; Globals.bWINSsupport = True; @@ -724,6 +732,7 @@ FN_GLOBAL_STRING(lp_smbrun,&Globals.szSmbrun) FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile) FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile) FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString) +FN_GLOBAL_STRING(lp_server_comment,&Globals.szServerComment) FN_GLOBAL_STRING(lp_printcapname,&Globals.szPrintcapname) FN_GLOBAL_STRING(lp_lockdir,&Globals.szLockDir) FN_GLOBAL_STRING(lp_rootdir,&Globals.szRootdir) @@ -747,6 +756,7 @@ FN_GLOBAL_STRING(lp_socket_address,&Globals.szSocketAddress) FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport) FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy) +FN_GLOBAL_BOOL(lp_local_master,&Globals.bLocalMaster) FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster) FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons) FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster) diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c index dd9b9661ae8..580aa446b6a 100644 --- a/source/smbd/ipc.c +++ b/source/smbd/ipc.c @@ -439,7 +439,7 @@ static void PackDriverData(struct pack_desc* desc) } static int check_printq_info(struct pack_desc* desc, - int uLevel, const char* id1, const char* id2) + int uLevel, char *id1, const char* id2) { desc->subformat = NULL; switch( uLevel ) { @@ -812,10 +812,7 @@ static int get_server_info(uint32 servertype, if (!next_token(&ptr,s->name , NULL)) continue; if (!next_token(&ptr,stype , NULL)) continue; if (!next_token(&ptr,s->comment, NULL)) continue; - if (!next_token(&ptr,s->domain , NULL)) { - /* this allows us to cope with an old nmbd */ - strcpy(s->domain,lp_workgroup()); - } + if (!next_token(&ptr,s->domain , NULL)) continue; if (sscanf(stype,"%X",&s->type) != 1) { DEBUG(4,("r:host file ")); @@ -983,8 +980,22 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, if (strcmp(str1, "WrLehDz") == 0) { StrnCpy(domain, p, sizeof(fstring)-1); - } else { - StrnCpy(domain, lp_workgroup(), sizeof(fstring)-1); + } + else + { + /* a server will connect to us under one of samba's NetBIOS + name aliases, and by not giving us a domain name it + assumes we know which domain it's talking about. + do a look-up for the workgroup name against the name + the host connected to us as. + */ + + char *work_alias; + + work_alias = conf_alias_to_workgroup(local_machine); /* look-up */ + + if (work_alias) + StrnCpy(domain, work_alias, sizeof(fstring)-1); } if (lp_browse_list()) @@ -1349,7 +1360,7 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data, DEBUG(3,("Set password for <%s>\n",user)); - if (password_ok(user,pass1,strlen(pass1),NULL,False) && + if (password_ok(user,pass1,strlen(pass1),NULL) && chgpasswd(user,pass1,pass2)) { SSVAL(*rparam,0,NERR_Success); @@ -1668,9 +1679,19 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data, pstring comment; uint32 servertype=DFLT_SERVER_TYPE; + char *work_alias; + char domain[16]; + + work_alias = conf_alias_to_workgroup(local_machine); /* look-up */ + + if (work_alias) + StrnCpy(domain, work_alias, sizeof(fstring)-1); + else + *domain = 0; + strcpy(comment,lp_serverstring()); - if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) { + if ((count=get_server_info(SV_TYPE_ALL,&servers,domain))>0) { for (i=0;i= SEC_USER) { #if (GUEST_SESSSETUP == 0) @@ -452,7 +460,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) p = smb_buf(outbuf); strcpy(p,"Unix"); p = skip_string(p,1); strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1); - strcpy(p,lp_workgroup()); p = skip_string(p,1); + strcpy(p,domain); p = skip_string(p,1); set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False); /* perhaps grab OS version here?? */ } diff --git a/source/smbd/server.c b/source/smbd/server.c index 0e0a524f166..4aaab4c087b 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -3746,6 +3746,8 @@ static void usage(char *pname) DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir())); } + read_smbbrowse_conf(myhostname); + process(); close_sockets(); diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c index d418814a69b..c137b4f93ac 100644 --- a/source/utils/nmblookup.c +++ b/source/utils/nmblookup.c @@ -100,6 +100,7 @@ int main(int argc,char *argv[]) BOOL find_master=False; BOOL find_status=False; int i; + static pstring servicesf = CONFIGFILE; DEBUGLEVEL = 1; *lookup = 0; @@ -110,7 +111,7 @@ int main(int argc,char *argv[]) charset_initialise(); - while ((opt = getopt(argc, argv, "p:d:B:i:SMh")) != EOF) + while ((opt = getopt(argc, argv, "p:d:B:i:s:SMh")) != EOF) switch (opt) { case 'B': @@ -129,6 +130,9 @@ int main(int argc,char *argv[]) case 'd': DEBUGLEVEL = atoi(optarg); break; + case 's': + strcpy(servicesf, optarg); + break; case 'h': usage(); exit(0); @@ -143,6 +147,11 @@ int main(int argc,char *argv[]) exit(1); } + if (!lp_load(servicesf,True)) { + fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf); + return (-1); + } + load_interfaces(); init_structs(); if (!open_sockets()) return(1); -- 2.34.1