summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/include/nameserv.h109
-rw-r--r--source/include/proto.h659
-rw-r--r--source/include/smb.h9
-rw-r--r--source/nameannounce.c196
-rw-r--r--source/namedb.c165
-rw-r--r--source/nameelect.c67
-rw-r--r--source/nameresp.c384
-rw-r--r--source/nameserv.c1169
-rw-r--r--source/namework.c118
-rw-r--r--source/nmbd/nmbd.c29
-rw-r--r--source/nmbsync.c10
-rw-r--r--source/param/loadparm.c3
-rw-r--r--source/script/mkproto.awk5
-rw-r--r--source/utils/nmblookup.c2
14 files changed, 2320 insertions, 605 deletions
diff --git a/source/include/nameserv.h b/source/include/nameserv.h
index 8882948ff4c..03bb5215586 100644
--- a/source/include/nameserv.h
+++ b/source/include/nameserv.h
@@ -29,8 +29,12 @@
#define NMB_QUERY 0x20
#define NMB_STATUS 0x21
-#define NMB_REG 0x05
-#define NMB_REL 0x06
+
+#define NMB_REG 0x05 /* see rfc1002.txt 4.2.2,3,5,6,7,8 */
+#define NMB_REG_REFRESH 0x09 /* see rfc1002.txt 4.2.4 */
+#define NMB_REL 0x06 /* see rfc1002.txt 4.2.9,10,11 */
+#define NMB_WAIT_ACK 0x07 /* see rfc1002.txt 4.2.17 */
+/* XXXX what about all the other types?? 0x1, 0x2, 0x3, 0x4, 0x8? */
#define NB_GROUP 0x80
#define NB_PERM 0x02
@@ -44,6 +48,8 @@
#define NB_FLGMSK 0x60
#define REFRESH_TIME (15*60)
+#define NAME_POLL_REFRESH_TIME (5*60)
+#define NAME_POLL_INTERVAL 15
#define NAME_PERMANENT(p) ((p) & NB_PERM)
#define NAME_ACTIVE(p) ((p) & NB_ACTIVE)
@@ -58,7 +64,6 @@
#define MSBROWSE "\001\002__MSBROWSE__\002"
-enum name_search { FIND_SELF, FIND_GLOBAL };
enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
@@ -66,13 +71,14 @@ enum cmd_type
{
NAME_STATUS_MASTER_CHECK,
NAME_STATUS_CHECK,
- MASTER_SERVER_CHECK,
- SERVER_CHECK,
- FIND_MASTER,
- CHECK_MASTER,
NAME_REGISTER,
NAME_RELEASE,
- NAME_CONFIRM_QUERY
+ NAME_QUERY_CONFIRM,
+ NAME_QUERY_SYNC,
+ NAME_QUERY_MST_SRV_CHK,
+ NAME_QUERY_SRV_CHK,
+ NAME_QUERY_FIND_MST,
+ NAME_QUERY_MST_CHK
};
/* a netbios name structure */
@@ -87,11 +93,15 @@ struct name_record
{
struct name_record *next;
struct name_record *prev;
- struct nmb_name name;
- time_t death_time;
- struct in_addr ip;
- int nb_flags;
- enum name_source source;
+
+ struct nmb_name name; /* the netbios name */
+ struct in_addr ip; /* ip address of host that owns this name */
+ int nb_flags; /* netbios flags */
+
+ enum name_source source; /* where the name came from */
+
+ time_t death_time; /* time record must be removed (do not remove if 0) */
+ time_t refresh_time; /* time record should be refreshed */
};
/* browse and backup server cache for synchronising browse list */
@@ -144,13 +154,63 @@ struct work_record
uint32 ElectionCriterion;
};
-/* a subnet structure. it contains a list of workgroups */
+/* initiated name queries recorded in this list to track any responses... */
+struct response_record
+{
+ struct response_record *next;
+ struct response_record *prev;
+
+ uint16 response_id;
+ enum cmd_type cmd_type;
+
+ int fd;
+ int quest_type;
+ struct nmb_name name;
+ int nb_flags;
+ time_t ttl;
+
+ BOOL bcast;
+ BOOL recurse;
+ struct in_addr to_ip;
+
+ int num_msgs;
+
+ time_t repeat_time;
+ time_t repeat_interval;
+ int repeat_count;
+};
+
+/* a subnet structure. it contains a list of workgroups and netbios names*/
+
+/* note that a subnet of 255.255.255.255 contains all the WINS netbios names.
+ all communication from such nodes are on a non-broadcast basis: they
+ are point-to-point (P nodes) or mixed point-to-point and broadcast
+ (M nodes). M nodes use point-to-point as a preference, and will use
+ broadcasting for certain activities, or will resort to broadcasting as a
+ last resort, if the WINS server fails (users of wfwg will notice that their
+ machine often freezes for 30 seconds at a time intermittently, if the WINS
+ server is down).
+
+ B nodes will have their own, totally separate subnet record, with their
+ own netbios name set. these do NOT interact with other subnet records'
+ netbios names, INCLUDING the WINS one (with an ip "address", so called,
+ of 255.255.255.255)
+
+ there is a separate response list for each subnet record. in the case of
+ the 255.255.255.255 subnet record (WINS), the WINS server will be able to
+ use this to poll (infrequently!) each of its entries, to ensure that the
+ names are still in use.
+ XXXX this polling is a planned feature for a really over-cautious WINS server
+*/
+
struct subnet_record
{
struct subnet_record *next;
struct subnet_record *prev;
- struct work_record *workgrouplist;
+ struct work_record *workgrouplist; /* list of workgroups */
+ struct name_record *namelist; /* list of netbios names */
+ struct response_record *responselist; /* list of responses expected */
struct in_addr bcast_ip;
struct in_addr mask_ip;
@@ -202,25 +262,6 @@ struct nmb_packet
};
-/* initiated name queries recorded in this list to track any responses... */
-struct name_response_record
-{
- struct name_response_record *next;
- struct name_response_record *prev;
-
- uint16 response_id;
- enum cmd_type cmd_type;
-
- int fd;
- struct nmb_name name;
- BOOL bcast;
- BOOL recurse;
- struct in_addr to_ip;
-
- time_t start_time;
- int num_msgs;
-};
-
/* a datagram - this normally contains SMB data in the data[] array */
struct dgram_packet {
struct {
diff --git a/source/include/proto.h b/source/include/proto.h
index e69de29bb2d..ce02be129fe 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -0,0 +1,659 @@
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+BOOL check_access(int snum);
+BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
+BOOL fromhost(int sock,struct from_host *f);
+char *unix2dos_format(char *str,BOOL overwrite);
+char *dos2unix_format(char *str, BOOL overwrite);
+int interpret_character_set(char *str, int def);
+void charset_initialise(void);
+void add_char_string(char *s);
+BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence);
+BOOL chgpasswd(char *name,char *oldpass,char *newpass);
+BOOL chgpasswd(char *name,char *oldpass,char *newpass);
+void setup_pkt(char *outbuf);
+void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
+void cmd_help(void);
+BOOL reopen_connection(char *inbuf,char *outbuf);
+char *smb_errstr(char *inbuf);
+void cli_setup_pkt(char *outbuf);
+BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len,
+ int *param_len, char **data,char **param);
+BOOL cli_send_session_request(char *inbuf, char *outbuf);
+BOOL cli_send_login(char *inbuf, char *outbuf, BOOL start_session, BOOL use_setup);
+void cli_send_logout(void);
+BOOL cli_call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt,
+ int *rdrcnt, char *param,char *data, char **rparam,char **rdata);
+BOOL cli_send_trans_request(char *outbuf, int trans, char *name, int fid, int flags,
+ char *data,char *param,uint16 *setup, int ldata,int lparam,
+ int lsetup,int mdata,int mparam,int msetup);
+BOOL cli_open_sockets(int port);
+BOOL cli_reopen_connection(char *inbuf,char *outbuf);
+char *smb_errstr(char *inbuf);
+int strslashcmp(const char *s1, const char *s2);
+void cmd_block(void);
+void cmd_tarmode(void);
+void cmd_setmode(void);
+void cmd_tar(char *inbuf, char *outbuf);
+int process_tar(char *inbuf, char *outbuf);
+int clipfind(char **aret, int ret, char *tok);
+int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
+void init_dptrs(void);
+char *dptr_path(int key);
+char *dptr_wcard(int key);
+BOOL dptr_set_wcard(int key, char *wcard);
+BOOL dptr_set_attr(int key, uint16 attr);
+uint16 dptr_attr(int key);
+void dptr_close(int key);
+void dptr_closecnum(int cnum);
+void dptr_idlecnum(int cnum);
+void dptr_closepath(char *path,int pid);
+int dptr_create(int cnum,char *path, BOOL expect_close,int pid);
+BOOL dptr_fill(char *buf1,unsigned int key);
+BOOL dptr_zero(char *buf);
+void *dptr_fetch(char *buf,int *num);
+void *dptr_fetch_lanman2(char *params,int dptr_num);
+BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype);
+BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend);
+void *OpenDir(char *name);
+void CloseDir(void *p);
+char *ReadDirName(void *p);
+BOOL SeekDir(void *p,int pos);
+int TellDir(void *p);
+void DirCacheAdd(char *path,char *name,char *dname,int snum);
+char *DirCacheCheck(char *path,char *name,int snum);
+void DirCacheFlush(int snum);
+void fault_setup(void (*fn)());
+char *getsmbpass(char *prompt) ;
+void load_interfaces(void);
+void add_subnet_interfaces(void);
+void iface_set_default(char *ip,char *bcast,char *nmask);
+BOOL ismyip(struct in_addr ip);
+BOOL ismybcast(struct in_addr bcast);
+int iface_count(void);
+struct in_addr *iface_n_ip(int n);
+struct in_addr *iface_bcast(struct in_addr ip);
+struct in_addr *iface_nmask(struct in_addr ip);
+struct in_addr *iface_ip(struct in_addr ip);
+int reply_trans(char *inbuf,char *outbuf);
+int interpret_coding_system(char *str, int def);
+char *lp_string(char *s);
+char *lp_logfile(void);
+char *lp_smbrun(void);
+char *lp_configfile(void);
+char *lp_smb_passwd_file(void);
+char *lp_serverstring(void);
+char *lp_printcapname(void);
+char *lp_lockdir(void);
+char *lp_rootdir(void);
+char *lp_defaultservice(void);
+char *lp_msg_command(void);
+char *lp_dfree_command(void);
+char *lp_hosts_equiv(void);
+char *lp_auto_services(void);
+char *lp_passwd_program(void);
+char *lp_passwd_chat(void);
+char *lp_passwordserver(void);
+char *lp_workgroup(void);
+char *lp_domain_controller(void);
+char *lp_username_map(void);
+char *lp_character_set(void);
+char *lp_logon_script(void);
+char *lp_wins_server(void);
+char *lp_interfaces(void);
+char *lp_remote_interfaces(void);
+BOOL lp_wins_support(void);
+BOOL lp_wins_proxy(void);
+BOOL lp_domain_master(void);
+BOOL lp_domain_logons(void);
+BOOL lp_preferred_master(void);
+BOOL lp_load_printers(void);
+BOOL lp_use_rhosts(void);
+BOOL lp_getwdcache(void);
+BOOL lp_readprediction(void);
+BOOL lp_readbmpx(void);
+BOOL lp_readraw(void);
+BOOL lp_writeraw(void);
+BOOL lp_null_passwords(void);
+BOOL lp_strip_dot(void);
+BOOL lp_encrypted_passwords(void);
+BOOL lp_syslog_only(void);
+BOOL lp_browse_list(void);
+int lp_os_level(void);
+int lp_max_ttl(void);
+int lp_max_log_size(void);
+int lp_mangledstack(void);
+int lp_maxxmit(void);
+int lp_maxmux(void);
+int lp_maxpacket(void);
+int lp_keepalive(void);
+int lp_passwordlevel(void);
+int lp_readsize(void);
+int lp_deadtime(void);
+int lp_maxprotocol(void);
+int lp_security(void);
+int lp_printing(void);
+int lp_maxdisksize(void);
+int lp_lpqcachetime(void);
+int lp_syslog(void);
+char *lp_preexec(int );
+char *lp_postexec(int );
+char *lp_rootpreexec(int );
+char *lp_rootpostexec(int );
+char *lp_servicename(int );
+char *lp_pathname(int );
+char *lp_dontdescend(int );
+char *lp_username(int );
+char *lp_guestaccount(int );
+char *lp_invalid_users(int );
+char *lp_valid_users(int );
+char *lp_admin_users(int );
+char *lp_printcommand(int );
+char *lp_lpqcommand(int );
+char *lp_lprmcommand(int );
+char *lp_lppausecommand(int );
+char *lp_lpresumecommand(int );
+char *lp_printername(int );
+char *lp_hostsallow(int );
+char *lp_hostsdeny(int );
+char *lp_magicscript(int );
+char *lp_magicoutput(int );
+char *lp_comment(int );
+char *lp_force_user(int );
+char *lp_force_group(int );
+char *lp_readlist(int );
+char *lp_writelist(int );
+char *lp_volume(int );
+char *lp_mangled_map(int );
+BOOL lp_alternate_permissions(int );
+BOOL lp_revalidate(int );
+BOOL lp_casesensitive(int );
+BOOL lp_preservecase(int );
+BOOL lp_shortpreservecase(int );
+BOOL lp_casemangle(int );
+BOOL lp_status(int );
+BOOL lp_hide_dot_files(int );
+BOOL lp_browseable(int );
+BOOL lp_readonly(int );
+BOOL lp_no_set_dir(int );
+BOOL lp_guest_ok(int );
+BOOL lp_guest_only(int );
+BOOL lp_print_ok(int );
+BOOL lp_postscript(int );
+BOOL lp_map_hidden(int );
+BOOL lp_map_archive(int );
+BOOL lp_locking(int );
+BOOL lp_strict_locking(int );
+BOOL lp_share_modes(int );
+BOOL lp_onlyuser(int );
+BOOL lp_manglednames(int );
+BOOL lp_widelinks(int );
+BOOL lp_syncalways(int );
+BOOL lp_map_system(int );
+BOOL lp_delete_readonly(int );
+int lp_create_mode(int );
+int lp_max_connections(int );
+int lp_defaultcase(int );
+int lp_minprintspace(int );
+char lp_magicchar(int );
+BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir);
+int lp_add_service(char *pszService, int iDefaultService);
+BOOL lp_add_printer(char *pszPrintername, int iDefaultService);
+BOOL lp_file_list_changed(void);
+BOOL lp_snum_ok(int iService);
+BOOL lp_loaded(void);
+void lp_killunused(BOOL (*snumused)(int ));
+BOOL lp_load(char *pszFname,BOOL global_only);
+int lp_numservices(void);
+void lp_dump(void);
+int lp_servicenumber(char *pszServiceName);
+char *my_workgroup(void);
+char *volume_label(int snum);
+BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type);
+int file_lock(char *name,int timeout);
+void file_unlock(int fd);
+BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset);
+BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
+BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
+int get_share_mode_by_fnum(int cnum,int fnum,int *pid);
+int get_share_mode_byname(int cnum,char *fname,int *pid);
+int get_share_mode(int cnum,struct stat *sbuf,int *pid);
+void del_share_mode(int fnum);
+BOOL set_share_mode(int fnum,int mode);
+void clean_share_files(void);
+int str_checksum(char *s);
+BOOL is_8_3(char *fname);
+void create_mangled_stack(int size);
+BOOL check_mangled_stack(char *s);
+BOOL is_mangled(char *s);
+void mangle_name_83(char *s);
+BOOL name_map_mangle(char *OutName,BOOL need83,int snum);
+int reply_sends(char *inbuf,char *outbuf);
+int reply_sendstrt(char *inbuf,char *outbuf);
+int reply_sendtxt(char *inbuf,char *outbuf);
+int reply_sendend(char *inbuf,char *outbuf);
+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 announce_backup(void);
+void announce_host(void);
+void announce_master(void);
+struct work_record *remove_workgroup(struct subnet_record *d,
+ struct work_record *work);
+void expire_browse_cache(time_t t);
+struct work_record *find_workgroupstruct(struct subnet_record *d,
+ fstring name, BOOL add);
+struct subnet_record *find_subnet(struct in_addr source_ip);
+void dump_workgroups(void);
+struct subnet_record *add_subnet_entry(struct in_addr source_ip,
+ struct in_addr source_mask,
+ char *name, BOOL add, BOOL lmhosts);
+struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
+ time_t ttl, struct in_addr ip);
+void remove_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);
+void write_browse_list(void);
+void expire_servers(time_t t);
+void query_refresh_names(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);
+void become_nonmaster(struct subnet_record *d, struct work_record *work,
+ int remove_type);
+void run_elections(void);
+void process_election(struct packet_struct *p,char *buf);
+BOOL check_elections(void);
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)());
+BOOL name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, struct in_addr *ip,void (*fn)());
+void expire_netbios_response_entries(void);
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode,int opcode,BOOL recurse,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len);
+void queue_netbios_pkt_wins(struct subnet_record *d,
+ int fd,int quest_type,enum cmd_type cmd,
+ char *name,int name_type, int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse,struct in_addr to_ip);
+void queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum cmd_type cmd,char *name,
+ int name_type,int nb_flags,time_t ttl,
+ BOOL bcast,BOOL recurse, struct in_addr to_ip);
+struct response_record *find_response_record(struct subnet_record *d,
+ uint16 id);
+void queue_packet(struct packet_struct *packet);
+void run_packet_queue();
+void listen_for_packets(BOOL run_election);
+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);
+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);
+void remove_name(struct subnet_record *d, struct name_record *n);
+void dump_names(void);
+void remove_netbios_name(struct subnet_record *d, 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 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 do_announce_host(int command,
+ char *from, int from_type, struct in_addr from_ip,
+ char *to , int to_type , struct in_addr to_ip,
+ int update_count, time_t announce_interval,
+ char *server_name, int server_type, char *server_comment);
+void load_netbios_names(void);
+void add_my_names(void);
+void remove_my_names(void);
+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);
+void refresh_my_names(time_t t);
+void expire_names(time_t t);
+void response_name_release(struct subnet_record *d,struct packet_struct *p);
+void reply_name_release(struct packet_struct *p);
+void response_name_reg(struct subnet_record *d,struct packet_struct *p);
+void reply_name_reg(struct packet_struct *p);
+void reply_name_status(struct packet_struct *p);
+void reply_name_query(struct packet_struct *p);
+void process_nmb(struct packet_struct *p);
+void reset_server(char *name, int state, struct in_addr ip);
+void tell_become_backup(void);
+void do_browser_lists(void);
+void sync_server(enum cmd_type cmd, char *serv_name, char *work_name,
+ int name_type,
+ struct in_addr ip);
+void add_my_subnets(char *group);
+BOOL same_context(struct dgram_packet *dgram);
+BOOL listening_name(struct work_record *work, struct nmb_name *n);
+void process_logon_packet(struct packet_struct *p,char *buf,int len);
+BOOL listening_type(struct packet_struct *p, int command);
+void process_browse_packet(struct packet_struct *p,char *buf,int len);
+void process_dgram(struct packet_struct *p);
+BOOL reload_services(BOOL test);
+void debug_nmb_packet(struct packet_struct *p);
+char *namestr(struct nmb_name *n);
+void free_nmb_packet(struct nmb_packet *nmb);
+void free_packet(struct packet_struct *packet);
+struct packet_struct *read_packet(int fd,enum packet_type packet_type);
+void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope);
+BOOL send_packet(struct packet_struct *p);
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
+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 pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *));
+void generate_next_challenge(char *challenge);
+BOOL set_challenge(char *challenge);
+BOOL last_challenge(char *challenge);
+int valid_uid(int uid);
+user_struct *get_valid_user_struct(int uid);
+void invalidate_uid(int uid);
+char *validated_username(int vuid);
+void register_uid(int uid,int gid, char *name,BOOL guest);
+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 user_ok(char *user,int snum);
+BOOL authorise_login(int snum,char *user,char *password, int pwlen,
+ BOOL *guest,BOOL *force,int vuid);
+BOOL check_hosts_equiv(char *user);
+BOOL server_cryptkey(char *buf);
+BOOL server_validate(char *buf);
+BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
+void pcap_printer_fn(void (*fn)());
+int read_predict(int fd,int offset,char *buf,char **ptr,int num);
+void do_read_prediction();
+void invalidate_read_prediction(int fd);
+void lpq_reset(int snum);
+void print_file(int fnum);
+int get_printqueue(int snum,int cnum,print_queue_struct **queue,
+ print_status_struct *status);
+void del_printqueue(int cnum,int snum,int jobid);
+void status_printjob(int cnum,int snum,int jobid,int status);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+char *Strstr(char *s, char *p);
+time_t Mktime(struct tm *t);
+int InNetGr(char *group,char *host,char *user,char *dom);
+void *malloc_wrapped(int size,char *file,int line);
+void *realloc_wrapped(void *ptr,int size,char *file,int line);
+void free_wrapped(void *ptr,char *file,int line);
+void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line);
+int reply_special(char *inbuf,char *outbuf);
+int reply_tcon(char *inbuf,char *outbuf);
+int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_unknown(char *inbuf,char *outbuf);
+int reply_ioctl(char *inbuf,char *outbuf);
+int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_chkpth(char *inbuf,char *outbuf);
+int reply_getatr(char *inbuf,char *outbuf);
+int reply_setatr(char *inbuf,char *outbuf);
+int reply_dskattr(char *inbuf,char *outbuf);
+int reply_search(char *inbuf,char *outbuf);
+int reply_fclose(char *inbuf,char *outbuf);
+int reply_open(char *inbuf,char *outbuf);
+int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_mknew(char *inbuf,char *outbuf);
+int reply_ctemp(char *inbuf,char *outbuf);
+int reply_unlink(char *inbuf,char *outbuf);
+int reply_readbraw(char *inbuf, char *outbuf);
+int reply_lockread(char *inbuf,char *outbuf);
+int reply_read(char *inbuf,char *outbuf);
+int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebraw(char *inbuf,char *outbuf);
+int reply_writeunlock(char *inbuf,char *outbuf);
+int reply_write(char *inbuf,char *outbuf,int dum1,int dum2);
+int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_lseek(char *inbuf,char *outbuf);
+int reply_flush(char *inbuf,char *outbuf);
+int reply_exit(char *inbuf,char *outbuf);
+int reply_close(char *inbuf,char *outbuf);
+int reply_writeclose(char *inbuf,char *outbuf);
+int reply_lock(char *inbuf,char *outbuf);
+int reply_unlock(char *inbuf,char *outbuf);
+int reply_tdis(char *inbuf,char *outbuf);
+int reply_echo(char *inbuf,char *outbuf);
+int reply_printopen(char *inbuf,char *outbuf);
+int reply_printclose(char *inbuf,char *outbuf);
+int reply_printqueue(char *inbuf,char *outbuf);
+int reply_printwrite(char *inbuf,char *outbuf);
+int reply_mkdir(char *inbuf,char *outbuf);
+int reply_rmdir(char *inbuf,char *outbuf);
+int reply_mv(char *inbuf,char *outbuf);
+int reply_copy(char *inbuf,char *outbuf);
+int reply_setdir(char *inbuf,char *outbuf);
+int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebmpx(char *inbuf,char *outbuf);
+int reply_writebs(char *inbuf,char *outbuf);
+int reply_setattrE(char *inbuf,char *outbuf);
+int reply_getattrE(char *inbuf,char *outbuf);
+mode_t unix_mode(int cnum,int dosmode);
+int dos_mode(int cnum,char *path,struct stat *sbuf);
+int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st);
+BOOL unix_convert(char *name,int cnum);
+int disk_free(char *path,int *bsize,int *dfree,int *dsize);
+int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize);
+BOOL check_name(char *name,int cnum);
+void open_file(int fnum,int cnum,char *fname1,int flags,int mode);
+void sync_file(int fnum);
+void close_file(int fnum);
+BOOL check_file_sharing(int cnum,char *fname);
+void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
+ int mode,int *Access,int *action);
+int seek_file(int fnum,int pos);
+int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact);
+int write_file(int fnum,char *data,int n);
+BOOL become_service(int cnum,BOOL do_chdir);
+int find_service(char *service);
+int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line);
+int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line);
+int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line);
+BOOL snum_used(int snum);
+BOOL reload_services(BOOL test);
+int setup_groups(char *user, int uid, int gid, int *p_ngroups,
+ int **p_igroups, gid_t **p_groups);
+int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid);
+int find_free_file(void );
+int reply_corep(char *outbuf);
+int reply_coreplus(char *outbuf);
+int reply_lanman1(char *outbuf);
+int reply_lanman2(char *outbuf);
+int reply_nt1(char *outbuf);
+void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev);
+void close_cnum(int cnum, int uid);
+BOOL yield_connection(int cnum,char *name,int max_connections);
+BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear);
+void exit_server(char *reason);
+void standard_sub(int cnum,char *s);
+char *smb_fn_name(int type);
+int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize);
+int construct_reply(char *inbuf,char *outbuf,int size,int bufsize);
+void str_to_key(uchar *str,uchar *key);
+void D1(uchar *k, uchar *d, uchar *out);
+void E1(uchar *k, uchar *d, uchar *out);
+void E_P16(uchar *p14,uchar *p16);
+void E_P24(uchar *p21, uchar *c8, uchar *p24);
+void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24);
+void E_md4hash(uchar *passwd, uchar *p16);
+void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24);
+void Ucrit_addUsername(pstring username);
+unsigned int Ucrit_checkUsername(pstring username);
+void Ucrit_addPid(int pid);
+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);
+int sys_open(char *fname,int flags,int mode);
+DIR *sys_opendir(char *dname);
+int sys_stat(char *fname,struct stat *sbuf);
+int sys_lstat(char *fname,struct stat *sbuf);
+int sys_mkdir(char *dname,int mode);
+int sys_rmdir(char *dname);
+int sys_chdir(char *dname);
+int sys_utime(char *fname,struct utimbuf *times);
+int sys_rename(char *from, char *to);
+int sys_chown(char *fname,int uid,int gid);
+int sys_chroot(char *dname);
+int main(int argc, char *argv[]);
+void GetTimeOfDay(struct timeval *tval);
+void TimeInit(void);
+int TimeDiff(time_t t);
+struct tm *LocalTime(time_t *t);
+time_t interpret_long_date(char *p);
+void put_long_date(char *p,time_t t);
+void put_dos_date(char *buf,int offset,time_t unixdate);
+void put_dos_date2(char *buf,int offset,time_t unixdate);
+void put_dos_date3(char *buf,int offset,time_t unixdate);
+time_t make_unix_date(void *date_ptr);
+time_t make_unix_date2(void *date_ptr);
+time_t make_unix_date3(void *date_ptr);
+BOOL set_filetime(char *fname,time_t mtime);
+char *timestring(void );
+int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize);
+char *ufc_crypt(char *key,char *salt);
+void init_uid(void);
+BOOL become_guest(void);
+BOOL become_user(int cnum, int uid);
+BOOL unbecome_user(void );
+int smbrun(char *cmd,char *outfile);
+char *get_home_dir(char *user);
+void map_username(char *user);
+struct passwd *Get_Pwnam(char *user,BOOL allow_change);
+BOOL user_in_list(char *user,char *list);
+void setup_logging(char *pname,BOOL interactive);
+void reopen_logs(void);
+BOOL is_a_socket(int fd);
+BOOL next_token(char **ptr,char *buff,char *sep);
+char **toktocliplist(int *ctok, char *sep);
+void *MemMove(void *dest,void *src,int size);
+void array_promote(char *array,int elsize,int element);
+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);
+void putip(void *dest,void *src);
+int name_mangle(char *In,char *Out,char name_type);
+BOOL file_exist(char *fname,struct stat *sbuf);
+time_t file_modtime(char *fname);
+BOOL directory_exist(char *dname,struct stat *st);
+uint32 file_size(char *file_name);
+char *attrib_string(int mode);
+int StrCaseCmp(char *s, char *t);
+int StrnCaseCmp(char *s, char *t, int n);
+BOOL strequal(char *s1,char *s2);
+BOOL strnequal(char *s1,char *s2,int n);
+BOOL strcsequal(char *s1,char *s2);
+void strlower(char *s);
+void strupper(char *s);
+void strnorm(char *s);
+BOOL strisnormal(char *s);
+void string_replace(char *s,char oldc,char newc);
+void unix_format(char *fname);
+void dos_format(char *fname);
+void show_msg(char *buf);
+int smb_len(char *buf);
+void _smb_setlen(char *buf,int len);
+void smb_setlen(char *buf,int len);
+int set_message(char *buf,int num_words,int num_bytes,BOOL zero);
+int smb_numwords(char *buf);
+int smb_buflen(char *buf);
+int smb_buf_ofs(char *buf);
+char *smb_buf(char *buf);
+int smb_offset(char *p,char *buf);
+char *skip_string(char *buf,int n);
+BOOL trim_string(char *s,char *front,char *back);
+void dos_clean_name(char *s);
+void unix_clean_name(char *s);
+int ChDir(char *path);
+char *GetWd(char *str);
+BOOL reduce_name(char *s,char *dir,BOOL widelinks);
+void expand_mask(char *Mask,BOOL doext);
+BOOL strhasupper(char *s);
+BOOL strhaslower(char *s);
+int count_chars(char *s,char c);
+void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date);
+void close_low_fds(void);
+int write_socket(int fd,char *buf,int len);
+int read_udp_socket(int fd,char *buf,int len);
+int set_blocking(int fd, BOOL set);
+int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact);
+int read_max_udp(int fd,char *buffer,int bufsize,int maxtime);
+int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew);
+BOOL send_keepalive(int client);
+int read_data(int fd,char *buffer,int N);
+int write_data(int fd,char *buffer,int N);
+int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align);
+int read_smb_length(int fd,char *inbuf,int timeout);
+BOOL receive_smb(int fd,char *buffer,int timeout);
+BOOL send_smb(int fd,char *buffer);
+char *name_ptr(char *buf,int ofs);
+int name_extract(char *buf,int ofs,char *name);
+int name_len(char *s);
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type);
+void msleep(int t);
+BOOL in_list(char *s,char *list,BOOL casesensitive);
+BOOL string_init(char **dest,char *src);
+void string_free(char **s);
+BOOL string_set(char **dest,char *src);
+BOOL string_sub(char *s,char *pattern,char *insert);
+BOOL do_match(char *str, char *regexp, int case_sig);
+BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2);
+void become_daemon(void);
+BOOL yesno(char *p);
+char *fgets_slash(char *s2,int maxlen,FILE *f);
+int set_filelen(int fd, long len);
+int byte_checksum(char *buf,int len);
+char *dirname_dos(char *path,char *buf);
+void *Realloc(void *p,int size);
+void Abort(void );
+BOOL get_myname(char *myname,struct in_addr *ip);
+BOOL ip_equal(struct in_addr ip1,struct in_addr ip2);
+int open_socket_in(int type, int port, int dlevel);
+int open_socket_out(int type, struct in_addr *addr, int port );
+int interpret_protocol(char *str,int def);
+int interpret_security(char *str,int def);
+unsigned long interpret_addr(char *str);
+struct in_addr *interpret_addr2(char *str);
+BOOL zero_ip(struct in_addr ip);
+void standard_sub_basic(char *s);
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
+int PutUniCode(char *dst,char *src);
+struct hostent *Get_Hostbyname(char *name);
+BOOL process_exists(int pid);
+char *uidtoname(int uid);
+char *gidtoname(int gid);
+void BlockSignals(BOOL block);
+void ajt_panic(void);
+char *readdirname(void *p);
+int VT_Check(char *buffer);
+int VT_Start_utmp(void);
+int VT_Stop_utmp(void);
+void VT_AtExit(void);
+void VT_SigCLD(int sig);
+void VT_SigEXIT(int sig);
+int VT_Start(void);
+int VT_Output(char *Buffer);
+int VT_Input(char *Buffer,int Size);
+void VT_Process(void);
diff --git a/source/include/smb.h b/source/include/smb.h
index b9dd13a802b..0e9c9983d25 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -381,6 +381,15 @@ struct server_info_struct
};
+/* used for network interfaces */
+struct interface
+{
+ struct interface *next;
+ struct in_addr ip;
+ struct in_addr bcast;
+ struct in_addr nmask;
+};
+
/* this is used for smbstatus */
struct connect_record
{
diff --git a/source/nameannounce.c b/source/nameannounce.c
index 9b0ef7067f2..5163c4aea9a 100644
--- a/source/nameannounce.c
+++ b/source/nameannounce.c
@@ -122,7 +122,8 @@ void announce_backup(void)
int tok;
if (!lastrun) lastrun = t;
- if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60) return;
+ if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
+ return;
lastrun = t;
for (tok = 0; tok <= workgroup_count; tok++)
@@ -179,19 +180,102 @@ void announce_backup(void)
/****************************************************************************
+ 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,
+ int updatecount, time_t announce_interval,
+ char *server_name, int server_type, char *server_comment)
+{
+ pstring outbuf;
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf+1;
+
+ /* command type */
+ CVAL(outbuf,0) = command;
+
+ /* 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);
+
+ CVAL(p,21) = 2; /* major version */
+ CVAL(p,22) = 2; /* minor version */
+
+ SIVAL(p,23,server_type);
+ SSVAL(p,27,0xaa55); /* browse signature */
+ SSVAL(p,29,1); /* browse version */
+
+ strcpy(p+31,server_comment);
+ p += 31;
+ p = skip_string(p,1);
+
+ /* 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);
+}
+
+
+/****************************************************************************
+ 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)
+{
+ if (AM_MASTER(work))
+ {
+ DEBUG(3,("sending local master announce to %s for %s(1e)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_LocalMasterAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1e, d->bcast_ip,
+ updatecount, ttl*1000,
+ name, server_type, comment);
+
+ DEBUG(3,("sending domain announce to %s for %s\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ /* XXXX should we do a domain-announce-kill? */
+ if (server_type != 0)
+ {
+ do_announce_host(ANN_DomainAnnouncement,
+ work->work_group, 0x00, d->myip,
+ MSBROWSE , 0x01, d->bcast_ip,
+ updatecount, ttl*1000,
+ name, server_type ? SV_TYPE_DOMAIN_ENUM : 0, comment);
+ }
+ }
+ else
+ {
+ DEBUG(3,("sending host announce to %s for %s(1d)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_HostAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1d, d->bcast_ip,
+ updatecount, ttl*1000,
+ name, server_type, comment);
+ }
+}
+
+/****************************************************************************
construct a host announcement unicast
**************************************************************************/
void announce_host(void)
{
time_t t = time(NULL);
- pstring outbuf;
- char *p;
- char *namep;
- char *stypep;
- char *commentp;
+ struct subnet_record *d;
pstring comment;
char *my_name;
- struct subnet_record *d;
StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
@@ -225,9 +309,6 @@ void announce_host(void)
work->lastannounce_time = t;
- /* when announcing to remote networks we make sure we don't
- claim to be any sort of special server, otherwise we may
- stuff up their browsing */
if (!d->my_interface) {
stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
@@ -243,78 +324,15 @@ void announce_host(void)
if (announce)
{
- bzero(outbuf,sizeof(outbuf));
- p = outbuf+1;
-
- CVAL(p,0) = updatecount;
- /* ms - despite the spec */
- SIVAL(p,1,work->announce_interval*1000);
- namep = p+5;
- StrnCpy(namep,my_name,16);
- strupper(namep);
- CVAL(p,21) = 2; /* major version */
- CVAL(p,22) = 2; /* minor version */
- stypep = p+23;
- SIVAL(p,23,stype);
- SSVAL(p,27,0xaa55); /* browse signature */
- SSVAL(p,29,1); /* browse version */
- commentp = p+31;
- strcpy(commentp,comment);
- p = p+31;
- p = skip_string(p,1);
-
- if (d->my_interface && AM_MASTER(work))
- {
- SIVAL(stypep,0,work->ServerType);
-
- DEBUG(2,("sending local master announce to %s for %s\n",
- inet_ntoa(d->bcast_ip),work->work_group));
-
- CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
- PTR_DIFF(p,outbuf),
- my_name,work->work_group,0,
- 0x1e,d->bcast_ip,
- *iface_ip(d->bcast_ip));
-
- DEBUG(2,("sending domain announce to %s for %s\n",
- inet_ntoa(d->bcast_ip),work->work_group));
-
- CVAL(outbuf,0) = ANN_DomainAnnouncement;
-
- StrnCpy(namep,work->work_group,15);
- strupper(namep);
- StrnCpy(commentp,myname,15);
- strupper(commentp);
-
- SIVAL(stypep,0,(unsigned)0x80000000);
- p = commentp + strlen(commentp) + 1;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
- PTR_DIFF(p,outbuf),
- my_name,MSBROWSE,0,0x01,d->bcast_ip,
- *iface_ip(d->bcast_ip));
- }
- else
- {
- DEBUG(2,("sending host announce to %s for %s\n",
- inet_ntoa(d->bcast_ip),work->work_group));
-
- CVAL(outbuf,0) = ANN_HostAnnouncement;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
- PTR_DIFF(p,outbuf),
- my_name,work->work_group,0,0x1d,
- d->bcast_ip,*iface_ip(d->bcast_ip));
- }
+ 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)
+ {
+ work->needannounce = False;
+ break;
+ /* sorry: can't do too many announces. do some more later */
+ }
}
}
}
@@ -328,7 +346,7 @@ void announce_host(void)
least 15 minutes.
this actually gets done in search_and_sync_workgroups() via the
- MASTER_SERVER_CHECK command, if there is a response from the
+ NAME_QUERY_MST_SRV_CHK command, if there is a response from the
name query initiated here. see response_name_query()
**************************************************************************/
void announce_master(void)
@@ -382,9 +400,9 @@ void announce_master(void)
struct in_addr ip;
ip = ipzero;
- queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
- MASTER_SERVER_CHECK,
- work->work_group,0x1b,0,
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_MST_SRV_CHK,
+ work->work_group,0x1b,0,0,
False, False, ip);
}
else
@@ -392,9 +410,9 @@ void announce_master(void)
struct subnet_record *d2;
for (d2 = subnetlist; d2; d2 = d2->next)
{
- queue_netbios_packet(ClientNMB,NMB_QUERY,
- MASTER_SERVER_CHECK,
- work->work_group,0x1b,0,
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_MST_SRV_CHK,
+ work->work_group,0x1b,0,0,
True, False, d2->bcast_ip);
}
}
@@ -427,8 +445,8 @@ void announce_master(void)
/* 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(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
- work->work_group,0x1b, 0,
+ queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_MST_SRV_CHK,
+ work->work_group,0x1b, 0, 0,
bcast, False, ip);
}
}
diff --git a/source/namedb.c b/source/namedb.c
index ea5b13a8009..a1442c0f03b 100644
--- a/source/namedb.c
+++ b/source/namedb.c
@@ -38,10 +38,17 @@ extern pstring myname;
extern pstring scope;
extern struct in_addr ipgrp;
+extern struct in_addr ipzero;
/* this is our browse master/backup cache database */
struct browse_cache_record *browserlist = NULL;
+/* local interfaces structure */
+extern struct interface *local_interfaces;
+
+/* remote interfaces structure */
+extern struct interface *remote_interfaces;
+
/* this is our domain/workgroup/server database */
struct subnet_record *subnetlist = NULL;
@@ -317,8 +324,8 @@ struct work_record *find_workgroupstruct(struct subnet_record *d,
{
DEBUG(2,("add any workgroups: initiating browser search on %s\n",
inet_ntoa(d->bcast_ip)));
- queue_netbios_pkt_wins(ClientNMB,NMB_QUERY, FIND_MASTER,
- MSBROWSE,0x1,0,
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, NAME_QUERY_FIND_MST,
+ MSBROWSE,0x1,0,0,
True,False, d->bcast_ip);
return NULL;
}
@@ -339,8 +346,6 @@ struct work_record *find_workgroupstruct(struct subnet_record *d,
if ((work = make_workgroup(name)))
{
- work->needelection = False;
-
if (lp_preferred_master() &&
strequal(lp_workgroup(), name) &&
d->my_interface)
@@ -349,6 +354,10 @@ struct work_record *find_workgroupstruct(struct subnet_record *d,
work->needelection = True;
work->ElectionCriterion |= (1<<3);
}
+ if (!d->my_interface)
+ {
+ work->needelection = False;
+ }
add_workgroup(work, d);
return(work);
}
@@ -356,20 +365,31 @@ struct work_record *find_workgroupstruct(struct subnet_record *d,
}
/****************************************************************************
- find a domain in the subnetlist
+ find a subnet in the subnetlist
**************************************************************************/
-struct subnet_record *find_domain(struct in_addr ip)
+struct subnet_record *find_subnet(struct in_addr bcast_ip)
{
struct subnet_record *d;
+ struct in_addr wins_ip = ipgrp;
- /* search through domain list for broadcast/netmask that matches
- the source ip address */
+ /* search through subnet list for broadcast/netmask that matches
+ the source ip address. a subnet 255.255.255.255 represents the
+ WINS list. */
for (d = subnetlist; d; d = d->next)
{
- if (same_net(ip, d->bcast_ip, d->mask_ip))
+ 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 (NULL);
}
@@ -411,8 +431,7 @@ void dump_workgroups(void)
/****************************************************************************
create a domain entry
****************************************************************************/
-static struct subnet_record *make_subnet(struct in_addr bcast_ip,
- struct in_addr mask)
+static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr mask_ip)
{
struct subnet_record *d;
d = (struct subnet_record *)malloc(sizeof(*d));
@@ -421,54 +440,107 @@ static struct subnet_record *make_subnet(struct in_addr bcast_ip,
bzero((char *)d,sizeof(*d));
- DEBUG(4,("making subnet %s ", inet_ntoa(bcast_ip)));
- DEBUG(4,("%s\n", inet_ntoa(mask)));
+ DEBUG(4, ("making domain %s ", inet_ntoa(bcast_ip)));
+ DEBUG(4, ("%s\n", inet_ntoa(mask_ip)));
d->bcast_ip = bcast_ip;
- d->mask_ip = mask;
+ d->mask_ip = mask_ip;
d->workgrouplist = NULL;
- d->my_interface = ismybcast(d->bcast_ip);
+ d->my_interface = False; /* True iff the interface is on the samba host */
add_subnet(d);
return d;
}
+
+/****************************************************************************
+ add the remote interfaces from lp_remote_interfaces() and lp_interfaces()
+ to the netbios subnet database.
+ ****************************************************************************/
+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))
+ {
+ struct subnet_record *d = make_subnet(i->bcast,i->nmask);
+ if (d)
+ {
+ /* short-cut method to identifying local interfaces */
+ d->my_interface = True;
+ }
+ }
+ }
+
+ /* loop on all remote interfaces */
+ for (i = remote_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())
+ {
+ struct in_addr wins_bcast = ipgrp;
+ struct in_addr wins_nmask = ipzero;
+ make_subnet(wins_bcast, wins_nmask);
+ }
+}
+
+
/****************************************************************************
add a domain entry. creates a workgroup, if necessary, and adds the domain
to the named a workgroup.
****************************************************************************/
-struct subnet_record *add_subnet_entry(struct in_addr source_ip,
- struct in_addr source_mask,
- char *name, BOOL add)
+struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
+ struct in_addr mask_ip,
+ char *name, BOOL add, BOOL lmhosts)
{
struct subnet_record *d;
- struct in_addr ip;
- ip = ipgrp;
+ /* 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.
+
+ struct in_addr ip = ipgrp;
+
+ */
- if (zero_ip(source_ip))
- source_ip = *iface_bcast(source_ip);
+ if (zero_ip(bcast_ip))
+ bcast_ip = *iface_bcast(bcast_ip);
/* add the domain into our domain database */
- if ((d = find_domain(source_ip)) ||
- (d = make_subnet(source_ip, source_mask)))
+ if ((d = find_subnet(bcast_ip)) ||
+ (d = make_subnet(bcast_ip, mask_ip)))
{
struct work_record *w = find_workgroupstruct(d, name, add);
+ extern pstring ServerComment;
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))
+ if (strequal(lp_workgroup(), name) && d->my_interface)
+ {
+ add_my_name_entry(d,name,0x1e,NB_ACTIVE|NB_GROUP);
+ add_my_name_entry(d,name,0x0 ,NB_ACTIVE|NB_GROUP);
+ }
+ /* add samba server name to workgroup list */
+ if ((strequal(lp_workgroup(), name) && d->my_interface) || lmhosts)
{
- extern pstring ServerComment;
- add_name_entry(name,0x1e,NB_ACTIVE|NB_GROUP);
- add_name_entry(name,0x0 ,NB_ACTIVE|NB_GROUP);
add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True);
}
- DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(ip)));
+ DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(bcast_ip)));
return d;
}
return NULL;
@@ -542,6 +614,28 @@ struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
/****************************************************************************
+ remove all samba's server entries
+ ****************************************************************************/
+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);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
add a server entry
****************************************************************************/
struct server_record *add_server_entry(struct subnet_record *d,
@@ -569,6 +663,7 @@ struct server_record *add_server_entry(struct subnet_record *d,
return(s);
}
+ if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment))
updatedlists=True;
if (!s)
@@ -581,8 +676,8 @@ struct server_record *add_server_entry(struct subnet_record *d,
bzero((char *)s,sizeof(*s));
}
- if (d->my_interface &&
- strequal(lp_workgroup(),work->work_group))
+
+ if (d->my_interface && strequal(lp_workgroup(),work->work_group))
{
if (servertype)
servertype |= SV_TYPE_LOCAL_LIST_ONLY;
@@ -597,10 +692,7 @@ struct server_record *add_server_entry(struct subnet_record *d,
StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
strupper(s->serv.name);
s->serv.type = servertype;
- s->death_time = ttl?time(NULL)+ttl*3:0;
-
- if (servertype == 0)
- s->death_time = time(NULL)-1;
+ s->death_time = servertype ? (ttl?time(NULL)+ttl*3:0) : (time(NULL)-1);
/* for a domain entry, the comment field refers to the server name */
@@ -669,8 +761,7 @@ void write_browse_list(void)
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])
+ if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0])
{
continue;
}
diff --git a/source/nameelect.c b/source/nameelect.c
index 1832240a116..c841d9b7a60 100644
--- a/source/nameelect.c
+++ b/source/nameelect.c
@@ -42,8 +42,6 @@ extern pstring ServerComment;
extern time_t StartupTime;
-#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
-
#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
extern struct subnet_record *subnetlist;
@@ -61,7 +59,6 @@ void check_master_browser(void)
if (!lastrun) lastrun = t;
if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
return;
-
lastrun = t;
dump_workgroups();
@@ -77,8 +74,8 @@ void check_master_browser(void)
if (!AM_MASTER(work))
{
- queue_netbios_packet(ClientNMB,NMB_QUERY,CHECK_MASTER,
- work->work_group,0x1d,0,
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
+ work->work_group,0x1d,0,0,
True,False,d->bcast_ip);
}
}
@@ -91,13 +88,13 @@ void check_master_browser(void)
******************************************************************/
void browser_gone(char *work_name, struct in_addr ip)
{
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
struct work_record *work = find_workgroupstruct(d, work_name, False);
if (!work || !d) return;
if (strequal(work->work_group, lp_workgroup()) &&
- d->my_interface)
+ ismybcast(d->bcast_ip))
{
DEBUG(2,("Forcing election on %s %s\n",
@@ -121,6 +118,7 @@ void browser_gone(char *work_name, struct in_addr ip)
}
}
+
/****************************************************************************
send an election packet
**************************************************************************/
@@ -169,15 +167,16 @@ static void become_master(struct subnet_record *d, struct work_record *work)
work->ElectionCriterion |= 0x5;
/* add browse, master and general names to database or register with WINS */
- add_name_entry(MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
- add_name_entry(work->work_group,0x1d,NB_ACTIVE );
+ add_my_name_entry(d,MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
+ add_my_name_entry(d,work->work_group,0x1d,NB_ACTIVE );
if (lp_domain_master())
{
DEBUG(4,("Domain master: adding names...\n"));
/* add domain master and domain member names or register with WINS */
- add_name_entry(work->work_group,0x1b,NB_ACTIVE);
+ add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE );
+
work->ServerType |= SV_TYPE_DOMAIN_MASTER;
if (lp_domain_logons())
@@ -200,21 +199,44 @@ static void become_master(struct subnet_record *d, struct work_record *work)
/*******************************************************************
- unbecome the master browser
+ unbecome the master browser. initates removal of necessary netbios
+ names, and tells the world that we are no longer a master browser.
******************************************************************/
-void become_nonmaster(struct subnet_record *d, struct work_record *work)
+void become_nonmaster(struct subnet_record *d, struct work_record *work,
+ int remove_type)
{
+ int new_server_type = work->ServerType;
+
DEBUG(2,("Becoming non-master for %s\n",work->work_group));
- work->ServerType &= ~SV_TYPE_MASTER_BROWSER;
- work->ServerType &= ~SV_TYPE_DOMAIN_MASTER;
- work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
+ /* can only remove master or domain types with this function */
+ remove_type &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
+
+ /* unbecome a master browser; unbecome a domain master, too :-( */
+ if (remove_type & SV_TYPE_MASTER_BROWSER)
+ remove_type |= SV_TYPE_DOMAIN_MASTER;
+ new_server_type &= ~remove_type;
+
+ if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER)))
+ {
+ /* no longer a master browser of any sort */
+
+ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
work->ElectionCriterion &= ~0x4;
- remove_name_entry(work->work_group,0x1b);
- remove_name_entry(work->work_group,0x1d);
- remove_name_entry(MSBROWSE ,0x01);
+ /* 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);
+ }
+
+ work->ServerType = new_server_type;
+
+ if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+ remove_name_entry(d,work->work_group,0x1b);
+
+ if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+ remove_name_entry(d,work->work_group,0x1d);
}
@@ -292,7 +314,7 @@ void process_election(struct packet_struct *p,char *buf)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
int version = CVAL(buf,0);
uint32 criterion = IVAL(buf,1);
int timeup = IVAL(buf,5)/1000;
@@ -335,7 +357,8 @@ void process_election(struct packet_struct *p,char *buf)
/* if we are the master then remove our masterly names */
if (AM_MASTER(work))
{
- become_nonmaster(d, work);
+ become_nonmaster(d, work,
+ SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
}
}
}
@@ -355,10 +378,6 @@ BOOL check_elections(void)
for (d = subnetlist; d; d = d->next)
{
struct work_record *work;
-
- /* we only want to run elections on our own interfaces */
- if (!d->my_interface) continue;
-
for (work = d->workgrouplist; work; work = work->next)
{
run_any_election |= work->RunningElection;
diff --git a/source/nameresp.c b/source/nameresp.c
index b244d811597..31df7996913 100644
--- a/source/nameresp.c
+++ b/source/nameresp.c
@@ -25,8 +25,7 @@
extern int ClientNMB;
extern int ClientDGRAM;
-/* this is our initiated name query response database */
-struct name_response_record *nameresponselist = NULL;
+extern struct subnet_record *subnetlist;
extern int DEBUGLEVEL;
@@ -35,24 +34,29 @@ BOOL CanRecurse = True;
extern pstring scope;
extern pstring myname;
extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+int num_response_packets = 0;
/***************************************************************************
add an initated name query into the list
**************************************************************************/
-extern void add_response_record(struct name_response_record *n)
+static void add_response_record(struct subnet_record *d,
+ struct response_record *n)
{
- struct name_response_record *n2;
+ struct response_record *n2;
- if (!nameresponselist)
+ if (!d) return;
+
+ if (!d->responselist)
{
- nameresponselist = n;
+ d->responselist = n;
n->prev = NULL;
n->next = NULL;
return;
}
- for (n2 = nameresponselist; n2->next; n2 = n2->next) ;
+ for (n2 = d->responselist; n2->next; n2 = n2->next) ;
n2->next = n;
n->next = NULL;
@@ -60,110 +64,123 @@ extern void add_response_record(struct name_response_record *n)
}
-/*******************************************************************
- remove old name response entries
- ******************************************************************/
-void expire_netbios_response_entries(time_t t)
+/***************************************************************************
+ deals with an entry before it dies
+ **************************************************************************/
+static void dead_netbios_entry(struct subnet_record *d,
+ struct response_record *n)
{
- struct name_response_record *n;
- struct name_response_record *nextn;
+ DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
+ inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
- for (n = nameresponselist; n; n = nextn)
+ switch (n->cmd_type)
{
- if (n->start_time < t)
+ case NAME_QUERY_CONFIRM:
{
- DEBUG(3,("Removing dead name query for %s %s (num_msgs=%d)\n",
- inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
+ if (!lp_wins_support()) return; /* only if we're a WINS server */
- if (n->cmd_type == CHECK_MASTER)
- {
- /* if no response received, the master browser must have gone */
if (n->num_msgs == 0)
- browser_gone(n->name.name, n->to_ip);
- }
-
- nextn = n->next;
+ {
+ /* oops. name query had no response. check that the name is
+ unique and then remove it from our WINS database */
- if (n->prev) n->prev->next = n->next;
- if (n->next) n->next->prev = n->prev;
+ /* IMPORTANT: see query_refresh_names() */
- if (nameresponselist == n) nameresponselist = n->next;
-
- free(n);
- }
- else
+ if ((!NAME_GROUP(n->nb_flags)))
{
- nextn = n->next;
+ struct subnet_record *d = find_subnet(ipgrp);
+ if (d)
+ {
+ /* 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(d, n->name.name, n->name.name_type,
+ REGISTER, n->to_ip);
}
}
}
+ break;
+ }
-
-/****************************************************************************
- reply to a netbios name packet
- ****************************************************************************/
-void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,
- int opcode,BOOL recurse,struct nmb_name *rr_name,
- int rr_type,int rr_class,int ttl,char *data,int len)
+ case NAME_QUERY_MST_CHK:
{
- struct packet_struct p;
- struct nmb_packet *nmb = &p.packet.nmb;
- struct res_rec answers;
- char *packet_type = "unknown";
+ /* if no response received, the master browser must have gone
+ down on that subnet, without telling anyone. */
- p = *p1;
+ /* IMPORTANT: see response_netbios_packet() */
- if (rr_type == NMB_STATUS) packet_type = "nmb_status";
- if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
- if (rr_type == NMB_REG ) packet_type = "nmb_reg";
- if (rr_type == NMB_REL ) packet_type = "nmb_rel";
+ if (n->num_msgs == 0)
+ browser_gone(n->name.name, n->to_ip);
+ break;
+ }
- DEBUG(4,("replying netbios packet: %s %s\n",
- packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+ 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) */
- nmb->header.name_trn_id = trn_id;
- nmb->header.opcode = opcode;
- nmb->header.response = True;
- nmb->header.nm_flags.bcast = False;
- nmb->header.nm_flags.recursion_available = recurse;
- nmb->header.nm_flags.recursion_desired = True;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = True;
+ /* IMPORTANT: see response_name_release() */
- nmb->header.qdcount = 0;
- nmb->header.ancount = 1;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
- nmb->header.rcode = 0;
+ if (ismyip(n->to_ip))
+ {
+ remove_netbios_name(d,n->name.name,n->name.name_type,SELF,n->to_ip);
+ }
+ if (!n->bcast)
+ {
+ DEBUG(1,("WINS server did not respond to name release!\n"));
+ }
+ break;
+ }
- bzero((char*)&nmb->question,sizeof(nmb->question));
+ 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. */
- nmb->answers = &answers;
- bzero((char*)nmb->answers,sizeof(*nmb->answers));
+ /* IMPORTANT: see response_name_reg() */
- nmb->answers->rr_name = *rr_name;
- nmb->answers->rr_type = rr_type;
- nmb->answers->rr_class = rr_class;
- nmb->answers->ttl = ttl;
+ enum name_source source = ismyip(n->to_ip) ? SELF : REGISTER;
- if (data && len)
- {
- nmb->answers->rdlength = len;
- memcpy(nmb->answers->rdata, data, len);
+ add_netbios_entry(d,n->name.name,n->name.name_type,
+ n->nb_flags, n->ttl, source,n->to_ip, True,!n->bcast);
}
+ else
+ {
+ /* XXXX oops. this is where i wish this code could retry DGRAM
+ packets. we directed a name registration at a WINS server, and
+ received no response. rfc1001.txt states that after retrying,
+ we should assume the WINS server is dead, and fall back to
+ broadcasting. */
- p.packet_type = NMB_PACKET;
-
- debug_nmb_packet(&p);
+ DEBUG(1,("WINS server did not respond to name registration!\n"));
+ }
+ break;
+ }
- send_packet(&p);
+ default:
+ {
+ /* nothing to do but delete the dead expected-response structure */
+ /* this is normal. */
+ break;
+ }
+ }
}
/****************************************************************************
initiate a netbios packet
****************************************************************************/
-uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
+static 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)
{
@@ -173,6 +190,8 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
char *packet_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; }
@@ -181,7 +200,7 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
- if (opcode == -1) return False;
+ if (opcode == -1) return;
bzero((char *)&p,sizeof(p));
@@ -189,7 +208,9 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
(getpid()%(unsigned)100);
name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
- nmb->header.name_trn_id = name_trn_id;
+ if (*id == 0xffff) *id = name_trn_id; /* allow resending with same id */
+
+ nmb->header.name_trn_id = *id;
nmb->header.opcode = opcode;
nmb->header.response = False;
nmb->header.nm_flags.bcast = bcast;
@@ -229,10 +250,120 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
- if (!send_packet(&p))
- return(0);
+ if (!send_packet(&p)) *id = 0xffff;
- return(name_trn_id);
+ return;
+}
+
+
+/*******************************************************************
+ remove old name response entries
+ XXXX retry code needs to be added, including a retry wait period and a count
+ see name_query() and name_status() for suggested implementation.
+ ******************************************************************/
+void expire_netbios_response_entries()
+{
+ struct response_record *n;
+ struct response_record *nextn;
+ struct subnet_record *d;
+
+ for (d = subnetlist; d; d = d->next)
+ for (n = d->responselist; n; n = nextn)
+ {
+ 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->to_ip);
+
+ n->repeat_time += n->repeat_interval; /* XXXX ms needed */
+ n->repeat_count--;
+ }
+ else
+ {
+ dead_netbios_entry(d,n);
+
+ nextn = n->next;
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (d->responselist == n) d->responselist = n->next;
+
+ free(n);
+
+ num_response_packets--;
+
+ continue;
+ }
+ }
+ nextn = n->next;
+ }
+}
+
+
+/****************************************************************************
+ reply to a netbios name packet
+ ****************************************************************************/
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode,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;
+ struct res_rec answers;
+ char *packet_type = "unknown";
+
+ p = *p1;
+
+ if (rr_type == NMB_STATUS) packet_type = "nmb_status";
+ if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
+ if (rr_type == NMB_REG ) packet_type = "nmb_reg";
+ if (rr_type == NMB_REL ) packet_type = "nmb_rel";
+
+ DEBUG(4,("replying netbios packet: %s %s\n",
+ packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+
+ nmb->header.name_trn_id = trn_id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = True;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = recurse;
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.qdcount = 0;
+ nmb->header.ancount = 1;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->header.rcode = 0;
+
+ bzero((char*)&nmb->question,sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ bzero((char*)nmb->answers,sizeof(*nmb->answers));
+
+ nmb->answers->rr_name = *rr_name;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = rr_class;
+ nmb->answers->ttl = ttl;
+
+ if (data && len)
+ {
+ nmb->answers->rdlength = len;
+ memcpy(nmb->answers->rdata, data, len);
+ }
+
+ p.packet_type = NMB_PACKET;
+
+ debug_nmb_packet(&p);
+
+ send_packet(&p);
}
@@ -241,8 +372,9 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
name server instead, if it exists. if wins is false, and there has been no
WINS server specified, the packet will NOT be sent.
****************************************************************************/
-void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
- char *name,int name_type,int nb_flags,
+void queue_netbios_pkt_wins(struct subnet_record *d,
+ int fd,int quest_type,enum cmd_type cmd,
+ char *name,int name_type,int nb_flags, time_t ttl,
BOOL bcast,BOOL recurse,struct in_addr to_ip)
{
if ((!lp_wins_support()) && (*lp_wins_server()))
@@ -266,35 +398,45 @@ void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
if (zero_ip(to_ip)) return;
- queue_netbios_packet(fd, quest_type, cmd,
- name, name_type, nb_flags,
+ queue_netbios_packet(d,fd, quest_type, cmd,
+ name, name_type, nb_flags, ttl,
bcast, recurse, to_ip);
}
/****************************************************************************
create a name query response record
**************************************************************************/
-static struct name_response_record *
-make_name_query_record(enum cmd_type cmd,int id,int fd,char *name,int type,
+static struct response_record *
+make_response_queue_record(enum cmd_type cmd,int id,int fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
BOOL bcast,BOOL recurse,struct in_addr ip)
{
- struct name_response_record *n;
+ struct response_record *n;
if (!name || !name[0]) return NULL;
- if (!(n = (struct name_response_record *)malloc(sizeof(*n))))
+ if (!(n = (struct response_record *)malloc(sizeof(*n))))
return(NULL);
n->response_id = id;
n->cmd_type = cmd;
n->fd = fd;
+ n->quest_type = quest_type;
make_nmb_name(&n->name, name, type, scope);
+ n->nb_flags = nb_flags;
+ n->ttl = ttl;
n->bcast = bcast;
n->recurse = recurse;
n->to_ip = ip;
- n->start_time = time(NULL);
+
+ n->repeat_interval = 1; /* XXXX should be in ms */
+ n->repeat_count = 4;
+ n->repeat_time = time(NULL) + n->repeat_interval;
+
n->num_msgs = 0;
+ num_response_packets++; /* count of total number of packets still around */
+
return n;
}
@@ -305,32 +447,43 @@ make_name_query_record(enum cmd_type cmd,int id,int fd,char *name,int type,
master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
complete lists across a wide area network
****************************************************************************/
-void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name,
- int name_type,int nb_flags,BOOL bcast,BOOL recurse,
- struct in_addr to_ip)
+void queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum cmd_type cmd,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse, struct in_addr to_ip)
{
- uint16 id = initiate_netbios_packet(fd, quest_type, name, name_type,
+ 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, to_ip)) return;
+
+ initiate_netbios_packet(&id, fd, quest_type, name, name_type,
nb_flags, bcast, recurse, to_ip);
- struct name_response_record *n;
- if (id == 0) return;
+ if (id == 0xffff) return;
- if ((n =
- make_name_query_record(cmd,id,fd,name,name_type,bcast,recurse,to_ip)))
+ if ((n = make_response_queue_record(cmd,id,fd,
+ quest_type,name,name_type,nb_flags,ttl,
+ bcast,recurse,to_ip)))
{
- add_response_record(n);
+ add_response_record(d,n);
}
}
/****************************************************************************
- find a response in the name query response list
+ find a response in a subnet's name query response list.
**************************************************************************/
-struct name_response_record *find_name_query(uint16 id)
+struct response_record *find_response_record(struct subnet_record *d,
+ uint16 id)
{
- struct name_response_record *n;
+ struct response_record *n;
- for (n = nameresponselist; n; n = n->next)
+ if (!d) return NULL;
+
+ for (n = d->responselist; n; n = n->next)
{
if (n->response_id == id) {
return n;
@@ -409,10 +562,12 @@ void listen_for_packets(BOOL run_election)
FD_SET(ClientNMB,&fds);
FD_SET(ClientDGRAM,&fds);
- /* during elections we need to send election packets at one
- second intervals */
+ /* during elections and when expecting a netbios response packet we need
+ to send election packets at one second intervals.
+ XXXX actually, it needs to be the interval (in ms) between time now and the
+ time we are expecting the next netbios packet */
- timeout.tv_sec = run_election ? 1 : NMBD_SELECT_LOOP;
+ timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
timeout.tv_usec = 0;
selrtn = sys_select(&fds,&timeout);
@@ -461,8 +616,9 @@ interpret a node status response. this is pretty hacked: we need two bits of
info. a) the name of the workgroup b) the name of the server. it will also
add all the names it finds into the namelist.
****************************************************************************/
-BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
- char *serv_name, struct in_addr ip)
+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)
{
int level = t==0x20 ? 4 : 0;
int numnames = CVAL(p,0);
@@ -516,7 +672,7 @@ BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
nameip = ip;
src = STATUS_QUERY;
}
- add_netbios_entry(qname,type,nb_flags,2*60*60,src,nameip,True);
+ add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
}
/* we want the server name */
@@ -559,9 +715,13 @@ BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
{
struct packet_struct p;
struct dgram_packet *dgram = &p.packet.dgram;
+ struct in_addr wins_ip = ipgrp;
char *ptr,*p2;
char tmp[4];
+ /* ha ha. no. do NOT send packets to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, dest_ip)) return False;
+
bzero((char *)&p,sizeof(p));
dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
diff --git a/source/nameserv.c b/source/nameserv.c
index 22c1e7dbbaa..7b72f93952a 100644
--- a/source/nameserv.c
+++ b/source/nameserv.c
@@ -30,6 +30,10 @@
extern int ClientNMB;
extern int ClientDGRAM;
+#define FIND_SELF 0x01
+#define FIND_WINS 0x02
+#define FIND_LOCAL 0x04
+
extern int DEBUGLEVEL;
extern pstring scope;
@@ -38,11 +42,27 @@ extern pstring myname;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
-/* netbios names database */
-struct name_record *namelist;
+extern struct subnet_record *subnetlist;
+
+#define WINS_LIST "wins.dat"
#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+/****************************************************************************
+ finds the appropriate subnet structure. directed packets (non-bcast) are
+ assumed to come from a point-to-point (P or M node), and so the subnet we
+ return in this instance is the WINS 'pseudo-subnet' with ip 255.255.255.255
+ ****************************************************************************/
+static struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast)
+{
+ if (bcast)
+ {
+ /* identify the subnet the broadcast request came from */
+ return find_subnet(*iface_bcast(ip));
+ }
+ /* find the subnet under the pseudo-ip of 255.255.255.255 */
+ return find_subnet(ipgrp);
+}
/****************************************************************************
true if two netbios names are equal
@@ -57,19 +77,21 @@ static BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
/****************************************************************************
add a netbios name into the namelist
**************************************************************************/
-static void add_name(struct name_record *n)
+static void add_name(struct subnet_record *d, struct name_record *n)
{
struct name_record *n2;
- if (!namelist)
+ if (!d) return;
+
+ if (!d->namelist)
{
- namelist = n;
+ d->namelist = n;
n->prev = NULL;
n->next = NULL;
return;
}
- for (n2 = namelist; n2->next; n2 = n2->next) ;
+ for (n2 = d->namelist; n2->next; n2 = n2->next) ;
n2->next = n;
n->next = NULL;
@@ -80,9 +102,12 @@ static void add_name(struct name_record *n)
remove a name from the namelist. The pointer must be an element just
retrieved
**************************************************************************/
-void remove_name(struct name_record *n)
+void remove_name(struct subnet_record *d, struct name_record *n)
{
- struct name_record *nlist = namelist;
+ struct name_record *nlist;
+ if (!d) return;
+
+ nlist = d->namelist;
while (nlist && nlist != n) nlist = nlist->next;
@@ -96,29 +121,70 @@ void remove_name(struct name_record *n)
/****************************************************************************
- find a name in the domain database namelist
- search can be:
- FIND_SELF - look for names the samba server has added for itself
- FIND_GLOBAL - the name can be anyone. first look on the client's
- subnet, then the server's subnet, then all subnets.
+ find a name in a namelist
**************************************************************************/
-static struct name_record *find_name_search(struct nmb_name *name,
- enum name_search search,
- struct in_addr ip)
+static struct name_record *find_name(struct name_record *n,
+ struct nmb_name *name,
+ int search, struct in_addr ip)
{
struct name_record *ret;
- for (ret = namelist; ret; ret = ret->next)
+ for (ret = n; ret; ret = ret->next)
{
- if (!name_equal(&ret->name,name)) continue;
-
- if (search == FIND_SELF && ret->source != SELF) continue;
+ if (name_equal(&ret->name,name))
+ {
+ /* self search: self names only */
+ if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF)
+ continue;
+ if (zero_ip(ip) || ip_equal(ip, ret->ip))
+ {
return ret;
}
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ find a name in the domain database namelist
+ search can be any of:
+ FIND_SELF - look exclusively for names the samba server has added for itself
+ FIND_LOCAL - look for names in the local subnet record.
+ FIND_WINS - look for names in the WINS record
+ **************************************************************************/
+static struct name_record *find_name_search(struct subnet_record **d,
+ struct nmb_name *name,
+ int search, struct in_addr ip)
+{
+ if (d == NULL) return NULL; /* bad error! */
+ if ((search & FIND_LOCAL) == FIND_LOCAL)
+ {
+ if (*d != NULL)
+ {
+ return find_name((*d)->namelist, name, search, ip);
+ }
+ else
+ {
+ DEBUG(4,("local find_name_search with a NULL subnet pointer\n"));
return NULL;
}
+ }
+
+ if ((search & FIND_WINS) != FIND_WINS) return NULL;
+
+ if (*d == NULL)
+ {
+ /* find WINS subnet record */
+ *d = find_subnet(ipgrp);
+ }
+
+ if (*d == NULL) return NULL;
+
+ return find_name((*d)->namelist, name, search, ip);
+}
/****************************************************************************
@@ -127,48 +193,232 @@ static struct name_record *find_name_search(struct nmb_name *name,
void dump_names(void)
{
struct name_record *n;
+ struct subnet_record *d;
+ fstring fname, fnamenew;
time_t t = time(NULL);
+ FILE *f;
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+ strcpy(fnamenew,fname);
+ strcat(fnamenew,".");
+
+ f = fopen(fnamenew,"w");
+
+ if (!f)
+ {
+ DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+ }
+
DEBUG(3,("Dump of local name table:\n"));
- for (n = namelist; n; n = n->next)
+ for (d = subnetlist; d; d = d->next)
+ for (n = d->namelist; n; n = n->next)
{
- DEBUG(3,("%s %s TTL=%d NBFLAGS=%2x\n",
+ if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER)
+ {
+ fstring data;
+
+ /* XXXX i have little imagination as to how to output nb_flags as
+ anything other than a hexadecimal number :-) */
+
+ sprintf(data, "%s#%02x %s %ld %2x",
+ n->name.name,n->name.name_type, /* XXXX ignore the scope for now */
+ inet_ntoa(n->ip),
+ n->death_time,
+ n->nb_flags);
+ fprintf(f, "%s\n", data);
+ }
+
+ DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
+ DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
+ DEBUG(3,("%s %15s TTL=%15d NBFLAGS=%2x\n",
namestr(&n->name),
inet_ntoa(n->ip),
n->death_time?n->death_time-t:0,
n->nb_flags));
}
+
+ fclose(f);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+
+ DEBUG(3,("Wrote wins database %s\n",fname));
+}
+
+/****************************************************************************
+load a netbios name database file
+****************************************************************************/
+void load_netbios_names(void)
+{
+ struct subnet_record *d = find_subnet(ipgrp);
+ fstring fname;
+
+ FILE *f;
+ pstring line;
+
+ if (!d) return;
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+
+ f = fopen(fname,"r");
+
+ if (!f) {
+ DEBUG(2,("Can't open wins database file %s\n",fname));
+ return;
+ }
+
+ while (!feof(f))
+ {
+ pstring name_str, ip_str, ttd_str, nb_flags_str;
+
+ pstring name;
+ int type = 0;
+ int nb_flags;
+ time_t ttd;
+ struct in_addr ipaddr;
+
+ enum name_source source;
+
+ char *ptr;
+ int count = 0;
+
+ char *p;
+
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ ptr = line;
+
+ if (next_token(&ptr,name_str ,NULL)) ++count;
+ if (next_token(&ptr,ip_str ,NULL)) ++count;
+ if (next_token(&ptr,ttd_str ,NULL)) ++count;
+ if (next_token(&ptr,nb_flags_str,NULL)) ++count;
+
+ if (count <= 0) continue;
+
+ if (count != 4) {
+ DEBUG(0,("Ill formed wins line"));
+ DEBUG(0,("[%s]: name#type ip nb_flags abs_time\n",line));
+ continue;
+ }
+
+ /* netbios name. # divides the name from the type (hex): netbios#xx */
+ strcpy(name,name_str);
+
+ p = strchr(name,'#');
+
+ if (p) {
+ *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);
+
+ ipaddr = *interpret_addr2(ip_str);
+
+ if (ip_equal(ipaddr,ipzero)) {
+ source = SELF;
+ }
+ else
+ {
+ source = REGISTER;
+ }
+
+ DEBUG(4, ("add WINS line: %s#%02x %s %ld %2x\n",
+ name,type, inet_ntoa(ipaddr), ttd, nb_flags));
+
+ /* add all entries that have 60 seconds or more to live */
+ if (ttd - 10 < time(NULL) || ttd == 0)
+ {
+ time_t t = (ttd?ttd-time(NULL):0) / 3;
+
+ /* add netbios entry read from the wins.dat file. IF it's ok */
+ add_netbios_entry(d,name,type,nb_flags,t,source,ipaddr,True,True);
+ }
+ }
+
+ fclose(f);
}
/****************************************************************************
remove an entry from the name list
****************************************************************************/
-void remove_netbios_name(char *name,int type, enum name_source source,
+void remove_netbios_name(struct subnet_record *d,
+ char *name,int type, enum name_source source,
struct in_addr ip)
{
struct nmb_name nn;
struct name_record *n;
+ int search = FIND_LOCAL;
+
+ /* if it's not a special browser name, search the WINS database */
+ if (type != 0x01 && type != 0x1d && type != 0x1e)
+ search |= FIND_WINS;
make_nmb_name(&nn, name, type, scope);
- n = find_name_search(&nn, FIND_GLOBAL, ip);
+ n = find_name_search(&d, &nn, search, ip);
- if (n && n->source == source) remove_name(n);
+ if (n && n->source == source) remove_name(d,n);
}
/****************************************************************************
- add an entry to the name list
+ add an entry to the name list.
+
+ this is a multi-purpose function.
+
+ it adds samba's own names in to its records on each interface, keeping a
+ record of whether it is a master browser, domain master, or WINS server.
+
+ it also keeps a record of WINS entries (names of type 0x00, 0x20, 0x03 etc)
+
****************************************************************************/
-struct name_record *add_netbios_entry(char *name, int type, int nb_flags,
- int ttl,
- enum name_source source,
- struct in_addr ip,
- BOOL new_only)
+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)
{
struct name_record *n;
struct name_record *n2=NULL;
+ int search = 0;
+ BOOL self = source == SELF;
+
+ /* add the name to the WINS list if the name comes from a directed query */
+ search |= wins ? FIND_WINS : FIND_LOCAL;
+ /* search for SELF names only */
+ search |= self ? FIND_SELF : 0;
+
+ if (!self)
+ {
+ if (wins)
+ {
+ if (type == 0x01 || type == 0x1d || type == 0x1e)
+ {
+ /* XXXX WINS server supposed to ignore special browser names. hm.
+ but is a primary domain controller supposed to ignore special
+ browser names? luke doesn't think so, but can't test it! :-)
+ */
+ return NULL;
+ }
+ }
+ else /* !wins */
+ {
+ /* the only broadcast (non-WINS) names we are adding are ours (SELF) */
+ return NULL;
+ }
+ }
n = (struct name_record *)malloc(sizeof(*n));
if (!n) return(NULL);
@@ -177,7 +427,7 @@ struct name_record *add_netbios_entry(char *name, int type, int nb_flags,
make_nmb_name(&n->name,name,type,scope);
- if ((n2 = find_name_search(&n->name, FIND_GLOBAL, new_only?ipzero:ip)))
+ if ((n2 = find_name_search(&d, &n->name, search, new_only?ipzero:ip)))
{
free(n);
if (new_only || (n2->source==SELF && source!=SELF)) return n2;
@@ -189,7 +439,7 @@ struct name_record *add_netbios_entry(char *name, int type, int nb_flags,
n->nb_flags = nb_flags;
n->source = source;
- if (!n2) add_name(n);
+ 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));
@@ -201,21 +451,39 @@ struct name_record *add_netbios_entry(char *name, int type, int nb_flags,
/****************************************************************************
remove an entry from the name list
****************************************************************************/
-void remove_name_entry(char *name,int type)
+void remove_name_entry(struct subnet_record *d, char *name,int type)
{
if (lp_wins_support())
{
/* we are a WINS server. */
- remove_netbios_name(name,type,SELF,ipzero);
+ /* XXXX assume that if we are a WINS server that we are therefore
+ not pointing to another WINS server as well. this may later NOT
+ actually be true */
+ remove_netbios_name(d,name,type,SELF,ipzero);
}
else
{
- struct in_addr ip;
- ip = ipzero;
+ /* not a WINS server: cannot just remove our own names: we have to
+ ask permission from the WINS server, or if no reply is received,
+ _then_ we can remove the name */
- queue_netbios_pkt_wins(ClientNMB,NMB_REL,NAME_RELEASE,
- name, type, 0,
- False, True, ip);
+ struct name_record n;
+ struct name_record *n2=NULL;
+
+ make_nmb_name(&n.name,name,type,scope);
+
+ if ((n2 = find_name_search(&d, &n.name, FIND_SELF, ipzero)))
+ {
+ /* check name isn't already being de-registered */
+ if (NAME_DEREG(n2->nb_flags))
+ return;
+
+ /* mark the name as in the process of deletion. */
+ n2->nb_flags &= NB_DEREG;
+ }
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0, 0,
+ False, True, ipzero);
}
}
@@ -223,19 +491,32 @@ void remove_name_entry(char *name,int type)
/****************************************************************************
add an entry to the name list
****************************************************************************/
-void add_name_entry(char *name,int type,int nb_flags)
+void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
{
+ BOOL re_reg = False;
+ struct nmb_name n;
+
+ if (!d) return;
+
+ /* not that it particularly matters, but if the SELF name already exists,
+ it must be re-registered, rather than just registered */
+
+ make_nmb_name(&n, name, type, scope);
+ if (find_name(d->namelist, &n, SELF, ipzero))
+ re_reg = True;
+
/* always add our own entries */
- add_netbios_entry(name,type,nb_flags,0,SELF,ipzero,False);
+ add_netbios_entry(d,name,type,nb_flags,0,SELF,ipzero,False,lp_wins_support());
if (!lp_wins_support())
{
- struct in_addr ip;
- ip = ipzero;
+ /* we aren't supporting WINS: register name using broadcast or
+ contact WINS server */
- queue_netbios_pkt_wins(ClientNMB,NMB_REG,NAME_REGISTER,
- name, type, nb_flags,
- False, True, ip);
+ queue_netbios_pkt_wins(d,ClientNMB,
+ re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+ name, type, nb_flags, GET_TTL(0),
+ False, True, ipzero);
}
}
@@ -245,38 +526,53 @@ void add_name_entry(char *name,int type,int nb_flags)
**************************************************************************/
void add_my_names(void)
{
- struct in_addr ip;
+ BOOL wins = lp_wins_support();
+ struct subnet_record *d;
- ip = ipzero;
-
- add_name_entry(myname,0x20,NB_ACTIVE);
- add_name_entry(myname,0x03,NB_ACTIVE);
- add_name_entry(myname,0x00,NB_ACTIVE);
- add_name_entry(myname,0x1f,NB_ACTIVE);
+ struct in_addr ip = ipzero;
- add_netbios_entry("*",0x0,NB_ACTIVE,0,SELF,ip,False);
- add_netbios_entry("__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip,False);
- add_netbios_entry("__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip,False);
+ /* each subnet entry, including the WINS one, must have its own
+ netbios name. */
+ /* XXXX if there was a transport layer added to samba (ipx/spx, netbeui
+ etc) then there would be yet _another_ for-loop, this time on the
+ transport type */
+ for (d = subnetlist; d; d = d->next)
+ {
+ add_my_name_entry(d, myname,0x20,NB_ACTIVE);
+ add_my_name_entry(d, myname,0x03,NB_ACTIVE);
+ add_my_name_entry(d, myname,0x00,NB_ACTIVE);
+ add_my_name_entry(d, myname,0x1f,NB_ACTIVE);
- if (lp_wins_support()) {
+ add_netbios_entry(d,"*",0x0,NB_ACTIVE,0,SELF,ip,False,wins);
+ add_netbios_entry(d,"__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip,False,wins);
+ add_netbios_entry(d,"__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip,False,wins);
+
+ if (wins) {
/* the 0x1c name gets added by any WINS server it seems */
- add_name_entry(my_workgroup(),0x1c,NB_ACTIVE|NB_GROUP);
+ add_my_name_entry(d, my_workgroup(),0x1c,NB_ACTIVE|NB_GROUP);
}
}
+}
+
/****************************************************************************
remove all the samba names... from a WINS server if necessary.
**************************************************************************/
void remove_my_names()
{
+ struct subnet_record *d;
+
+ for (d = subnetlist; d; d = d->next)
+ {
struct name_record *n;
- for (n = namelist; n; n = n->next)
+ for (n = d->namelist; n; n = n->next)
{
if (n->source == SELF)
{
/* get all SELF names removed from the WINS server's database */
- remove_name_entry(n->name.name, n->name.name_type);
+ remove_name_entry(d,n->name.name, n->name.name_type);
+ }
}
}
}
@@ -297,15 +593,73 @@ void refresh_my_names(time_t t)
}
/*******************************************************************
+ queries names occasionally. an over-cautious, non-trusting WINS server!
+ ******************************************************************/
+void query_refresh_names(void)
+{
+ struct name_record *n;
+ struct subnet_record *d = find_subnet(ipgrp);
+
+ 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;
+
+ name_refresh_time = NAME_POLL_INTERVAL * max_count / 2;
+
+ /* if (!lp_poll_wins()) return; polling of registered names allowed */
+
+ if (!d) return;
+
+ if (t - lasttime < NAME_POLL_INTERVAL) return;
+
+ for (n = d->namelist; n; n = n->next)
+ {
+ /* only do unique, registered names */
+
+ if (n->source != REGISTER) continue;
+ if (!NAME_GROUP(n->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,
+ False,False,n->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;
+ }
+}
+
+
+/*******************************************************************
expires old names in the namelist
******************************************************************/
void expire_names(time_t t)
{
struct name_record *n;
struct name_record *next;
+ struct subnet_record *d;
/* expire old names */
- for (n = namelist; n; n = next)
+ for (d = subnetlist; d; d = d->next)
+ {
+ for (n = d->namelist; n; n = next)
{
if (n->death_time && n->death_time < t)
{
@@ -316,7 +670,7 @@ void expire_names(time_t t)
if (n->prev) n->prev->next = n->next;
if (n->next) n->next->prev = n->prev;
- if (namelist == n) namelist = n->next;
+ if (d->namelist == n) d->namelist = n->next;
free(n);
}
@@ -326,12 +680,14 @@ void expire_names(time_t t)
}
}
}
+}
/****************************************************************************
- response for a reg release received
+ response for a reg release received. samba has asked a WINS server if it
+ could release a name.
**************************************************************************/
-void response_name_release(struct packet_struct *p)
+void response_name_release(struct subnet_record *d, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
char *name = nmb->question.question_name.name;
@@ -341,18 +697,24 @@ void response_name_release(struct packet_struct *p)
if (nmb->header.rcode == 0 && nmb->answers->rdata)
{
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
struct in_addr found_ip;
putip((char*)&found_ip,&nmb->answers->rdata[2]);
if (ismyip(found_ip))
{
- remove_netbios_name(name,type,SELF,found_ip);
+ remove_netbios_name(d,name,type,SELF,found_ip);
}
}
else
{
- DEBUG(1,("name registration for %s rejected!\n",
+ DEBUG(2,("name release for %s rejected!\n",
namestr(&nmb->question.question_name)));
+
+ /* XXXX do we honestly care if our name release was rejected?
+ only if samba is issuing the release on behalf of some out-of-sync
+ server. if it's one of samba's SELF names, we don't care. */
}
}
@@ -369,14 +731,29 @@ void reply_name_release(struct packet_struct *p)
int nb_flags = nmb->additional->rdata[0];
BOOL bcast = nmb->header.nm_flags.bcast;
struct name_record *n;
+ struct subnet_record *d = NULL;
char rdata[6];
+ int search = 0;
putip((char *)&ip,&nmb->additional->rdata[2]);
DEBUG(3,("Name release on name %s rcode=%d\n",
namestr(&nmb->question.question_name),rcode));
- n = find_name_search(&nmb->question.question_name, FIND_GLOBAL, ip);
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("response packet: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (bcast)
+ search &= FIND_LOCAL;
+ else
+ search &= FIND_WINS;
+
+ n = find_name_search(&d, &nmb->question.question_name,
+ search, ip);
/* XXXX under what conditions should we reject the removal?? */
if (n && n->nb_flags == nb_flags)
@@ -384,7 +761,7 @@ void reply_name_release(struct packet_struct *p)
/* success = True;
rcode = 6; */
- remove_name(n);
+ remove_name(d,n);
n = NULL;
}
@@ -408,16 +785,19 @@ void reply_name_release(struct packet_struct *p)
/****************************************************************************
response for a reg request received
**************************************************************************/
-void response_name_reg(struct packet_struct *p)
+void response_name_reg(struct subnet_record *d, struct packet_struct *p)
{
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)
{
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
int nb_flags = nmb->answers->rdata[0];
struct in_addr found_ip;
int ttl = nmb->answers->ttl;
@@ -427,12 +807,31 @@ void response_name_reg(struct packet_struct *p)
if (ismyip(found_ip)) source = SELF;
- add_netbios_entry(name,type,nb_flags,ttl,source,found_ip,True);
+ add_netbios_entry(d, name,type,nb_flags,ttl,source,found_ip,True,!bcast);
}
else
{
+ struct work_record *work;
+
DEBUG(1,("name registration for %s rejected!\n",
namestr(&nmb->question.question_name)));
+
+ /* XXXX oh dear. we have problems. must deal with our name having
+ been rejected: e.g if it was our GROUP(1d) name, we must unbecome
+ a master browser. */
+
+ if (!(work = find_workgroupstruct(d, name, False))) return;
+
+ /* remove_netbios_name(d,name,type,SELF,ipzero); */
+
+ if (AM_MASTER(work) && (type == 0x1d || type == 0x1b))
+ {
+ int remove_type = 0;
+ if (type == 0x1d) remove_type = SV_TYPE_MASTER_BROWSER;
+ if (type == 0x1b) remove_type = SV_TYPE_DOMAIN_MASTER;
+
+ become_nonmaster(d, work, remove_type);
+ }
}
}
@@ -458,20 +857,21 @@ void reply_name_reg(struct packet_struct *p)
int rcode = 0;
int opcode = nmb->header.opcode;
+ struct subnet_record *d = NULL;
struct name_record *n = NULL;
BOOL success = True;
BOOL recurse = True; /* true if samba replies yes/no: false if caller */
- /* must challenge the current owner */
+ /* must challenge the current owner of the unique name */
char rdata[6];
-
struct in_addr ip, from_ip;
-
- DEBUG(3,("Name registration for name %s at %s rcode=%d\n",
- namestr(question),inet_ntoa(ip),rcode));
+ int search = 0;
putip((char *)&from_ip,&nmb->additional->rdata[2]);
ip = from_ip;
+ DEBUG(3,("Name registration for name %s at %s rcode=%d\n",
+ namestr(question),inet_ntoa(ip),rcode));
+
if (group)
{
/* apparently we should return 255.255.255.255 for group queries
@@ -479,8 +879,20 @@ void reply_name_reg(struct packet_struct *p)
ip = ipgrp;
}
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("response packet: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (bcast)
+ search &= FIND_LOCAL;
+ else
+ search &= FIND_WINS;
+
/* see if the name already exists */
- n = find_name_search(question, FIND_GLOBAL, from_ip);
+ n = find_name_search(&d, question, search, from_ip);
if (n)
{
@@ -502,10 +914,10 @@ void reply_name_reg(struct packet_struct *p)
* if we are doing secured WINS, we must send a Wait-Acknowledge
* packet (WACK) to the person who wants the name, then do a
* name query on the person who currently owns the unique name.
- * if the current owner is alive, the person who wants the name
- * can't have it. if they are not alive, they can.
+ * if the current owner still says they own it, the person who wants
+ * the name can't have it. if they do not, or are not alive, they can.
*
- * if we are doing non-secure WINS (which is much simpler) then
+ * if we are doing non-secured WINS (which is much simpler) then
* we send a message to the person wanting the name saying 'he
* owns this name: i don't want to hear from you ever again
* until you've checked with him if you can have it!'. we then
@@ -535,8 +947,6 @@ void reply_name_reg(struct packet_struct *p)
}
else
{
- /* XXXX removed code that checked with the owner of a name */
-
n->ip = ip;
n->death_time = ttl?p->timestamp+ttl*3:0;
DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip)));
@@ -550,27 +960,30 @@ void reply_name_reg(struct packet_struct *p)
n->death_time = ttl?p->timestamp + ttl*3:0;
}
}
+
+ /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
+ /* names that people have checked for and not found get DNSFAILed.
+ we need to update the name record if someone then registers */
+
+ if (n->source == DNSFAIL)
+ n->source = REGISTER;
+
}
else
{
- /* add the name to our subnet/name database */
- n = add_netbios_entry(qname,name_type,nb_flags,ttl,REGISTER,ip,True);
+ /* add the name to our name/subnet, or WINS, database */
+ n = add_netbios_entry(d,qname,name_type,nb_flags,ttl,REGISTER,ip,
+ True,!bcast);
}
if (bcast) return;
- if (success)
- {
- update_from_reg(nmb->question.question_name.name,
- nmb->question.question_name.name_type, from_ip);
- }
-
rdata[0] = nb_flags;
rdata[1] = 0;
putip(&rdata[2],(char *)&ip);
/* Send a NAME REGISTRATION RESPONSE (pos/neg)
- or and END-NODE CHALLENGE REGISTRATION RESPONSE */
+ or an END-NODE CHALLENGE REGISTRATION RESPONSE */
reply_netbios_packet(p,nmb->header.name_trn_id,
rcode,opcode,recurse,
reply_name, name_type, name_class,
@@ -591,11 +1004,23 @@ void reply_name_status(struct packet_struct *p)
char *countptr, *buf, *bufend;
int names_added;
struct name_record *n;
+ struct subnet_record *d = NULL;
+
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("Name status req: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
DEBUG(3,("Name status for name %s %s\n",
namestr(&nmb->question.question_name), inet_ntoa(p->ip)));
- n = find_name_search(&nmb->question.question_name,FIND_GLOBAL, p->ip);
+ n = find_name_search(&d, &nmb->question.question_name,
+ FIND_SELF|FIND_LOCAL,
+ p->ip);
if (!n) return;
@@ -606,7 +1031,7 @@ void reply_name_status(struct packet_struct *p)
names_added = 0;
- for (n = namelist ; n && buf < bufend; n = n->next)
+ for (n = d->namelist ; n && buf < bufend; n = n->next)
{
int name_type = n->name.name_type;
@@ -666,9 +1091,9 @@ void reply_name_status(struct packet_struct *p)
/***************************************************************************
reply to a name query
****************************************************************************/
-static struct name_record *search_for_name(struct nmb_name *question,
- struct in_addr ip, int Time,
- enum name_search search)
+struct name_record *search_for_name(struct subnet_record **d,
+ struct nmb_name *question,
+ struct in_addr ip, int Time, int search)
{
int name_type = question->name_type;
char *qname = question->name;
@@ -678,8 +1103,10 @@ static struct name_record *search_for_name(struct nmb_name *question,
DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
- /* first look up name in cache. use ip as well as name to locate it */
- n = find_name_search(question,search,ip);
+ /* first look up name in cache */
+ n = find_name_search(d,question,search,ip);
+
+ if (*d == NULL) return NULL;
/* now try DNS lookup. */
if (!n)
@@ -702,14 +1129,16 @@ static struct name_record *search_for_name(struct nmb_name *question,
if (!a)
{
/* no luck with DNS. We could possibly recurse here XXXX */
- /* if this isn't a bcast then we should send a negative reply XXXX */
- DEBUG(3,("no recursion\n"));
- add_netbios_entry(qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,True);
+ 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 it to our cache of names. give it 2 hours in the cache */
- n = add_netbios_entry(qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,True);
+ /* 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);
/* failed to add it? yikes! */
if (!n) return NULL;
@@ -734,42 +1163,112 @@ static struct name_record *search_for_name(struct nmb_name *question,
}
-
/***************************************************************************
- reply to a name query
+reply to a name query.
+
+with broadcast name queries:
+
+ - only reply if the query is for one of YOUR names. all other machines on
+ the network will be doing the same thing (that is, only replying to a
+ broadcast query if they own it)
+ NOTE: broadcast name queries should only be sent out by a machine
+ if they HAVEN'T been configured to use WINS. this is generally bad news
+ in a wide area tcp/ip network and should be rectified by the systems
+ administrator. USE WINS! :-)
+ - the exception to this is if the query is for a Primary Domain Controller
+ type name (0x1b), in which case, a reply is sent.
+
+ - NEVER send a negative response to a broadcast query. no-one else will!
+
+with directed name queries:
+
+ - if you are the WINS server, you are expected to respond with either
+ a negative response, a positive response, or a wait-for-acknowledgement
+ packet, and then later on a pos/neg response.
+
****************************************************************************/
void reply_name_query(struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
int name_type = question->name_type;
- BOOL dns_type = name_type == 0x20 || name_type == 0;
BOOL bcast = nmb->header.nm_flags.bcast;
int ttl=0;
int rcode = 0;
int nb_flags = 0;
struct in_addr retip;
char rdata[6];
+ struct subnet_record *d = NULL;
+
BOOL success = True;
+
struct name_record *n;
- enum name_search search = (dns_type || name_type == 0x1b) ?
- FIND_GLOBAL : FIND_SELF;
+ int search = 0;
+
+ if (name_type == 0x20 || name_type == 0x00 || name_type == 0x1b ||
+ name_type == 0x1f || name_type == 0x03 || name_type == 0x01 ||
+ name_type == 0x1c)
+ {
+ /* search for any of the non-'special browser' names, or for a PDC type
+ (0x1b) name in the WINS database.
+ XXXX should we include name type 0x1c: WINS server type?
+ */
+ search |= FIND_WINS;
+ }
+ else
+ {
+ /* special browser name types e.g
+ ^1^2__MSBROWSE__^2^1, GROUP(1d) and GROUP(1e)
+
+ name_type == 0x01 || name_type == 0x1d || name_type == 0x1e.
+
+ XXXX luke reckons we should be able to search for any SELF name
+ in the WINS database, if we are a primary domain controller.
+ */
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("name query: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ success = False;
+ }
+
+ /* XXXX delete if shouldn't search for SELF names in WINS database */
+ search |= FIND_WINS;
+ }
+
+ if (bcast)
+ {
+ /* a name query has been made by a non-WINS configured host. search the
+ local interface database as well */
+ search |= FIND_LOCAL;
+ }
DEBUG(3,("Name query "));
- if ((n = search_for_name(question,p->ip,p->timestamp, search)))
+ if (search == 0)
+ {
+ /* eh? no criterion for searching database. help! */
+ success = False;
+ }
+
+ if (success && (n = search_for_name(&d,question,p->ip,p->timestamp, search)))
{
/* don't respond to broadcast queries unless the query is for
a name we own or it is for a Primary Domain Controller name */
- if (bcast && n->source != SELF && name_type != 0x1b)
- {
+
+ if (bcast && n->source != SELF && name_type != 0x1b) {
if (!lp_wins_proxy() || same_net(p->ip,n->ip,*iface_nmask(p->ip))) {
/* never reply with a negative response to broadcast queries */
return;
}
}
- /* name is directed query, or it's self, or it's a PDC type name */
+ /* name is directed query, or it's self, or it's a PDC type name, or
+ we're replying on behalf of a caller because they are on a different
+ subnet and cannot hear the broadcast. XXXX lp_wins_proxy should be
+ switched off in environments where broadcasts are forwarded */
+
ttl = n->death_time - p->timestamp;
retip = n->ip;
nb_flags = n->nb_flags;
@@ -811,169 +1310,349 @@ void reply_name_query(struct packet_struct *p)
}
+/****************************************************************************
+ response from a name query server check. commands of type NAME_QUERY_MST_SRV_CHK,
+ 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)
+{
+ /* issue another command: this time to do a name status check */
+
+ enum cmd_type cmd = (n->cmd_type == NAME_QUERY_MST_SRV_CHK) ?
+ NAME_STATUS_MASTER_CHECK : NAME_STATUS_CHECK;
+
+ /* 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,
+ False,False,n->to_ip);
+}
/****************************************************************************
-response from a name query
+ response from a name status check. commands of type NAME_STATUS_MASTER_CHECK
+ and NAME_STATUS_CHECK dealt with here.
****************************************************************************/
-static void response_netbios_packet(struct packet_struct *p)
+static void response_name_status_check(struct in_addr ip,
+ struct nmb_packet *nmb, BOOL bcast,
+ struct response_record *n, struct subnet_record *d)
{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
- char *qname = question->name;
- BOOL bcast = nmb->header.nm_flags.bcast;
- struct name_response_record *n;
+ /* NMB_STATUS arrives: contains workgroup name and server name required.
+ amongst other things. */
- if (nmb->answers == NULL)
+ struct nmb_name name;
+ fstring serv_name;
+
+ if (interpret_node_status(d,nmb->answers->rdata,
+ &name,0x1d,serv_name,ip,bcast))
{
- DEBUG(3,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
- inet_ntoa(p->ip),
- BOOLSTR(bcast)));
- return;
+ if (*serv_name)
+ {
+ sync_server(n->cmd_type,serv_name,
+ name.name,name.name_type, n->to_ip);
}
-
- if (nmb->answers->rr_type == NMB_STATUS) {
- DEBUG(3,("Name status "));
}
-
- if (nmb->answers->rr_type == NMB_QUERY) {
- DEBUG(3,("Name query "));
+ else
+ {
+ DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
}
-
- if (nmb->answers->rr_type == NMB_REG) {
- DEBUG(3,("Name registration "));
}
- if (nmb->answers->rr_type == NMB_REL) {
- DEBUG(3,("Name release "));
- }
- DEBUG(3,("response for %s from %s (bcast=%s)\n",
- namestr(&nmb->answers->rr_name),
- inet_ntoa(p->ip),
- BOOLSTR(bcast)));
+/****************************************************************************
+ response from a name query to sync browse lists or to update our netbios
+ entry. commands 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)
+{
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->to_ip)));
- if (!(n = find_name_query(nmb->header.name_trn_id))) {
- DEBUG(3,("unknown response (received too late or from nmblookup?)\n"));
- 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]);
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+
+ if (n->cmd_type == NAME_QUERY_SYNC)
+ {
+ struct work_record *work = NULL;
+ if ((work = find_workgroupstruct(d, ans_name->name, False)))
+ {
+ /* the server is there: sync quick before it (possibly) dies! */
+ sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
+ found_ip);
+ }
}
+ else
+ {
+ /* update our netbios name list */
+ add_netbios_entry(d, ans_name->name, ans_name->name_type,
+ nb_flags,GET_TTL(0),STATUS_QUERY,
+ found_ip,False,!bcast);
+ }
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE!\n"));
- n->num_msgs++; /* count number of responses received */
+ if (n->cmd_type == 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
+ */
+ }
+ }
+}
- switch (n->cmd_type)
+/****************************************************************************
+ report the response record type
+ ****************************************************************************/
+static void debug_rr_type(int rr_type)
{
- case MASTER_SERVER_CHECK : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
- case SERVER_CHECK : DEBUG(4,("SERVER_CHECK\n")); break;
- case FIND_MASTER : DEBUG(4,("FIND_MASTER\n")); break;
+ 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;
+ default : DEBUG(1,("wrong response packet type received")); break;
+ }
+}
+
+/****************************************************************************
+ report the response record nmbd command type
+ ****************************************************************************/
+static void debug_cmd_type(int cmd_type)
+{
+ /* report the command type to help debugging */
+ switch (cmd_type)
+ {
+ case NAME_QUERY_MST_SRV_CHK : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
+ case NAME_QUERY_SRV_CHK : DEBUG(4,("NAME_QUERY_SRV_CHK\n")); break;
+ case NAME_QUERY_FIND_MST : DEBUG(4,("NAME_QUERY_FIND_MST\n")); break;
case NAME_STATUS_MASTER_CHECK: DEBUG(4,("NAME_STAT_MST_CHK\n")); break;
case NAME_STATUS_CHECK : DEBUG(4,("NAME_STATUS_CHECK\n")); break;
- case CHECK_MASTER : DEBUG(4,("CHECK_MASTER\n")); break;
- case NAME_CONFIRM_QUERY : DEBUG(4,("NAME_CONFIRM_QUERY\n")); break;
+ case NAME_QUERY_MST_CHK : DEBUG(4,("NAME_QUERY_MST_CHK\n")); break;
+ case NAME_REGISTER : DEBUG(4,("NAME_REGISTER\n")); break;
+ case NAME_RELEASE : DEBUG(4,("NAME_RELEASE\n")); break;
+ case NAME_QUERY_CONFIRM : DEBUG(4,("NAME_QUERY_CONFIRM\n")); break;
+ case NAME_QUERY_SYNC : DEBUG(4,("NAME_QUERY_SYNC\n")); break;
default: break;
}
- switch (n->cmd_type)
+}
+
+/****************************************************************************
+ report any problems with the fact that a response has been received.
+
+ (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)
{
- case MASTER_SERVER_CHECK:
- case SERVER_CHECK:
- case FIND_MASTER:
- {
- if (nmb->answers->rr_type == NMB_QUERY)
- {
- enum cmd_type cmd = (n->cmd_type == MASTER_SERVER_CHECK) ?
- NAME_STATUS_MASTER_CHECK :
- NAME_STATUS_CHECK;
- if (n->num_msgs > 1 && !strequal(qname,n->name.name))
+ switch (nmb->answers->rr_type)
{
- /* one subnet, one master browser per workgroup */
- /* XXXX force an election? */
- DEBUG(1,("more than one master browser replied!\n"));
+ case NMB_REL:
+ {
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one release name response received!\n"));
+ return True;
}
-
- /* initiate a name status check on the server that replied */
- queue_netbios_packet(ClientNMB,NMB_STATUS, cmd,
- nmb->answers->rr_name.name,
- nmb->answers->rr_name.name_type,0,
- False,False,n->to_ip);
+ break;
}
- else
+
+ case NMB_REG:
{
- DEBUG(1,("Name query reply has wrong answer rr_type\n"));
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one register name response received!\n"));
+ return True;
}
break;
}
- case NAME_STATUS_MASTER_CHECK:
- case NAME_STATUS_CHECK:
+ case NMB_QUERY:
{
- if (nmb->answers->rr_type == NMB_STATUS)
+ if (n->num_msgs > 1)
{
- /* NMB_STATUS arrives: contains the workgroup name
- and server name we require */
- struct nmb_name name;
- fstring serv_name;
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ int nb_flags = nmb->answers->rdata[0];
- if (interpret_node_status(nmb->answers->rdata,
- &name,0x1d,serv_name,p->ip))
+ if ((!NAME_GROUP(nb_flags)))
{
- if (*serv_name)
+ /* 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->cmd_type)
{
- sync_server(n->cmd_type,serv_name,
- name.name,name.name_type,
- n->to_ip);
+ case NAME_QUERY_MST_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_MST_CHK:
+ /* don't do case NAME_QUERY_FIND_MST: MSBROWSE isn't a unique name. */
+ {
+ 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
{
- DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
+ /* 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;
}
}
- else
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ check that the response received is compatible with the response record
+ ****************************************************************************/
+static BOOL response_compatible(struct response_record *n,
+ struct nmb_packet *nmb)
{
- DEBUG(1,("Name status reply has wrong answer rr_type\n"));
+ switch (n->cmd_type)
+ {
+ case NAME_RELEASE:
+ {
+ if (nmb->answers->rr_type != NMB_REL)
+ {
+ DEBUG(1,("Name release reply has wrong answer rr_type\n"));
+ return False;
}
break;
}
- case CHECK_MASTER:
+ case NAME_REGISTER:
{
- /* 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\n",
- namestr(&n->name),
- inet_ntoa(n->to_ip)));
- if (n->num_msgs > 1)
+ if (nmb->answers->rr_type != NMB_REG)
{
- DEBUG(1,("more than one master browser!\n"));
+ DEBUG(1,("Name register reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
}
+
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_SYNC:
+ case NAME_QUERY_MST_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ 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;
}
- case NAME_CONFIRM_QUERY:
+
+ case NAME_STATUS_MASTER_CHECK:
+ case NAME_STATUS_CHECK:
{
- DEBUG(4, ("Name query at WINS server: %s at %s - ",
- namestr(&n->name),
- inet_ntoa(n->to_ip)));
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ if (nmb->answers->rr_type != NMB_STATUS)
{
- int nb_flags = nmb->answers->rdata[0];
- struct in_addr found_ip;
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
+ DEBUG(1,("Name status reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
- DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
- add_netbios_entry(nmb->answers->rr_name.name,
- nmb->answers->rr_name.name_type,
- nb_flags,GET_TTL(0),STATUS_QUERY,found_ip,False);
+ default:
+ {
+ DEBUG(0,("unknown command received in response_netbios_packet\n"));
+ break;
}
- else
+ }
+ return True;
+}
+
+
+/****************************************************************************
+ 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)
+{
+ switch (n->cmd_type)
{
- DEBUG(4, (" NEGATIVE RESPONSE\n"));
+ case NAME_RELEASE:
+ {
+ response_name_release(d, p);
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ response_name_reg(d, p);
+ break;
}
+ case NAME_QUERY_MST_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_FIND_MST:
+ {
+ response_server_check(ans_name, n, d);
break;
}
+
+ case NAME_STATUS_MASTER_CHECK:
+ case NAME_STATUS_CHECK:
+ {
+ response_name_status_check(p->ip, nmb, bcast, n, d);
+ break;
+ }
+
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_SYNC:
+ {
+ response_name_query_sync(nmb, 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->to_ip)));
+ break;
+ }
+
default:
{
DEBUG(0,("unknown command received in response_netbios_packet\n"));
@@ -984,6 +1663,62 @@ static void response_netbios_packet(struct packet_struct *p)
/****************************************************************************
+ response from a netbios packet.
+ ****************************************************************************/
+static void response_netbios_packet(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ struct nmb_name *ans_name = NULL;
+ char *qname = question->name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct response_record *n;
+ struct subnet_record *d = NULL;
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("response packet: bcast %s not known\n", inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (nmb->answers == NULL)
+ {
+ /* 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)));
+ 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)));
+
+ if (!(n = find_response_record(d,nmb->header.name_trn_id))) {
+ DEBUG(2,("unknown netbios response (received late or from nmblookup?)\n"));
+ return;
+ }
+
+ debug_rr_type(nmb->answers->rr_type);
+
+ n->num_msgs++; /* count number of responses received */
+ n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
+
+ debug_cmd_type(n->cmd_type);
+
+ /* problem checking: multiple responses etc */
+ if (response_problem_check(n, nmb, qname))
+ return;
+
+ /* now check whether the command has received the correct type of response*/
+ if (!response_compatible(n, nmb))
+ return;
+
+ /* now deal with the command */
+ response_process(d, p, n, nmb, bcast, ans_name);
+}
+
+
+/****************************************************************************
process a nmb packet
****************************************************************************/
void process_nmb(struct packet_struct *p)
@@ -994,13 +1729,13 @@ void process_nmb(struct packet_struct *p)
switch (nmb->header.opcode)
{
- case 5:
- case 8:
- case 9:
+ 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_name_reg(p);
+ response_netbios_packet(p); /* response to registration dealt with here */
else
reply_name_reg(p);
break;
@@ -1040,7 +1775,7 @@ void process_nmb(struct packet_struct *p)
break;
}
- case 6:
+ case NMB_REL:
{
if (nmb->header.qdcount==0 || nmb->header.arcount==0)
{
@@ -1049,7 +1784,7 @@ void process_nmb(struct packet_struct *p)
}
if (nmb->header.response)
- response_name_release(p);
+ response_netbios_packet(p); /* response to reply dealt with in here */
else
reply_name_release(p);
break;
diff --git a/source/namework.c b/source/namework.c
index e9e939dd37f..f0fca0071e3 100644
--- a/source/namework.c
+++ b/source/namework.c
@@ -49,6 +49,9 @@ extern int workgroup_count; /* total number of workgroups we know about */
extern struct browse_cache_record *browserlist;
/* this is our domain/workgroup/server database */
+extern struct interface *local_interfaces;
+
+/* this is our domain/workgroup/server database */
extern struct subnet_record *subnetlist;
/* machine comment for host announcements */
@@ -67,9 +70,6 @@ extern int updatecount;
extern time_t StartupTime;
-#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
-#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
-
#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
@@ -158,28 +158,26 @@ void tell_become_backup(void)
/****************************************************************************
find a server responsible for a workgroup, and sync browse lists
**************************************************************************/
-static BOOL sync_browse_entry(struct browse_cache_record *b)
+static void start_sync_browse_entry(struct browse_cache_record *b)
{
struct subnet_record *d;
struct work_record *work;
- /*
- if (!strequal(serv_name, b->name))
- {
- DEBUG(0, ("browser's netbios name (%s) does not match %s (%s)",
- b->name, inet_ntoa(b->ip), serv_name));
- }
- */
- if (!(d = find_domain(b->ip))) return False;
- if (!(work = find_workgroupstruct(d, b->group, False))) return False;
+ if (!(d = find_subnet(b->ip))) return;
+
+ /* only sync if we are the master */
if (AM_MASTER(work)) {
- /* only try to sync browse lists if we are the master, otherwise
- the net could get a little bit too busy */
- sync_browse_lists(work,b->name,0x20,b->ip);
+
+ /* 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,NAME_QUERY_SYNC,
+ b->group,0x20,0,0,
+ False,False,b->ip);
}
- b->synced = True;
- return True;
+ b->synced = True;
}
@@ -193,6 +191,8 @@ void do_browser_lists(void)
time_t t = time(NULL);
if (t-last < 20) return; /* don't do too many of these at once! */
+ /* XXXX equally this period should not be too long
+ the server may die in the intervening gap */
last = t;
@@ -202,12 +202,13 @@ void do_browser_lists(void)
if (b->sync_time < t && b->synced == False) break;
}
- if (!b || b->synced || sync_browse_entry(b))
+ if (b && !b->synced)
{
- /* leave entries (even ones already sync'd) for up to a minute.
- this stops them getting re-sync'd too often */
+ /* sync with the selected entry then remove some dead entries */
+ start_sync_browse_entry(b);
expire_browse_cache(t - 60);
}
+
}
@@ -221,7 +222,7 @@ void sync_server(enum cmd_type cmd, char *serv_name, char *work_name,
{
add_browser_entry(serv_name, name_type, work_name, 0, ip);
- if (cmd == MASTER_SERVER_CHECK)
+ if (cmd == NAME_QUERY_MST_SRV_CHK)
{
/* announce ourselves as a master browser to serv_name */
do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
@@ -231,55 +232,22 @@ void sync_server(enum cmd_type cmd, char *serv_name, char *work_name,
/****************************************************************************
-update workgroup database from a name registration
-**************************************************************************/
-void update_from_reg(char *name, int type, struct in_addr ip)
-{
- /* default server type: minimum guess at requirement XXXX */
-
- DEBUG(3,("update from registration: host %s ip %s type %0x\n",
- name, inet_ntoa(ip), type));
-
- /* workgroup types, but not a chat type */
- if (type >= 0x1b && type <= 0x1e)
- {
- struct work_record *work;
- struct subnet_record *d;
-
- if (!(d = find_domain(ip))) return;
- if (!(work = find_workgroupstruct(d, name, False))) return;
-
- /* request the server to announce if on our subnet */
- if (d->my_interface) announce_request(work, ip);
-
- /* domain master type or master browser type */
- if (type == 0x1b || type == 0x1d)
- {
- struct hostent *hp = gethostbyaddr((char*)&ip, sizeof(ip), AF_INET);
- if (hp) {
- /* gethostbyaddr name may not match netbios name but who cares */
- add_browser_entry(hp->h_name, type, work->work_group, 120, ip);
- }
- }
- }
-}
-
-
-/****************************************************************************
add the default workgroup into my domain
**************************************************************************/
-void add_my_domains(char *group)
+void add_my_subnets(char *group)
{
- int n,i;
- struct in_addr *ip;
+ struct interface *i;
+
+ /* add or find domain on our local subnet, in the default workgroup */
if (*group == '*') return;
- n = iface_count();
- for (i=0;i<n;i++) {
- ip = iface_n_ip(i);
- if (!ip) return;
- add_subnet_entry(*iface_bcast(*ip),*iface_nmask(*ip),lp_workgroup(),True);
+ /* 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)
+ {
+ add_subnet_entry(i->bcast,i->nmask,group, True, False);
}
}
@@ -464,7 +432,7 @@ static void process_announce(struct packet_struct *p,int command,char *buf)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
int update_count = CVAL(buf,0);
int ttl = IVAL(buf,1)/1000;
char *name = buf+5;
@@ -545,8 +513,8 @@ static void process_master_announce(struct packet_struct *p,char *buf)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
- struct subnet_record *mydomain = find_domain(*iface_bcast(ip));
+ struct subnet_record *d = find_subnet(ip);
+ struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
char *name = buf;
struct work_record *work;
name[15] = 0;
@@ -613,7 +581,7 @@ static void process_rcv_backup_list(struct packet_struct *p,char *buf)
DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
- if ((d = find_domain(back_ip)))
+ if ((d = find_subnet(back_ip)))
{
struct subnet_record *d1;
for (d1 = subnetlist; d1; d1 = d1->next)
@@ -623,8 +591,8 @@ static void process_rcv_backup_list(struct packet_struct *p,char *buf)
{
if (work->token == Index)
{
- queue_netbios_packet(ClientNMB,NMB_QUERY,SERVER_CHECK,
- work->work_group,0x1d,0,
+ queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
+ work->work_group,0x1d,0,0,
False,False,back_ip);
return;
}
@@ -714,7 +682,7 @@ static void process_reset_browser(struct packet_struct *p,char *buf)
{
if (AM_MASTER(work))
{
- become_nonmaster(d,work);
+ become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
}
}
}
@@ -729,7 +697,7 @@ static void process_reset_browser(struct packet_struct *p,char *buf)
struct work_record *work;
for (work=d->workgrouplist;work;work=remove_workgroup(d,work));
}
- add_my_domains(lp_workgroup());
+ add_my_subnets(lp_workgroup());
}
/* stop browsing altogether. i don't think this is a good idea! */
@@ -751,7 +719,7 @@ static void process_announce_request(struct packet_struct *p,char *buf)
struct dgram_packet *dgram = &p->packet.dgram;
struct work_record *work;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
int token = CVAL(buf,0);
char *name = buf+1;
@@ -783,7 +751,7 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
char *logname,*q;
char *reply_name;
BOOL add_slashes = False;
diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c
index a20c4eb9993..1d541ea95f0 100644
--- a/source/nmbd/nmbd.c
+++ b/source/nmbd/nmbd.c
@@ -69,6 +69,9 @@ static int sig_term()
/* remove all samba names, with wins server if necessary. */
remove_my_names();
+ /* announce all server entries as 0 time-to-live, 0 type */
+ remove_my_servers();
+
/* XXXX don't care if we never receive a response back... yet */
/* XXXX other things: if we are a master browser, force an election? */
@@ -204,6 +207,7 @@ BOOL reload_services(BOOL test)
}
load_interfaces();
+ add_subnet_interfaces();
return(ret);
}
@@ -286,9 +290,13 @@ static void load_hosts_file(char *fname)
ipmask = *iface_nmask(ipaddr);
if (group) {
- add_subnet_entry(ipaddr, ipmask, name, True);
+ add_subnet_entry(ipaddr, ipmask, name, True, True);
} else {
- add_netbios_entry(name,0x20,NB_ACTIVE,0,source,ipaddr,True);
+ struct subnet_record *d = find_subnet(ipaddr);
+ if (d)
+ {
+ add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
+ }
}
}
}
@@ -316,16 +324,19 @@ static void process(void)
announce_host();
#if 0
- /* what was this stuff supposed to do? It sent
+ /* XXXX what was this stuff supposed to do? It sent
ANN_GetBackupListReq packets which I think should only be
sent when trying to find out who to browse with */
+
announce_backup();
#endif
announce_master();
+ query_refresh_names();
+
expire_names_and_servers();
- expire_netbios_response_entries(t-10);
+ expire_netbios_response_entries();
refresh_my_names(t);
write_browse_list();
@@ -514,7 +525,7 @@ static void usage(char *pname)
return(-1);
if (*group)
- add_my_domains(group);
+ add_my_subnets(group);
if (!is_daemon && !is_a_socket(0)) {
DEBUG(0,("standard input is not a socket, assuming -D option\n"));
@@ -535,16 +546,22 @@ static void usage(char *pname)
DEBUG(3,("Loaded hosts file\n"));
}
+
+
if (!*ServerComment)
strcpy(ServerComment,"Samba %v");
string_sub(ServerComment,"%v",VERSION);
string_sub(ServerComment,"%h",myhostname);
add_my_names();
- add_my_domains(lp_workgroup());
+ add_my_subnets(lp_workgroup());
DEBUG(3,("Checked names\n"));
+ load_netbios_names();
+
+ DEBUG(3,("Loaded names\n"));
+
write_browse_list();
DEBUG(3,("Dumped names\n"));
diff --git a/source/nmbsync.c b/source/nmbsync.c
index 55cc9a04e99..2a95c60d59a 100644
--- a/source/nmbsync.c
+++ b/source/nmbsync.c
@@ -102,6 +102,7 @@ static BOOL add_info(struct subnet_record *d, struct work_record *work, int serv
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));
@@ -137,10 +138,11 @@ static BOOL add_info(struct subnet_record *d, struct work_record *work, int serv
log in on the remote server's SMB port to their IPC$ service,
do a NetServerEnum and update our server and workgroup databases.
******************************************************************/
-void sync_browse_lists(struct work_record *work, char *name, int nm_type,
- struct in_addr ip)
+void sync_browse_lists(struct subnet_record *d, struct work_record *work,
+ char *name, int nm_type, struct in_addr ip)
{
- struct subnet_record *d;
+ if (!d || !work || !AM_MASTER(work)) return;
+
pid = getpid();
uid = getuid();
gid = getgid();
@@ -159,8 +161,6 @@ void sync_browse_lists(struct work_record *work, char *name, int nm_type,
if (zero_ip(dest_ip)) return;
have_ip = True;
- if (!(d = find_domain(ip))) return;
-
connect_as_ipc = True;
/* connect as server and get domains, then servers */
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index f4aaa16e6a4..48b9d062e86 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -129,6 +129,7 @@ typedef struct
char *szSmbrun;
char *szWINSserver;
char *szInterfaces;
+ char *szRemoteInterfaces;
int max_log_size;
int mangled_stack;
int max_xmit;
@@ -366,6 +367,7 @@ struct parm_struct
{"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL},
{"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL},
{"interfaces", P_STRING, P_GLOBAL, &Globals.szInterfaces, NULL},
+ {"remote interfaces",P_STRING, P_GLOBAL, &Globals.szRemoteInterfaces,NULL},
{"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL},
{"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL},
{"smbrun", P_STRING, P_GLOBAL, &Globals.szSmbrun, NULL},
@@ -704,6 +706,7 @@ FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet)
FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript)
FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
FN_GLOBAL_STRING(lp_interfaces,&Globals.szInterfaces)
+FN_GLOBAL_STRING(lp_remote_interfaces,&Globals.szRemoteInterfaces)
FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk
index 78f3fa080b3..200d5bd050b 100644
--- a/source/script/mkproto.awk
+++ b/source/script/mkproto.awk
@@ -1,8 +1,3 @@
-# generate prototypes for Samba C code
-# tridge, June 1996
-# added comment for each source file for use as crude index
-# dan, 17 June 1996
-
BEGIN {
inheader=0;
current_file="";
diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c
index 4d7c6e85349..4fbd8390368 100644
--- a/source/utils/nmblookup.c
+++ b/source/utils/nmblookup.c
@@ -93,7 +93,7 @@ static void usage(void)
int main(int argc,char *argv[])
{
int opt;
- unsigned int lookup_type = 0;
+ unsigned int lookup_type = 0x0;
pstring lookup;
extern int optind;
extern char *optarg;