diff options
-rw-r--r-- | source3/include/nameserv.h | 109 | ||||
-rw-r--r-- | source3/include/proto.h | 659 | ||||
-rw-r--r-- | source3/include/smb.h | 9 | ||||
-rw-r--r-- | source3/nameannounce.c | 196 | ||||
-rw-r--r-- | source3/namedb.c | 165 | ||||
-rw-r--r-- | source3/nameelect.c | 67 | ||||
-rw-r--r-- | source3/nameresp.c | 384 | ||||
-rw-r--r-- | source3/nameserv.c | 1169 | ||||
-rw-r--r-- | source3/namework.c | 118 | ||||
-rw-r--r-- | source3/nmbd/nmbd.c | 29 | ||||
-rw-r--r-- | source3/nmbsync.c | 10 | ||||
-rw-r--r-- | source3/param/loadparm.c | 3 | ||||
-rw-r--r-- | source3/script/mkproto.awk | 5 | ||||
-rw-r--r-- | source3/utils/nmblookup.c | 2 |
14 files changed, 2320 insertions, 605 deletions
diff --git a/source3/include/nameserv.h b/source3/include/nameserv.h index 8882948ff4..03bb521558 100644 --- a/source3/include/nameserv.h +++ b/source3/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/source3/include/proto.h b/source3/include/proto.h index e69de29bb2..ce02be129f 100644 --- a/source3/include/proto.h +++ b/source3/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/source3/include/smb.h b/source3/include/smb.h index b9dd13a802..0e9c9983d2 100644 --- a/source3/include/smb.h +++ b/source3/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/source3/nameannounce.c b/source3/nameannounce.c index 9b0ef7067f..5163c4aea9 100644 --- a/source3/nameannounce.c +++ b/source3/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/source3/namedb.c b/source3/namedb.c index ea5b13a800..a1442c0f03 100644 --- a/source3/namedb.c +++ b/source3/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/source3/nameelect.c b/source3/nameelect.c index 1832240a11..c841d9b7a6 100644 --- a/source3/nameelect.c +++ b/source3/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/source3/nameresp.c b/source3/nameresp.c index b244d81159..31df799691 100644 --- a/source3/nameresp.c +++ b/source3/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/source3/nameserv.c b/source3/nameserv.c index 22c1e7dbba..7b72f93952 100644 --- a/source3/nameserv.c +++ b/source3/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/source3/namework.c b/source3/namework.c index e9e939dd37..f0fca0071e 100644 --- a/source3/namework.c +++ b/source3/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/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c index a20c4eb999..1d541ea95f 100644 --- a/source3/nmbd/nmbd.c +++ b/source3/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/source3/nmbsync.c b/source3/nmbsync.c index 55cc9a04e9..2a95c60d59 100644 --- a/source3/nmbsync.c +++ b/source3/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/source3/param/loadparm.c b/source3/param/loadparm.c index f4aaa16e6a..48b9d062e8 100644 --- a/source3/param/loadparm.c +++ b/source3/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/source3/script/mkproto.awk b/source3/script/mkproto.awk index 78f3fa080b..200d5bd050 100644 --- a/source3/script/mkproto.awk +++ b/source3/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/source3/utils/nmblookup.c b/source3/utils/nmblookup.c index 4d7c6e8534..4fbd839036 100644 --- a/source3/utils/nmblookup.c +++ b/source3/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; |