back into the main tree.
For the cvs logs of all the files starting nmbd_*.c, look
in the JRA_NMBD_REWRITE branch. That branch has now been
discontinued.
Jeremy.
{
#ifdef USENMB
/* Try and resolve the name with the netbios server */
- int bcast;
+ int bcast, count;
+ struct in_addr *ip_list;
if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3,
interpret_addr(lp_socket_address()))) != -1) {
set_socket_options(bcast, "SO_BROADCAST");
- if (name_query(bcast, host, name_type, True, True, *iface_bcast(dest_ip),
- &dest_ip,0)) {
- failed = False;
+ if ((ip_list = name_query(bcast, host, name_type, True, True, *iface_bcast(dest_ip),
+ &count,0)) {
+ dest_ip = ip_list[0];
+ free(ip_list);
+ failed = False;
}
close (bcast);
}
+#ifndef _NAMESERV_H_
+#define _NAMESERV_H_
/*
Unix SMB/Netbios implementation.
Version 1.9.
*/
-#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+#define PERMANENT_TTL 0
/* NTAS uses 2, NT uses 1, WfWg uses 0 */
#define MAINTAIN_LIST 2
#define MAX_DGRAM_SIZE (576) /* tcp/ip datagram limit is 576 bytes */
#define MIN_DGRAM_SIZE 12
-#define NMB_QUERY 0x20
-#define NMB_STATUS 0x21
+/*********************************************************
+ Types of reply packet.
+**********************************************************/
+
+enum netbios_reply_type_code { NMB_QUERY, NMB_STATUS, NMB_REG, NMB_REG_REFRESH,
+ NMB_REL, NMB_WAIT_ACK, NMB_MULTIHOMED_REG,
+ WINS_REG, WINS_QUERY };
+
+/* From rfc1002, 4.2.1.2 */
+/* Question types. */
+#define QUESTION_TYPE_NB_QUERY 0x20
+#define QUESTION_TYPE_NB_STATUS 0x21
+
+/* Question class */
+#define QUESTION_CLASS_IN 0x1
+
+/* Opcode definitions */
+#define NMB_NAME_QUERY_OPCODE 0x0
+#define NMB_NAME_REG_OPCODE 0x05 /* see rfc1002.txt 4.2.2,3,5,6,7,8 */
+#define NMB_NAME_RELEASE_OPCODE 0x06 /* see rfc1002.txt 4.2.9,10,11 */
+#define NMB_WACK_OPCODE 0x07 /* see rfc1002.txt 4.2.16 */
+/* Ambiguity in rfc1002 about which of these is correct. */
+/* WinNT uses 8 by default but can be made to use 9. */
+#define NMB_NAME_REFRESH_OPCODE_8 0x08 /* see rfc1002.txt 4.2.4 */
+#define NMB_NAME_REFRESH_OPCODE_9 0x09 /* see rfc1002.txt 4.2.4 */
+#define NMB_NAME_MULTIHOMED_REG_OPCODE 0x0F /* Invented by Microsoft. */
-#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.16 */
/* XXXX what about all the other types?? 0x1, 0x2, 0x3, 0x4, 0x8? */
-#define FIND_ANY_NAME 0
-#define FIND_SELF_NAME 1
+/* Resource record types. rfc1002 4.2.1.3 */
+#define RR_TYPE_A 0x1
+#define RR_TYPE_NS 0x2
+#define RR_TYPE_NULL 0xA
+#define RR_TYPE_NB 0x20
+#define RR_TYPE_NBSTAT 0x21
+
+/* Resource record class. */
+#define RR_CLASS_IN 0x1
/* NetBIOS flags */
#define NB_GROUP 0x80
#define NB_ACTIVE 0x04
#define NB_CONFL 0x08
#define NB_DEREG 0x10
-#define NB_BFLAG 0x00 /* broadcast node type */
-#define NB_PFLAG 0x20 /* point-to-point node type */
-#define NB_MFLAG 0x40 /* mixed bcast & p-p node type */
-#define NB_HFLAG 0x60 /* microsoft 'hybrid' node type */
-#define NB_FLGMSK 0x60
+#define NB_BFLAG 0x00 /* Broadcast node type. */
+#define NB_PFLAG 0x20 /* Point-to-point node type. */
+#define NB_MFLAG 0x40 /* Mixed bcast & p-p node type. */
+#define NB_HFLAG 0x60 /* Microsoft 'hybrid' node type. */
+#define NB_NODETYPEMASK 0x60
+/* Mask applied to outgoing NetBIOS flags. */
+#define NB_FLGMSK 0xE0
+
+/* NetBIOS flag identifier. */
+#define NAME_GROUP(p) ((p)->nb_flags & NB_GROUP)
+#define NAME_BFLAG(p) (((p)->nb_flags & NB_NODETYPEMASK) == NB_BFLAG)
+#define NAME_PFLAG(p) (((p)->nb_flags & NB_NODETYPEMASK) == NB_PFLAG)
+#define NAME_MFLAG(p) (((p)->nb_flags & NB_NODETYPEMASK) == NB_MFLAG)
+#define NAME_HFLAG(p) (((p)->nb_flags & NB_NODETYPEMASK) == NB_HFLAG)
+
+/* Samba name state for a name in a namelist. */
+#define NAME_IS_ACTIVE(p) ((p)->nb_flags & NB_ACTIVE)
+#define NAME_IN_CONFLICT(p) ((p)->nb_flags & NB_CONFL)
+#define NAME_IS_DEREGISTERING(p) ((p)->nb_flags & NB_DEREG)
+
+/* Error codes for NetBIOS requests. */
+#define FMT_ERR 0x1 /* Packet format error. */
+#define SRV_ERR 0x2 /* Internal server error. */
+#define NAM_ERR 0x3 /* Name does not exist. */
+#define IMP_ERR 0x4 /* Request not implemented. */
+#define RFS_ERR 0x5 /* Request refused. */
+#define ACT_ERR 0x6 /* Active error - name owned by another host. */
+#define CFT_ERR 0x7 /* Name in conflict error. */
#define REFRESH_TIME (15*60)
#define NAME_POLL_REFRESH_TIME (5*60)
#define NAME_POLL_INTERVAL 15
-/* NetBIOS flag identifier */
-#define NAME_PERMANENT(p) ((p) & NB_PERM)
-#define NAME_ACTIVE(p) ((p) & NB_ACTIVE)
-#define NAME_CONFLICT(p) ((p) & NB_CONFL)
-#define NAME_DEREG(p) ((p) & NB_DEREG)
-#define NAME_GROUP(p) ((p) & NB_GROUP)
-
-#define NAME_BFLAG(p) (((p) & NB_FLGMSK) == NB_BFLAG)
-#define NAME_PFLAG(p) (((p) & NB_FLGMSK) == NB_PFLAG)
-#define NAME_MFLAG(p) (((p) & NB_FLGMSK) == NB_MFLAG)
-#define NAME_HFLAG(p) (((p) & NB_FLGMSK) == NB_HFLAG)
-
-/* server type identifiers */
-#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
-#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
-#define AM_DOMMST(work) (work->ServerType & SV_TYPE_DOMAIN_MASTER)
-#define AM_DOMMEM(work) (work->ServerType & SV_TYPE_DOMAIN_MEMBER)
-
-/* microsoft browser NetBIOS name */
+/* Workgroup state identifiers. */
+#define AM_POTENTIAL_MASTER_BROWSER(work) ((work)->mst_state == MST_POTENTIAL)
+#define AM_LOCAL_MASTER_BROWSER(work) ((work)->mst_state == MST_BROWSER)
+#define AM_DOMAIN_MASTER_BROWSER(work) ((work)->dom_state == DOMAIN_MST)
+#define AM_DOMAIN_MEMBER(work) ((work)->log_state == LOGON_SRV)
+
+/* Microsoft browser NetBIOS name. */
#define MSBROWSE "\001\002__MSBROWSE__\002"
-/* mail slots */
+/* Mail slots. */
#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
#define NET_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NETLOGON"
#define NT_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NTLOGON"
-enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
+/* Samba definitions for find_name_on_subnet(). */
+#define FIND_ANY_NAME 0
+#define FIND_SELF_NAME 1
+
+/*
+ * The different name types that can be in namelists.
+ *
+ * SELF_NAME should only be on the broadcast and unicast subnets.
+ * LMHOSTS_NAME should only be in the remote_broadcast_subnet.
+ * REGISTER_NAME, DNS_NAME, DNSFAIL_NAME should only be in the wins_server_subnet.
+ * WINS_PROXY_NAME should only be on the broadcast subnets.
+ * PERMANENT_NAME can be on all subnets except remote_broadcast_subnet.
+ *
+ */
+
+enum name_source {LMHOSTS_NAME, REGISTER_NAME, SELF_NAME, DNS_NAME,
+ DNSFAIL_NAME, PERMANENT_NAME, WINS_PROXY_NAME};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
enum master_state
{
- MST_POTENTIAL,
- MST_BACK,
- MST_MSB,
- MST_BROWSER
+ MST_NONE,
+ MST_POTENTIAL,
+ MST_BACKUP,
+ MST_MSB,
+ MST_BROWSER,
+ MST_UNBECOMING_MASTER
};
enum domain_state
{
- DOMAIN_NONE,
- DOMAIN_WAIT,
- DOMAIN_MST
+ DOMAIN_NONE,
+ DOMAIN_WAIT,
+ DOMAIN_MST
};
enum logon_state
{
- LOGON_NONE,
- LOGON_WAIT,
- LOGON_SRV
-};
-
-enum state_type
-{
- NAME_STATUS_DOM_SRV_CHK,
- NAME_STATUS_SRV_CHK,
- NAME_REGISTER_CHALLENGE,
- NAME_REGISTER,
- NAME_RELEASE,
- NAME_QUERY_CONFIRM,
- NAME_QUERY_SYNC_LOCAL,
- NAME_QUERY_SYNC_REMOTE,
- NAME_QUERY_DOM_SRV_CHK,
- NAME_QUERY_SRV_CHK,
- NAME_QUERY_FIND_MST,
- NAME_QUERY_MST_CHK,
- NAME_QUERY_DOMAIN
+ LOGON_NONE,
+ LOGON_WAIT,
+ LOGON_SRV
};
-/* a netbios name structure */
+/* A netbios name structure. */
struct nmb_name {
char name[17];
char scope[64];
- int name_type;
+ unsigned int name_type;
};
-/* a netbios flags + ip address structure */
-/* this is used for multi-homed systems and for internet group names */
-struct nmb_ip
-{
- struct in_addr ip; /* ip address of host that owns this name */
- uint16 nb_flags; /* netbios flags */
-};
-
-/* this is the structure used for the local netbios name list */
+/* This is the structure used for the local netbios name list. */
struct name_record
{
struct name_record *next;
struct name_record *prev;
- struct nmb_name name; /* the netbios name */
- struct nmb_ip *ip_flgs; /* the ip + flags */
- int num_ips; /* number of ip+flags entries */
+ struct subnet_record *subnet;
- enum name_source source; /* where the name came from */
+ struct nmb_name name; /* The netbios name. */
+ uint16 nb_flags; /* Netbios flags. */
+ int num_ips; /* Number of ip entries. */
+ struct in_addr *ip; /* The ip list for this name. */
- time_t death_time; /* time record must be removed (do not remove if 0) */
- time_t refresh_time; /* time record should be refreshed */
+ enum name_source source; /* Where the name came from. */
+
+ time_t death_time; /* The time the record must be removed (do not remove if 0). */
+ time_t refresh_time; /* The time the record should be refreshed. */
};
struct subnet_record;
-/* browse and backup server cache for synchronising browse list */
+/* Browser cache for synchronising browse lists. */
struct browse_cache_record
{
- struct browse_cache_record *next;
- struct browse_cache_record *prev;
-
- pstring name;
- int type;
- pstring group;
- struct in_addr ip;
- time_t sync_time;
- BOOL synced;
- BOOL local;
- struct subnet_record *subnet;
+ struct browse_cache_record *next;
+ struct browse_cache_record *prev;
+
+ pstring lmb_name;
+ pstring work_group;
+ struct in_addr ip;
+ time_t sync_time;
+ time_t death_time; /* The time the record must be removed. */
};
-/* this is used to hold the list of servers in my domain, and is */
-/* contained within lists of domains */
+/* This is used to hold the list of servers in my domain, and is
+ contained within lists of domains. */
+
struct server_record
{
struct server_record *next;
struct server_record *prev;
+ struct subnet_record *subnet;
+
struct server_info_struct serv;
time_t death_time;
};
-/* a workgroup structure. it contains a list of servers */
+/* A workgroup structure. It contains a list of servers. */
struct work_record
{
struct work_record *next;
struct work_record *prev;
+ struct subnet_record *subnet;
+
struct server_record *serverlist;
- /* stage of development from non-local-master up to local-master browser */
+ /* Stage of development from non-local-master up to local-master browser. */
enum master_state mst_state;
- /* stage of development from non-domain-master to domain master browser */
+ /* Stage of development from non-domain-master to domain-master browser. */
enum domain_state dom_state;
- /* stage of development from non-logon-server to logon server */
+ /* Stage of development from non-logon-server to logon server. */
enum logon_state log_state;
- /* work group info */
+ /* Work group info. */
fstring work_group;
- int token; /* used when communicating with backup browsers */
- int ServerType;
+ int token; /* Used when communicating with backup browsers. */
+ fstring local_master_browser_name; /* Current local master browser. */
- /* announce info */
+ /* Announce info. */
time_t lastannounce_time;
int announce_interval;
BOOL needannounce;
+ /* Timeout time for this workgroup. 0 means permanent. */
+ time_t death_time;
- /* election info */
+ /* Election info */
BOOL RunningElection;
BOOL needelection;
int ElectionCount;
uint32 ElectionCriterion;
+
+ /* Domain master browser info. Used for efficient syncs. */
+ struct nmb_name dmb_name;
+ struct in_addr dmb_addr;
};
-/* initiated name queries recorded in this list to track any responses... */
-/* sadly, we need to group everything together. i suppose that if this
- gets unwieldy, then a union ought to be considered. oh for c++... */
+/* typedefs needed to define copy & free functions for userdata. */
+struct userdata_struct;
+
+typedef struct userdata_struct * (*userdata_copy_fn)(struct userdata_struct *);
+typedef void (*userdata_free_fn)(struct userdata_struct *);
+
+/* Structure to define any userdata passed around. */
+
+struct userdata_struct {
+ userdata_copy_fn copy_fn;
+ userdata_free_fn free_fn;
+ unsigned int userdata_len;
+ char data[1];
+};
+
+struct response_record;
+struct packet_struct;
+struct res_rec;
+
+/* typedef to define the function called when this response packet comes in. */
+typedef void (*response_function)(struct subnet_record *, struct response_record *,
+ struct packet_struct *);
+
+/* typedef to define the function called when this response record times out. */
+typedef void (*timeout_response_function)(struct subnet_record *,
+ struct response_record *);
+
+/* typedef to define the function called when the request that caused this
+ response record to be created is successful. */
+typedef void (*success_function)(struct subnet_record *, struct userdata_struct *, ...);
+
+/* typedef to define the function called when the request that caused this
+ response record to be created is unsuccessful. */
+typedef void (*fail_function)(struct subnet_record *, struct response_record *, ...);
+
+/* List of typedefs for success and fail functions of the different query
+ types. Used to catch any compile time prototype errors. */
+
+typedef void (*register_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ uint16,
+ int,
+ struct in_addr);
+typedef void (*register_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*release_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ struct in_addr);
+typedef void (*release_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*refresh_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ uint16,
+ int,
+ struct in_addr);
+typedef void (*refresh_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*query_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ struct in_addr,
+ struct res_rec *answers);
+
+typedef void (*query_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *,
+ int);
+
+typedef void (*node_status_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct res_rec *,
+ struct in_addr);
+typedef void (*node_status_fail_function)( struct subnet_record *,
+ struct response_record *);
+
+/* Initiated name queries are recorded in this list to track any responses. */
+
struct response_record
{
struct response_record *next;
struct response_record *prev;
uint16 response_id;
- enum state_type state;
- int fd;
- int quest_type;
- struct nmb_name name;
- int nb_flags;
- time_t ttl;
+ /* Callbacks for packets received or not. */
+ response_function resp_fn;
+ timeout_response_function timeout_fn;
- int server_type;
- fstring my_name;
- fstring my_comment;
+ /* Callbacks for the request succeeding or not. */
+ success_function success_fn;
+ fail_function fail_fn;
+
+ struct packet_struct *packet;
- BOOL bcast;
- BOOL recurse;
- struct in_addr send_ip;
- struct in_addr reply_to_ip;
- int reply_id;
+ struct userdata_struct *userdata;
int num_msgs;
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).
+/* A subnet structure. It contains a list of workgroups and netbios names. */
+/*
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
+ own netbios name set. These do NOT interact with other subnet records'
+ netbios names.
*/
+enum subnet_type {
+ NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
+ UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
+ REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
+ WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
+};
+
struct subnet_record
{
struct subnet_record *next;
struct subnet_record *prev;
- struct work_record *workgrouplist; /* list of workgroups */
- struct name_record *namelist; /* list of netbios names */
- struct response_record *responselist; /* list of responses expected */
+ char *subnet_name; /* For Debug identification. */
+ enum subnet_type type; /* To catagorize the subnet. */
+
+ struct work_record *workgrouplist; /* List of workgroups. */
+ struct name_record *namelist; /* List of netbios names. */
+ struct response_record *responselist; /* List of responses expected. */
+
+ BOOL namelist_changed;
+ BOOL work_changed;
struct in_addr bcast_ip;
struct in_addr mask_ip;
int dgram_sock; /* socket to listen for unicast 138. */
};
-/* a resource record */
+/* A resource record. */
struct res_rec {
struct nmb_name rr_name;
int rr_type;
char rdata[MAX_DGRAM_SIZE];
};
-/* define a nmb packet. */
+/* An nmb packet. */
struct nmb_packet
{
struct {
};
-/* a datagram - this normally contains SMB data in the data[] array */
+/* A datagram - this normally contains SMB data in the data[] array. */
+
struct dgram_packet {
struct {
int msg_type;
char data[MAX_DGRAM_SIZE];
};
-/* define a structure used to queue packets. this will be a linked
- list of nmb packets */
+/* Define a structure used to queue packets. This will be a linked
+ list of nmb packets. */
+
struct packet_struct
{
- struct packet_struct *next;
- struct packet_struct *prev;
- BOOL locked;
- struct in_addr ip;
- int port;
- int fd;
- time_t timestamp;
- enum packet_type packet_type;
- union {
- struct nmb_packet nmb;
- struct dgram_packet dgram;
- } packet;
+ struct packet_struct *next;
+ struct packet_struct *prev;
+ BOOL locked;
+ struct in_addr ip;
+ int port;
+ int fd;
+ time_t timestamp;
+ enum packet_type packet_type;
+ union {
+ struct nmb_packet nmb;
+ struct dgram_packet dgram;
+ } packet;
};
/* NETLOGON opcodes */
-#define QUERYFORPDC 7 /* Query for PDC */
-#define QUERYFORPDC_R 12 /* Response to Query for PDC */
+
+#define QUERYFORPDC 7 /* Query for PDC. */
+#define QUERYFORPDC_R 12 /* Response to Query for PDC. */
#define SAMLOGON 18
#define SAMLOGON_R 19
-/* ids for netbios packet types */
+/* Ids for netbios packet types. */
+
#define ANN_HostAnnouncement 1
#define ANN_AnnouncementRequest 2
#define ANN_Election 8
#define ANN_LocalMasterAnnouncement 15
-/* broadcast packet announcement intervals, in minutes */
+/* Broadcast packet announcement intervals, in minutes. */
-/* attempt to add domain logon and domain master names */
+/* Attempt to add domain logon and domain master names. */
#define CHECK_TIME_ADD_DOM_NAMES 5
-/* search for master browsers of workgroups samba knows about,
- except default */
+/* Search for master browsers of workgroups samba knows about,
+ except default. */
#define CHECK_TIME_MST_BROWSE 5
-/* request backup browser announcements from other servers */
+/* Request backup browser announcements from other servers. */
#define CHECK_TIME_ANNOUNCE_BACKUP 15
-/* request host announcements from other servers: min and max of interval */
+/* Request host announcements from other servers: min and max of interval. */
#define CHECK_TIME_MIN_HOST_ANNCE 3
#define CHECK_TIME_MAX_HOST_ANNCE 12
-/* announce as master to WINS server and any Primary Domain Controllers */
+/* Announce as master to WINS server and any Primary Domain Controllers. */
#define CHECK_TIME_MST_ANNOUNCE 15
-/* do all remote announcements this often */
+/* Time between syncs from domain master browser to local master browsers. */
+#define CHECK_TIME_DMB_TO_LMB_SYNC 15
+
+/* Do all remote announcements this often. */
#define REMOTE_ANNOUNCE_INTERVAL 180
-/* Types of machine we can announce as */
+/* Types of machine we can announce as. */
#define ANNOUNCE_AS_NT 1
#define ANNOUNCE_AS_WIN95 2
#define ANNOUNCE_AS_WFW 3
/* Macro's to enumerate subnets either with or without
- the WINS subnet. */
+ the UNICAST subnet. */
extern struct subnet_record *subnetlist;
-extern struct subnet_record *wins_client_subnet;
+extern struct subnet_record *unicast_subnet;
+extern struct subnet_record *wins_server_subnet;
+extern struct subnet_record *remote_broadcast_subnet;
#define FIRST_SUBNET subnetlist
-#define NEXT_SUBNET_EXCLUDING_WINS(x) ((x)->next)
-#define NEXT_SUBNET_INCLUDING_WINS(x) ( ((x) == wins_client_subnet) ? NULL : \
- (((x)->next == NULL) ? wins_client_subnet : \
- (x)->next))
+#define NEXT_SUBNET_EXCLUDING_UNICAST(x) ((x)->next)
+#define NEXT_SUBNET_INCLUDING_UNICAST(x) (get_next_subnet_maybe_unicast((x)))
+/* To be removed. */
+enum state_type { TEST };
+#endif /* _NAMESERV_H_ */
BOOL ismybcast(struct in_addr bcast);
BOOL is_local_net(struct in_addr from);
int iface_count(void);
+BOOL we_are_multihomed();
+struct interface *get_interface(int n);
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);
BOOL lp_bind_interfaces_only(void);
int lp_os_level(void);
int lp_max_ttl(void);
+int lp_max_wins_ttl(void);
+int lp_min_wins_ttl(void);
int lp_max_log_size(void);
int lp_mangledstack(void);
int lp_maxxmit(void);
int reply_sendtxt(char *inbuf,char *outbuf);
int reply_sendend(char *inbuf,char *outbuf);
-/*The following definitions come from nameannounce.c */
+/*The following definitions come from namequery.c */
-void announce_request(struct work_record *work, struct in_addr ip);
-void do_announce_request(char *info, char *to_name, int announce_type,
- int from,
- int to, struct in_addr dest_ip);
-void sync_server(enum state_type state, char *serv_name, char *work_name,
- int name_type,
- struct subnet_record *d,
- struct in_addr ip);
-void announce_my_servers_removed(void);
-void announce_server(struct subnet_record *d, struct work_record *work,
- char *name, char *comment, time_t ttl, int server_type);
-void announce_host(time_t t);
-void reset_announce_timer();
-void announce_master(time_t t);
-void announce_remote(time_t t);
-void browse_sync_remote(time_t t);
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)());
+struct in_addr *name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, int *count, void (*fn)());
-/*The following definitions come from namebrowse.c */
+/*The following definitions come from nmbd.c */
-void expire_browse_cache(time_t t);
-struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
- time_t ttl, struct subnet_record *d,
- struct in_addr ip, BOOL local);
-void do_browser_lists(time_t t);
+BOOL reload_services(BOOL test);
+int main(int argc,char *argv[]);
-/*The following definitions come from namedbname.c */
+/*The following definitions come from nmbd_become_dmb.c */
-void set_samba_nb_type(void);
-BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2);
-BOOL ms_browser_name(char *name, int type);
-void remove_name(struct subnet_record *d, struct name_record *n);
-struct name_record *find_name_on_subnet(struct subnet_record *d,
- struct nmb_name *name, BOOL self_only);
-void dump_names(void);
-void load_netbios_names(void);
-void remove_netbios_name(struct subnet_record *d,
- char *name,int type, enum name_source source);
-struct 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);
-void expire_names(time_t t);
+void unbecome_domain_master(char *workgroup_name);
+void add_domain_names(time_t t);
-/*The following definitions come from namedbresp.c */
-
-void add_response_record(struct subnet_record *d,
- struct response_record *n);
-void remove_response_record(struct subnet_record *d,
- struct response_record *n);
-struct response_record *make_response_queue_record(enum state_type state,
- int id,uint16 fd,
- int quest_type, char *name,int type, int nb_flags, time_t ttl,
- int server_type, char *my_name, char *my_comment,
- BOOL bcast,BOOL recurse,
- struct in_addr send_ip, struct in_addr reply_to_ip,
- int reply_id);
-struct response_record *find_response_record(struct subnet_record **d,
- uint16 id);
+/*The following definitions come from nmbd_become_lmb.c */
-/*The following definitions come from namedbserver.c */
-
-void remove_old_servers(struct work_record *work, time_t t,
- BOOL remove_all);
-struct server_record *find_server(struct work_record *work, char *name);
-struct server_record *add_server_entry(struct subnet_record *d,
- struct work_record *work,
- char *name,int servertype,
- int ttl,char *comment,
- BOOL replace);
-void expire_servers(time_t t);
-
-/*The following definitions come from namedbsubnet.c */
-
-struct subnet_record *find_subnet(struct in_addr ip);
-struct subnet_record *find_subnet_all(struct in_addr ip);
-void add_workgroup_to_subnet( struct subnet_record *d, char *group);
-void add_my_subnets(char *group);
-void write_browse_list(time_t t);
-
-/*The following definitions come from namedbwork.c */
-
-struct work_record *remove_workgroup(struct subnet_record *d,
- struct work_record *work,
- BOOL remove_all_servers);
-struct work_record *find_workgroupstruct(struct subnet_record *d,
- fstring name, BOOL add);
-void dump_workgroups(void);
+void unbecome_local_master_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *released_name,
+ struct in_addr released_ip);
+void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
+ struct nmb_name *fail_name);
+void release_1d_name( struct subnet_record *subrec, char *workgroup_name);
+void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work);
+void become_local_master_browser(struct subnet_record *subrec, struct work_record *work);
+
+/*The following definitions come from nmbd_browserdb.c */
+
+void remove_lmb_browser_entry(struct browse_cache_record *browc);
+void update_browser_death_time(struct browse_cache_record *browc);
+struct browse_cache_record *create_browser_in_lmb_cache(char *work_name, char *browser_name,
+ struct in_addr ip);
+struct browse_cache_record *find_browser_in_lmb_cache( char *browser_name );
+void expire_lmb_browsers(time_t t);
+void remove_workgroup_lmb_browsers(char *work_group);
+
+/*The following definitions come from nmbd_browsesync.c */
+
+void dmb_expire_and_sync_browser_lists(time_t t);
+void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
+ struct work_record *work);
+
+/*The following definitions come from nmbd_elections.c */
-/*The following definitions come from nameelect.c */
-
-void check_master_browser(time_t t);
-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 name_unregister_work(struct subnet_record *d, char *name, int name_type);
-void name_register_work(struct subnet_record *d, char *name, int name_type,
- int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast);
-void become_local_master(struct subnet_record *d, struct work_record *work);
-void become_domain_master(struct subnet_record *d, struct work_record *work);
-void become_logon_server(struct subnet_record *d, struct work_record *work);
-void unbecome_local_master(struct subnet_record *d, struct work_record *work,
- int remove_type);
-void unbecome_domain_master(struct subnet_record *d, struct work_record *work,
- int remove_type);
-void unbecome_logon_server(struct subnet_record *d, struct work_record *work,
- int remove_type);
+void check_master_browser_exists(time_t t);
void run_elections(time_t t);
-void process_election(struct packet_struct *p,char *buf);
+void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf);
BOOL check_elections(void);
-/*The following definitions come from namelogon.c */
+/*The following definitions come from nmbd_incomingdgrams.c */
-void process_logon_packet(struct packet_struct *p,char *buf,int len,
- char *mailslot);
-
-/*The following definitions come from namepacket.c */
-
-void debug_browse_data(char *outbuf, int len);
-void initiate_netbios_packet(uint16 *id,
- int fd,int quest_type,char *name,int name_type,
- int nb_flags,BOOL bcast,BOOL recurse,
- struct in_addr to_ip);
-void reply_netbios_packet(struct packet_struct *p1,int trn_id,
- int rcode, int rcv_code, int opcode,
- BOOL recursion_available,
- BOOL recursion_desired,
- struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
- char *data,int len);
-void queue_packet(struct packet_struct *packet);
-void run_packet_queue();
-BOOL listen_for_packets(BOOL run_election);
-BOOL send_mailslot_reply(BOOL unique, 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 tell_become_backup(void);
+void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_master_browser_announce(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf);
+void process_get_backup_list_request(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf);
+void process_reset_browser(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf);
+void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf);
-/*The following definitions come from namequery.c */
+/*The following definitions come from nmbd_incomingrequests.c */
-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)());
-
-/*The following definitions come from nameresp.c */
-
-void expire_netbios_response_entries(time_t t);
-struct response_record *queue_netbios_pkt_wins(
- int fd,int quest_type,enum state_type state,
- char *name,int name_type,int nb_flags, time_t ttl,
- int server_type, char *my_name, char *my_comment,
- struct in_addr send_ip, struct in_addr reply_to_ip);
-struct response_record *queue_netbios_packet(struct subnet_record *d,
- int fd,int quest_type,enum state_type state,char *name,
- int name_type,int nb_flags, time_t ttl,
- int server_type, char *my_name, char *my_comment,
- BOOL bcast,BOOL recurse,
- struct in_addr send_ip, struct in_addr reply_to_ip,
- int reply_id);
-
-/*The following definitions come from nameserv.c */
-
-void remove_name_entry(struct subnet_record *d, char *name,int type);
-void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags);
-void add_domain_logon_names(void);
-void add_domain_master_bcast(void);
-void add_domain_master_wins(void);
-void add_domain_names(time_t t);
-void add_my_names(void);
-void remove_my_names();
-void refresh_my_names(time_t t);
-void query_refresh_names(time_t t);
+void process_name_release_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void process_name_refresh_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p);
+void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p);
-/*The following definitions come from nameservreply.c */
+/*The following definitions come from nmbd_lmhosts.c */
-void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
- uint16 response_id,
- struct nmb_name *name,
- int nb_flags, int ttl, struct in_addr register_ip,
- BOOL new_owner, struct in_addr reply_to_ip);
-void reply_name_release(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 load_lmhosts_file(char *fname);
+BOOL find_name_in_lmhosts(struct nmb_name *nmbname, struct name_record **namerecp);
-/*The following definitions come from nameservresp.c */
+/*The following definitions come from nmbd_logonnames.c */
-void debug_state_type(int state);
-void response_netbios_packet(struct packet_struct *p);
+void add_logon_names(void);
-/*The following definitions come from namework.c */
+/*The following definitions come from nmbd_mynames.c */
-void reset_server(char *name, int state, struct in_addr ip);
-void tell_become_backup(void);
-BOOL same_context(struct dgram_packet *dgram);
-void process_browse_packet(struct packet_struct *p,char *buf,int len);
+BOOL register_my_workgroup_and_names();
+void release_my_names();
+void refresh_my_names(time_t t);
-/*The following definitions come from nmbd.c */
+/*The following definitions come from nmbd_namelistdb.c */
-BOOL reload_services(BOOL test);
+void set_samba_nb_type(void);
+BOOL ms_browser_name(char *name, int type);
+void remove_name_from_namelist(struct subnet_record *subrec,
+ struct name_record *namerec);
+struct name_record *find_name_on_subnet(struct subnet_record *subrec,
+ struct nmb_name *nmbname, BOOL self_only);
+struct name_record *find_name_for_remote_broadcast_subnet( struct nmb_name *nmbname,
+ BOOL self_only);
+void update_name_ttl(struct name_record *namerec, int ttl);
+struct name_record *add_name_to_subnet(struct subnet_record *subrec,
+ char *name, int type, uint16 nb_flags, int ttl,
+ enum name_source source, int num_ips, struct in_addr *iplist);
+void standard_success_register(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname, uint16 nb_flags, int ttl,
+ struct in_addr registered_ip);
+void standard_fail_register(struct subnet_record *subrec,
+ struct response_record *rrec, struct nmb_name *nmbname);
+BOOL find_ip_in_name_record(struct name_record *namerec, struct in_addr ip);
+void add_ip_to_name_record(struct name_record *namerec, struct in_addr new_ip);
+void remove_ip_from_name_record( struct name_record *namerec, struct in_addr remove_ip);
+void standard_success_release(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname, struct in_addr released_ip);
+void expire_names_on_subnet(struct subnet_record *subrec, time_t t);
+void expire_names(time_t t);
+void add_samba_names_to_subnet(struct subnet_record *subrec);
+void dump_all_namelists();
+
+/*The following definitions come from nmbd_namequery.c */
+
+BOOL query_name(struct subnet_record *subrec, char *name, int type,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata);
+
+/*The following definitions come from nmbd_nameregister.c */
+
+BOOL register_name(struct subnet_record *subrec,
+ char *name, int type, uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata);
+BOOL refresh_name(struct subnet_record *subrec, struct name_record *namerec,
+ refresh_name_success_function success_fn,
+ refresh_name_fail_function fail_fn,
+ struct userdata_struct *userdata);
+
+/*The following definitions come from nmbd_namerelease.c */
+
+BOOL release_name(struct subnet_record *subrec, struct name_record *namerec,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata);
+
+/*The following definitions come from nmbd_nodestatus.c */
+
+BOOL node_status(struct subnet_record *subrec, struct nmb_name *nmbname,
+ struct in_addr send_ip, node_status_success_function success_fn,
+ node_status_fail_function fail_fn, struct userdata_struct *userdata);
+
+/*The following definitions come from nmbd_packets.c */
+
+uint16 get_nb_flags(char *buf);
+void set_nb_flags(char *buf, uint16 nb_flags);
+struct response_record *queue_register_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags);
+struct response_record *queue_register_multihomed_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr register_ip);
+struct response_record *queue_release_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr release_ip);
+struct response_record *queue_refresh_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ refresh_name_success_function success_fn,
+ refresh_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct name_record *namerec,
+ struct in_addr refresh_ip);
+struct response_record *queue_query_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname);
+struct response_record *queue_node_status( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ node_status_success_function success_fn,
+ node_status_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ struct in_addr send_ip);
+void reply_netbios_packet(struct packet_struct *orig_packet,
+ int rcode, enum netbios_reply_type_code rcv_code, int opcode,
+ int ttl, char *data,int len);
+void queue_packet(struct packet_struct *packet);
+void process_browse_packet(struct packet_struct *p, char *buf,int len);
+BOOL validate_nmb_response_packet( struct nmb_packet *nmb );
+BOOL validate_nmb_packet( struct nmb_packet *nmb );
+void run_packet_queue();
+void retransmit_or_expire_response_records(time_t t);
+BOOL listen_for_packets(BOOL run_election);
+BOOL send_mailslot(BOOL unique, char *mailslot,char *buf,int len,
+ char *srcname, int src_type,
+ char *dstname, int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip);
+
+/*The following definitions come from nmbd_processlogon.c */
+
+void process_logon_packet(struct packet_struct *p,char *buf,int len,
+ char *mailslot);
+
+/*The following definitions come from nmbd_responserecordsdb.c */
+
+void add_response_record(struct subnet_record *subrec,
+ struct response_record *rrec);
+void remove_response_record(struct subnet_record *subrec,
+ struct response_record *rrec);
+struct response_record *make_response_record( struct subnet_record *subrec,
+ struct packet_struct *p,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ success_function success_fn,
+ fail_function fail_fn,
+ struct userdata_struct *userdata);
+struct response_record *find_response_record(struct subnet_record **ppsubrec,
+ uint16 id);
+
+/*The following definitions come from nmbd_sendannounce.c */
+
+void send_browser_reset(int reset_type, char *to_name, int to_type, struct in_addr to_ip);
+void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work);
+void announce_my_server_names(time_t t);
+void reset_announce_timer();
+void announce_myself_to_domain_master_browser(time_t t);
+void announce_my_servers_removed(void);
+void announce_remote(time_t t);
+void browse_sync_remote(time_t t);
+
+/*The following definitions come from nmbd_serverlistdb.c */
+
+void remove_all_servers(struct work_record *work);
+struct server_record *find_server_in_workgroup(struct work_record *work, char *name);
+struct server_record *create_server_on_workgroup(struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment);
+void update_server_ttl(struct server_record *servrec, int ttl);
+void expire_servers(struct work_record *work, time_t t);
+void write_browse_list(time_t t, BOOL force_write);
+
+/*The following definitions come from nmbd_subnetdb.c */
+
+BOOL create_subnets();
+BOOL we_are_a_wins_client();
+struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec);
+
+/*The following definitions come from nmbd_winsproxy.c */
+
+void make_wins_proxy_name_query_request( struct subnet_record *subrec,
+ struct packet_struct *incoming_packet,
+ struct nmb_name *question_name);
+
+/*The following definitions come from nmbd_winsserver.c */
+
+BOOL packet_is_for_wins_server(struct packet_struct *packet);
+BOOL initialise_wins(void);
+void wins_process_name_refresh_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void wins_process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
+ struct packet_struct *p);
+void send_wins_name_query_response(int rcode, struct packet_struct *p,
+ struct name_record *namerec);
+void wins_process_name_query_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void wins_process_name_release_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void initiate_wins_processing(time_t t);
+void wins_write_database(void);
+
+/*The following definitions come from nmbd_workgroupdb.c */
+
+struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec,
+ fstring name);
+struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
+ fstring name, int ttl);
+void update_workgroup_ttl(struct work_record *work, int ttl);
+void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work);
+void dump_workgroups(void);
+void expire_workgroups_and_servers(time_t t);
/*The following definitions come from nmblib.c */
char *lookup_opcode_name( int opcode );
void debug_nmb_packet(struct packet_struct *p);
char *namestr(struct nmb_name *n);
-void free_nmb_packet(struct nmb_packet *nmb);
+struct packet_struct *copy_packet(struct packet_struct *packet);
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 nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2);
BOOL send_packet(struct packet_struct *p);
struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
-/*The following definitions come from nmbsync.c */
-
-void sync_browse_lists(struct subnet_record *d, struct work_record *work,
- char *name, int nm_type, struct in_addr ip, BOOL local);
-
/*The following definitions come from ntclient.c */
BOOL do_nt_login(char *desthost, char *myhostname,
extern int DEBUGLEVEL;
struct in_addr ipzero;
-struct in_addr wins_ip;
+struct in_addr allones_ip;
struct in_addr loopback_ip;
static struct in_addr default_ip;
static struct in_addr default_bcast;
static BOOL got_bcast=False;
static BOOL got_nmask=False;
-struct interface *local_interfaces = NULL;
+static struct interface *local_interfaces = NULL;
struct interface *last_iface;
struct in_addr ip;
ipzero = *interpret_addr2("0.0.0.0");
- wins_ip = *interpret_addr2("255.255.255.255");
+ allones_ip = *interpret_addr2("255.255.255.255");
loopback_ip = *interpret_addr2("127.0.0.1");
while (next_token(&ptr,token,NULL)) {
return ret;
}
+/****************************************************************************
+ True if we have two or more interfaces.
+ **************************************************************************/
+BOOL we_are_multihomed()
+{
+ static int multi = -1;
+
+ if(multi == -1)
+ multi = (iface_count() > 1 ? True : False);
+
+ return multi;
+}
+
+/****************************************************************************
+ return the Nth interface
+ **************************************************************************/
+struct interface *get_interface(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return i;
+ return NULL;
+}
+
/****************************************************************************
return IP of the Nth interface
**************************************************************************/
}
/* these 3 functions return the ip/bcast/nmask for the interface
- most appropriate for the given ip address */
+ most appropriate for the given ip address. If they can't find
+ an appropriate interface they return the requested field of the
+ first known interface. */
struct in_addr *iface_bcast(struct in_addr ip)
{
/****************************************************************************
do a netbios name query to find someones IP
+ returns an array of IP addresses or NULL if none
+ *count will be set to the number of addresses returned
****************************************************************************/
-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)())
+struct in_addr *name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, int *count, void (*fn)())
{
BOOL found=False;
- int retries = 3;
+ int i, retries = 3;
int retry_time = bcast?250:2000;
struct timeval tval;
struct packet_struct p;
struct packet_struct *p2;
struct nmb_packet *nmb = &p.packet.nmb;
static int name_trn_id = 0;
+ struct in_addr *ip_list = NULL;
bzero((char *)&p,sizeof(p));
+ (*count) = 0;
if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
(getpid()%(unsigned)100);
GetTimeOfDay(&tval);
if (!send_packet(&p))
- return(False);
+ return NULL;
retries--;
if (TvalDiff(&tval,&tval2) > retry_time) {
if (!retries) break;
if (!found && !send_packet(&p))
- return False;
+ return NULL;
GetTimeOfDay(&tval);
retries--;
}
if ((p2=receive_packet(fd,NMB_PACKET,90)))
{
struct nmb_packet *nmb2 = &p2->packet.nmb;
- debug_nmb_packet(p2);
+ debug_nmb_packet(p2);
if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
!nmb2->header.response) {
continue;
}
- if (ip) {
- putip((char *)ip,&nmb2->answers->rdata[2]);
- DEBUG(fn?3:2,("Got a positive name query response from %s",
- inet_ntoa(p2->ip)));
- DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
+ ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
+ ((*count)+nmb2->answers->rdlength/6));
+ if (ip_list) {
+ DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
+ inet_ntoa(p2->ip)));
+ for (i=0;i<nmb2->answers->rdlength/6;i++) {
+ putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
+ DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
+ (*count)++;
+ }
+ DEBUG(fn?3:2,(")\n"));
}
found=True; retries=0;
free_packet(p2);
}
}
- return(found);
+ return ip_list;
}
char *nmb_opcode_name;
int opcode;
} nmb_header_opcode_names[] = {
- { "Query", 0 },
+ {"Query", 0 },
{"Registration", 5 },
{"Release", 6 },
{"WACK", 7 },
- {"refresh", 8 },
+ {"Refresh", 8 },
+ {"Refresh(altcode)", 9 },
+ {"Multi-homed Registration", 15 },
{0, -1 }
};
if (n==16) {
/* parse out the name type,
its always in the 16th byte of the name */
- name->name_type = name->name[15];
+ name->name_type = ((unsigned char)name->name[15]) & 0xff;
/* remove trailing spaces */
name->name[15] = 0;
/* special case for wildcard name */
bzero(buf1,20);
buf1[0] = '*';
+ buf1[15] = name->name_type;
} else {
sprintf(buf1,"%-15.15s%c",name->name,name->name_type);
}
char *p = ret[i];
if (!n->scope[0])
- sprintf(p,"%s(%x)",n->name,n->name_type);
+ sprintf(p,"%s<%02x>",n->name,n->name_type);
else
- sprintf(p,"%s(%x).%s",n->name,n->name_type,n->scope);
+ sprintf(p,"%s<%02x>.%s",n->name,n->name_type,n->scope);
i = (i+1)%4;
return(p);
return(True);
}
+/*******************************************************************
+ 'Copy constructor' for an nmb packet
+ ******************************************************************/
+static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
+{
+ struct nmb_packet *nmb;
+ struct nmb_packet *copy_nmb;
+ struct packet_struct *pkt_copy;
+
+ if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+ {
+ DEBUG(0,("copy_nmb_packet: malloc fail.\n"));
+ return NULL;
+ }
+
+ /* Structure copy of entire thing. */
+
+ *pkt_copy = *packet;
+
+ /* Ensure this copy is not locked. */
+ pkt_copy->locked = False;
+
+ /* Ensure this copy has no resource records. */
+ nmb = &packet->packet.nmb;
+ copy_nmb = &pkt_copy->packet.nmb;
+
+ copy_nmb->answers = NULL;
+ copy_nmb->nsrecs = NULL;
+ copy_nmb->additional = NULL;
+
+ /* Now copy any resource records. */
+
+ if (nmb->answers)
+ {
+ if((copy_nmb->answers = (struct res_rec *)
+ malloc(nmb->header.ancount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->answers, (char *)nmb->answers,
+ nmb->header.ancount * sizeof(struct res_rec));
+ }
+ if (nmb->nsrecs)
+ {
+ if((copy_nmb->nsrecs = (struct res_rec *)
+ malloc(nmb->header.nscount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs,
+ nmb->header.nscount * sizeof(struct res_rec));
+ }
+ if (nmb->additional)
+ {
+ if((copy_nmb->additional = (struct res_rec *)
+ malloc(nmb->header.arcount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->additional, (char *)nmb->additional,
+ nmb->header.arcount * sizeof(struct res_rec));
+ }
+
+ return pkt_copy;
+
+free_and_exit:
+
+ if(copy_nmb->answers)
+ free((char *)copy_nmb->answers);
+ if(copy_nmb->nsrecs)
+ free((char *)copy_nmb->nsrecs);
+ if(copy_nmb->additional)
+ free((char *)copy_nmb->additional);
+ free((char *)pkt_copy);
+
+ DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
+ return NULL;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a dgram packet
+ ******************************************************************/
+static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
+{
+ struct packet_struct *pkt_copy;
+
+ if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+ {
+ DEBUG(0,("copy_dgram_packet: malloc fail.\n"));
+ return NULL;
+ }
+
+ /* Structure copy of entire thing. */
+
+ *pkt_copy = *packet;
+
+ /* Ensure this copy is not locked. */
+ pkt_copy->locked = False;
+
+ /* There are no additional pointers in a dgram packet,
+ we are finished. */
+ return pkt_copy;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a generic packet
+ ******************************************************************/
+struct packet_struct *copy_packet(struct packet_struct *packet)
+{
+ if(packet->packet_type == NMB_PACKET)
+ return copy_nmb_packet(packet);
+ else if (packet->packet_type == DGRAM_PACKET)
+ return copy_dgram_packet(packet);
+ return NULL;
+}
+
/*******************************************************************
free up any resources associated with an nmb packet
******************************************************************/
-void free_nmb_packet(struct nmb_packet *nmb)
+static void free_nmb_packet(struct nmb_packet *nmb)
{
if (nmb->answers) free(nmb->answers);
if (nmb->nsrecs) free(nmb->nsrecs);
if (nmb->additional) free(nmb->additional);
}
+/*******************************************************************
+ free up any resources associated with a dgram packet
+ ******************************************************************/
+static void free_dgram_packet(struct dgram_packet *nmb)
+{
+ /* We have nothing to do for a dgram packet. */
+}
+
/*******************************************************************
free up any resources associated with a packet
******************************************************************/
void free_packet(struct packet_struct *packet)
{
- if (packet->locked)
- return;
- if (packet->packet_type == NMB_PACKET)
- free_nmb_packet(&packet->packet.nmb);
- free(packet);
+ if (packet->locked)
+ return;
+ if (packet->packet_type == NMB_PACKET)
+ free_nmb_packet(&packet->packet.nmb);
+ else if (packet->packet_type == DGRAM_PACKET)
+ free_dgram_packet(&packet->packet.dgram);
+ free(packet);
}
/*******************************************************************
******************************************************************/
void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope)
{
- fstrcpy(n->name,name);
+ StrnCpy(n->name,name,15);
strupper(n->name);
- n->name_type = type;
- fstrcpy(n->scope,this_scope);
+ n->name_type = (unsigned int)type & 0xFF;
+ StrnCpy(n->scope,this_scope,63);
}
+/*******************************************************************
+ Compare two nmb names
+ ******************************************************************/
+
+BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
+{
+ return ((n1->name_type == n2->name_type) &&
+ strequal(n1->name ,n2->name ) &&
+ strequal(n1->scope,n2->scope));
+}
/*******************************************************************
build a nmb packet ready for sending
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- SMB Version handling
- Copyright (C) John H Terpstra 1995-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
-*/
-
-#include "includes.h"
-
-#define TEST_CODE
-
-extern int DEBUGLEVEL;
-extern BOOL CanRecurse;
-
-extern struct in_addr ipzero;
-
-extern pstring myname;
-extern fstring myworkgroup;
-extern char **my_netbios_names;
-
-extern int ClientDGRAM;
-extern int ClientNMB;
-
-/* this is our domain/workgroup/server database */
-extern struct subnet_record *subnetlist;
-
-extern int updatecount;
-extern int workgroup_count;
-
-extern struct in_addr wins_ip;
-
-extern pstring scope;
-
-/****************************************************************************
- send a announce request to the local net
- **************************************************************************/
-void announce_request(struct work_record *work, struct in_addr ip)
-{
- pstring outbuf;
- char *p;
-
- if (!work) return;
-
- work->needannounce = True;
-
- DEBUG(2,("sending announce request to %s for workgroup %s\n",
- inet_ntoa(ip),work->work_group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = ANN_AnnouncementRequest;
- p++;
-
- CVAL(p,0) = work->token; /* (local) unique workgroup token id */
- p++;
- StrnCpy(p,myname,16);
- strupper(p);
- p = skip_string(p,1);
-
- /* XXXX note: if we sent the announcement request to 0x1d instead
- of 0x1e, then we could get the master browser to announce to
- us instead of the members of the workgroup. wha-hey! */
-
- send_mailslot_reply(False, BROWSE_MAILSLOT, ClientDGRAM,
- outbuf,PTR_DIFF(p,outbuf),
- myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
-}
-
-
-/****************************************************************************
- request an announcement
- **************************************************************************/
-void do_announce_request(char *info, char *to_name, int announce_type,
- int from,
- int to, struct in_addr dest_ip)
-{
- pstring outbuf;
- char *p;
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = announce_type;
- p++;
-
- DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
- announce_type, info, inet_ntoa(dest_ip),to_name,to));
-
- StrnCpy(p,info,16);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(False,BROWSE_MAILSLOT, ClientDGRAM,
- outbuf,PTR_DIFF(p,outbuf),
- myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
-}
-
-
-/****************************************************************************
- find a server responsible for a workgroup, and sync browse lists
- control ends up back here via response_name_query.
- **************************************************************************/
-void sync_server(enum state_type state, char *serv_name, char *work_name,
- int name_type,
- struct subnet_record *d,
- struct in_addr ip)
-{
- /* with a domain master we can get the whole list (not local only list) */
- BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
-
- add_browser_entry(serv_name, name_type, work_name, 0, d, ip, local_only);
-
- if (state == NAME_STATUS_DOM_SRV_CHK)
- {
- /* announce ourselves as a master browser to serv_name */
- do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
- 0x20, 0, ip);
- }
-}
-
-
-/****************************************************************************
- send a host announcement packet
- **************************************************************************/
-static void do_announce_host(int command,
- char *from_name, int from_type, struct in_addr from_ip,
- char *to_name , int to_type , struct in_addr to_ip,
- time_t announce_interval,
- char *server_name, int server_type, char *server_comment)
-{
- 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) = lp_major_announce_version(); /* major version */
- CVAL(p,22) = lp_minor_announce_version(); /* minor version */
-
- SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
- /* browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT)*/
- SSVAL(p,27,BROWSER_ELECTION_VERSION);
- SSVAL(p,29,BROWSER_CONSTANT); /* browse signature */
-
- pstrcpy(p+31,server_comment);
- p += 31;
- p = skip_string(p,1);
-
- debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
-
- /* send the announcement */
- send_mailslot_reply(False,BROWSE_MAILSLOT, ClientDGRAM, outbuf,
- PTR_DIFF(p,outbuf),
- from_name, to_name,
- from_type, to_type,
- to_ip, from_ip);
-}
-
-
-/****************************************************************************
-announce all samba's server entries as 'gone'.
-****************************************************************************/
-void announce_my_servers_removed(void)
-{
- struct subnet_record *d;
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- 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 (!is_myname(s->serv.name)) continue;
- announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
- }
- }
- }
-}
-
-
-/****************************************************************************
- 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)
-{
- /* domain type cannot have anything in it that might confuse
- a client into thinking that the domain is in fact a server.
- (SV_TYPE_SERVER_UNIX, for example)
- */
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
- BOOL wins_iface = ip_equal(d->bcast_ip, wins_ip);
-
- if(wins_iface)
- {
- DEBUG(0,("announce_server: error - announcement requested on WINS \
-interface for workgroup %s, name %s\n", work->work_group, name));
- return;
- }
-
- /* Only do domain announcements if we are a master and it's
- our name we're being asked to announce. */
- if (AM_MASTER(work) && strequal(myname,name))
- {
- 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,
- ttl,
- 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,
- name , 0x00, d->myip,
- MSBROWSE, 0x01, d->bcast_ip,
- ttl,
- work->work_group, server_type ? domain_type : 0,
- name);
- }
- }
- 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,
- ttl,
- name, server_type, comment);
- }
-}
-
-/****************************************************************************
- construct a host announcement unicast
- **************************************************************************/
-void announce_host(time_t t)
-{
- struct subnet_record *d;
- pstring comment;
- char *my_name;
-
- StrnCpy(comment, lp_serverstring(), 43);
-
- my_name = *myname ? myname : "NoName";
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- struct work_record *work;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- uint32 stype = work->ServerType;
- struct server_record *s;
-
- /* must work on the code that does announcements at up to
- 30 seconds later if a master browser sends us a request
- announce.
- */
-
- if (work->needannounce) {
- /* drop back to a max 3 minute announce - this is to prevent a
- single lost packet from stuffing things up for too long */
- work->announce_interval = MIN(work->announce_interval,
- CHECK_TIME_MIN_HOST_ANNCE*60);
- work->lastannounce_time = t - (work->announce_interval+1);
- }
-
- /* announce every minute at first then progress to every 12 mins */
- if (work->lastannounce_time &&
- (t - work->lastannounce_time) < work->announce_interval)
- continue;
-
- if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
- work->announce_interval += 60;
-
- work->lastannounce_time = t;
-
- for (s = work->serverlist; s; s = s->next) {
- if (is_myname(s->serv.name)) {
- /* If we are any kind of browser or logon server, only
- announce it for our primary name, not our aliases. */
- if(!strequal(myname, s->serv.name))
- stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
- SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
- announce_server(d,work,s->serv.name,comment,
- work->announce_interval,stype);
- }
- }
-
- if (work->needannounce)
- {
- work->needannounce = False;
- break;
- /* sorry: can't do too many announces. do some more later */
- }
- }
- }
-}
-
-/* Announce timer. Moved into global static so it can be reset
- when a machine becomes a master browser. */
-static time_t announce_timer_last=0;
-
-/****************************************************************************
- Reset the announce_timer so that a master browser announce will be done
- immediately.
- ****************************************************************************/
-
-void reset_announce_timer()
-{
- announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
-}
-
-/****************************************************************************
- announce myself as a master to all other domain master browsers.
-
- this actually gets done in search_and_sync_workgroups() via the
- NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
- name query initiated here. see response_name_query()
- **************************************************************************/
-void announce_master(time_t t)
-{
- struct subnet_record *d;
- struct work_record *work;
- BOOL am_master = False; /* are we a master of some sort? :-) */
-
- if (!announce_timer_last) announce_timer_last = t;
- if (t-announce_timer_last < CHECK_TIME_MST_ANNOUNCE * 60)
- {
- DEBUG(10,("announce_master: t (%d) - last(%d) < %d\n",
- t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 ));
- return;
- }
-
- if(wins_client_subnet == NULL)
- {
- DEBUG(10,("announce_master: no wins subnet, ignoring.\n"));
- return;
- }
-
- announce_timer_last = t;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- for (work = d->workgrouplist; work; work = work->next)
- {
- if (AM_MASTER(work))
- {
- am_master = True;
- DEBUG(4,( "announce_master: am_master = %d for \
-workgroup %s\n", am_master, work->work_group));
- }
- }
- }
-
- if (!am_master) return; /* only proceed if we are a master browser */
-
- /* Note that we don't do this if we are domain master browser
- and that we *only* do this on the WINS subnet. */
-
- /* Try and find our workgroup on the WINS subnet */
- work = find_workgroupstruct(wins_client_subnet, myworkgroup, False);
-
- if (work)
- {
- /* assume that the domain master browser we want to sync
- with is our own domain.
- */
- char *name = work->work_group;
- int type = 0x1b;
-
- /* check the existence of a dmb for this workgroup, and if
- one exists at the specified ip, sync with it and announce
- ourselves as a master browser to it
- */
-
- if (!lp_wins_support() && *lp_wins_server() )
- {
- DEBUG(4, ("Local Announce: find %s<%02x> from WINS server %s\n",
- name, type, lp_wins_server()));
-
- queue_netbios_pkt_wins(ClientNMB,
- NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
- name, type, 0,0,0,
- work->work_group,NULL,
- ipzero, ipzero);
- }
- else if(lp_wins_support())
- {
- /* We are the WINS server - query ourselves for the dmb name. */
-
- struct nmb_name netb_name;
- struct name_record *nr = 0;
-
- make_nmb_name(&netb_name, name, type, scope);
-
- if ((nr = find_name_on_subnet(wins_client_subnet, &netb_name, FIND_ANY_NAME)) == 0)
- {
- DEBUG(0, ("announce_master: unable to find domain master browser for workgroup %s \
-in our own WINS database.\n", work->work_group));
- return;
- }
-
- /* Check that this isn't one of our addresses (ie. we are not domain master
- ourselves) */
- if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero))
- {
- DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \
-is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) ));
- return;
- }
-
- /* Issue a NAME_STATUS_DOM_SRV_CHK immediately - short circuit the
- NAME_QUERY_DOM_SRV_CHK which is done only if we are talking to a
- remote WINS server. */
-
- DEBUG(4, ("announce_master: doing name status for %s<%02x> to domain master ip %s \
-for workgroup %s\n", name, type, inet_ntoa(nr->ip_flgs[0].ip), work->work_group ));
-
- queue_netbios_packet(wins_client_subnet, ClientNMB,
- NMB_STATUS,NAME_STATUS_DOM_SRV_CHK,
- name, type, 0,0,0,
- work->work_group,NULL,
- False, False, nr->ip_flgs[0].ip, nr->ip_flgs[0].ip, 0);
- }
- }
-}
-
-/****************************************************************************
- do all the "remote" announcements. These are used to put ourselves
- on a remote browse list. They are done blind, no checking is done to
- see if there is actually a browse master at the other end.
- **************************************************************************/
-void announce_remote(time_t t)
-{
- char *s,*ptr;
- static time_t last_time = 0;
- pstring s2;
- struct in_addr addr;
- char *comment,*workgroup;
- int stype = lp_default_server_announce();
-
- if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
- return;
-
- last_time = t;
-
- s = lp_remote_announce();
- if (!*s) return;
-
- comment = lp_serverstring();
- workgroup = myworkgroup;
-
- for (ptr=s; next_token(&ptr,s2,NULL); )
- {
- /* the entries are of the form a.b.c.d/WORKGROUP with
- WORKGROUP being optional */
- char *wgroup;
- int n;
-
- wgroup = strchr(s2,'/');
- if (wgroup) *wgroup++ = 0;
- if (!wgroup || !*wgroup)
- wgroup = workgroup;
-
- addr = *interpret_addr2(s2);
-
- /* Announce all our names including aliases */
- for (n=0; my_netbios_names[n]; n++)
- {
- char *name = my_netbios_names[n];
- do_announce_host(ANN_HostAnnouncement,name,0x20,*iface_ip(addr),
- wgroup,0x1e,addr,
- REMOTE_ANNOUNCE_INTERVAL,
- name,stype,comment);
- }
- }
-}
-
-/****************************************************************************
- do all the "remote" browse synchronisation stuff.
- These are used to put our browse lists into remote browse lists.
- **************************************************************************/
-void browse_sync_remote(time_t t)
-{
- char *s,*ptr;
- static time_t last_time = 0;
- pstring s2;
- struct in_addr addr;
-
- if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
- return;
-
- last_time = t;
-
- s = lp_remote_browse_sync();
- if (!*s) return;
-
- for (ptr=s; next_token(&ptr,s2,NULL); )
- {
- /* the entries are of the form a.b.c.d */
- int n;
-
- addr = *interpret_addr2(s2);
-
- /* Announce all our names including aliases */
- for (n=0; my_netbios_names[n]; n++)
- {
- char *name = my_netbios_names[n];
- do_announce_request(name, "*", ANN_MasterAnnouncement, 0x20, 0, addr);
- }
- }
-}
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.2
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: nameannounce.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-
- 0.1 - 22jul96 : Andrew.Tridgell@anu.edu.au
- tridge's comments on first revision
-
- 0.2 - 05aug96 : lkcl@pires.co.uk
- actioned tridge comments about pdc -> domain master
- documented NAME_QUERY_ANNOUNCE_HOST
-
-*/
-
-
-this module deals with announcements: the sending of announcement requests
-and the sending of announcements either to refresh other servers' records
-or as a response to announcement requests.
-
-
-/*************************************************************************
- announce_master()
- *************************************************************************/
-
-this function is responsible for announcing samba as a master browser
-to all known domain masters.
-
-this announcement is sent out at CHECK_TIME_MST_ANNOUNCE minute
-intervals, only if samba is a master browser on one or more of
-its local interfaces.
-
-if no domain controller has been specified (lp_domain_controller())
-samba goes through its list of servers looking for domain master
-browsers. when it finds one (other than itself) it will either
-initiate a NAME_QUERY_PDC_SRV_CHK by broadcast or with a WINS
-server. this will result in a NAME_STATUS_PDC_SRV_CHK, which
-will result in a sync browse list and an announcement
-ANN_MasterAnnounce being sent (see sync_server()).
-
-if a domain controller has been specified, samba will search for
-a domain master browser for its workgroup (either by directed
-packet or by broadcast if it cannot resolve the domain controller
-name using DNS), which results in the same action as listed above.
-
-------------
-NOTE FROM TRIDGE:
-
-PDC in the above should really be DMB (domain master browser). They
-might be separate entities.
-
-I also propose a simpler scheme :-)
-
-If a DMB is not configured with lp_domain_controller() (perhaps
-renamed to lp_domain_master()?) then just don't do master
-announcements. Remember that most peoples networks are very simple and
-don't need DMB capabilities. Those that do need them will have more
-complex network topologies and they really need to choose themselves
-which box will act as the "hub" for netbios name resolution. Doing it
-via name queries will just lead to lag and propogation delays, because
-if two parts of the net choose different DMBs then the data will be
-very slow to propoogate.
-
-If a DMB is configured then just send the master announcemnt to that
-box! Thats all that needs to be done. Just send a udp 138 packet and
-forget it. If the recipient is indeed a DMB (as it should be if the
-config file is correct) then it should initiate a browse list sync
-with us at some later time, but that is take care of by smbd and nmbd
-doesn't even need to know it happened.
-
-Additionally, if a DMB is configured we need to sync our workgroup
-list and server list with them occasionally. Note that this is only
-time a non-DMB should do a browse sync, and it should only do it with
-a DMB. Essentially WAN based netbios is just a simple star. There is a
-DMB in the centre, and the individual master browsers for each subnet
-talk to it, but never talk to each other. If they start talking to
-each other then the network load will go as the square of the number
-of machines, which will result in meltdown :-)
--------------
-
-
-/*************************************************************************
- announce_host()
- *************************************************************************/
-
-this complex-looking function is responsible for announcing samba's
-existence to other servers by broadcast. the actual announcement
-is carried out by announce_server().
-
-the time period between samba's announcement will stretch from one
-minute to twelve minutes by one minute. if samba has received an
-announce request from a master browser, then it should answer at
-any random interval between zero and thirty seconds after the
-request is received. this is to ensure that the master browser
-does not get overloaded with responses!
-
-
-/*************************************************************************
- announce_server()
- *************************************************************************/
-
-this function is responsible for sending announcement packets.
-these packets are received by other servers, which will then
-update their records accordingly: what services we have, our
-name, our comment field and our time to live (to name a few).
-
-if samba is a non-master then we need to see if there is a
-domain master (on a remote subnet) that we need to announce to
-it.
-
-if samba is not the WINS server (and it is using another
-WINS server) then we need to do a name query to the WINS
-server to ask it what the domain controller is. this is done
-using a samba 'state' NAME_QUERY_ANNOUNCE_HOST, which passes
-sufficient information on to be able to carry out the
-host announcement using a unicasted do_announce_host() if and
-when a reply comes back. if there is no reply to the name query,
-this is not necessarily an error - there may genuinely be no
-domain master currently up and running for samba's workgroup.
-
-if samba is a WINS server, then samba will need to look up the
-domain controller for its workgroup in its WINS records. an
-over-cautious samba could carry out a name query on that
-domain controller to make sure that it is alive and that samba's
-WINS records are up-to-date. in any event, it will send a unicast
-do_announce_host() to inform the domain master browser, if one
-exists, of samba's server status.
-
-if we are a master browser, then using do_announce_host() we
-must send a broadcast announcement on the local interface
-notifying members of that workgroup that we are their master
-browser, and another announcement indicating to all backup
-browsers and master browsers that we are a master browser.
-
-(note: if another master browser receives this broadcasted
-announcement and thinks that it is also the master browser
-for this workgroup, it stops being a master browser and forces
-an election).
-
-if we are not a master browser, then we send a broacast
-announcement notifying the master browser that we are a member
-of its workgroup, on the local interface.
-
-
-/*************************************************************************
- remove_my_servers()
- *************************************************************************/
-
-this function is responsible for informing other servers that
-samba is about to go down. it announces, on all subnets, that
-samba's time to live is zero and that it has no services.
-
-
-/*************************************************************************
- do_announce_host()
- *************************************************************************/
-
-this function is responsible for sending out an announcement
-MAILSLOT browse packet. it contains information such as the
-time to live, name of the server, services that the server
-offers etc.
-
-the format of this MAILSLOT browse packet is described in
-draft-heizer-cifs-v1-spec-00.txt 3.9.50.4.1 page 165-6.
-
-
-/*************************************************************************
- announce_backup()
- *************************************************************************/
-
-this function is responsible for getting master browsers and domain
-controllers to send us lists of backup servers. this is done by
-sending an ANN_GetBackupListReq browse mailslot.
-
-the local master browser, or domain master browser, should respond
-with an ANN_GetBackupListResp browse mailslot containing the list
-of backup servers.
-
---------------
-NOTE FROM TRIDGE: I don't see why nmbd should ever send one of
-these. The only reason I can see for any part of Samba sending one of
-these is if we implement it in smbclient.
-
-This packet is used to request a list of backup master browsers from
-the master browser. It is used by clients (not servers!) to spread the
-browse load over more than one server. The only server that needs to
-know what the list of backups is is the master browser, and as it is
-also responsible for generating this list it will never ask anyone
-else for it.
---------------
-
-
-/*************************************************************************
- sync_server()
- *************************************************************************/
-
-this function is responsible for initiating a sync browse list
-sequence and, if necessary, carrying out an ANN_MasterAnnouncement
-to the domain master browser (that we are also sync'ing browse lists
-with).
-
-see nameservresp.c:response_name_status_check().
-
-
-/*************************************************************************
- announce_request()
- *************************************************************************/
-
-this function is responsible for sending an announcement request to
-another server. this server should respond with an announcement.
-
-if the announce request is sent to WORKGROUP(0x1e) then members of
-the workgroup will respond (with ANN_HostAnnounce packets)
-
-if the announce request is sent to WORKGROUP(0x1d) then the master
-browser of the workgroup should respond (ANN_LocalMasterAnnounce).
-this is untested.
-
-if the announce request is sent to ^1^2__MSBROWSE__^2(0x1) then
-(and this is pure speculation), all backup browsers and master
-browsers should respond with ANN_DomainAnnounce packets.
-this is untested.
-
------------
-NOTE FROM TRIDGE:
-
-I had great trouble getting machines to actually respond to this
-packet. Either we have the format wrong or MS chose not to implement
-it.
-
-Not implementing it doesn't break anything, it just means a new master
-browser won't get a complete server list as quickly.
-
-Also note that this packet should be used as little as possible as it
-could easily cause meltdown if too many servers used it. Imagine a
-dozen samba servers on a net all sending this packet! You will get 244
-responses all within 30 seconds. now imagine 50 samba servers ....
-
-So I think we should restrict ourselves to sending this packet only if
-we are already the master browser for a workgroup. We could send a
-single "announce request" when we become the master, just to prime our
-server lists. From then on the normal announce cycles should take care
-of keeping it uptodate.
------------
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
-*/
-
-#include "includes.h"
-#include "smb.h"
-
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-extern struct in_addr wins_ip;
-
-/* this is our browse master/backup cache database */
-static struct browse_cache_record *browserlist = NULL;
-
-
-/***************************************************************************
- add a browser into the list
- **************************************************************************/
-static void add_browse_cache(struct browse_cache_record *b)
-{
- struct browse_cache_record *b2;
-
- if (!browserlist)
- {
- browserlist = b;
- b->prev = NULL;
- b->next = NULL;
- return;
- }
-
- for (b2 = browserlist; b2->next; b2 = b2->next) ;
-
- b2->next = b;
- b->next = NULL;
- b->prev = b2;
-}
-
-
-/*******************************************************************
- remove old browse entries
- ******************************************************************/
-void expire_browse_cache(time_t t)
-{
- struct browse_cache_record *b;
- struct browse_cache_record *nextb;
-
- /* expire old entries in the serverlist */
- for (b = browserlist; b; b = nextb)
- {
- nextb = b->next;
- if (b->synced && b->sync_time < t) {
- DEBUG(3,("Removing dead cached browser %s\n",b->name));
-
- if (b->prev) b->prev->next = b->next;
- if (b->next) b->next->prev = b->prev;
-
- if (browserlist == b) browserlist = b->next;
-
- free(b);
- }
- }
-}
-
-/****************************************************************************
- add a browser entry
- ****************************************************************************/
-struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
- time_t ttl, struct subnet_record *d,
- struct in_addr ip, BOOL local)
-{
- BOOL newentry=False;
-
- struct browse_cache_record *b;
-
- /* search for the entry: if it's already in the cache, update that entry */
- for (b = browserlist; b; b = b->next)
- {
- if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
- }
-
- if (b && b->synced)
- {
- /* entries get left in the cache for a while. this stops sync'ing too
- often if the network is large */
- DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
- b->name, b->group, inet_ntoa(b->ip), b->sync_time));
- return NULL;
- }
-
- if (!b)
- {
- newentry = True;
- b = (struct browse_cache_record *)malloc(sizeof(*b));
-
- if (!b) return(NULL);
-
- bzero((char *)b,sizeof(*b));
- }
-
- /* update the entry */
- ttl = time(NULL)+ttl;
-
- StrnCpy(b->name ,name,sizeof(b->name )-1);
- StrnCpy(b->group,wg ,sizeof(b->group)-1);
- strupper(b->name);
- strupper(b->group);
-
- b->ip = ip;
- b->type = type;
- b->local = local; /* local server list sync or complete sync required */
- b->subnet = d;
-
- if (newentry || ttl < b->sync_time)
- b->sync_time = ttl;
-
- if (newentry)
- {
- b->synced = False;
- add_browse_cache(b);
-
- DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
- wg, name, type, inet_ntoa(ip),ttl));
- }
- else
- {
- DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
- wg, name, type, inet_ntoa(ip),ttl));
- }
-
- return(b);
-}
-
-
-/****************************************************************************
-find a server responsible for a workgroup, and sync browse lists
-**************************************************************************/
-static void start_sync_browse_entry(struct browse_cache_record *b)
-{
- struct subnet_record *d = b->subnet;
- struct work_record *work;
-
- /* Check panic conditions - these should not be true. */
- if(b->subnet != wins_client_subnet) {
- DEBUG(0,
- ("start_sync_browse_entry: ERROR sync requested on non-WINS subnet.\n"));
- return;
- }
-
- if (!(work = find_workgroupstruct(d, b->group, False))) {
- DEBUG(0, ("start_sync_browse_entry: failed to get a \
-workgroup for a browse cache entry workgroup %s, server %s\n",
- b->group, b->name));
- return;
- }
-
- DEBUG(4, ("start_sync_browse_entry: Initiating %s sync with %s<0x20>, \
-workgroup %s\n",
- b->local ? "local" : "remote", b->name, b->group));
-
- /* first check whether the server 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() */
- /* We cheat here by using the my_comment field of the response_record
- struct as the workgroup name we are going to do the sync for.
- This is because the reply packet doesn't include the workgroup, but
- we need it when the reply comes back.
- */
- queue_netbios_packet(d,ClientNMB,NMB_QUERY,
- b->local?NAME_QUERY_SYNC_LOCAL:NAME_QUERY_SYNC_REMOTE,
- b->name,0x20,0,0,0,NULL,b->group,
- False,False,b->ip,b->ip, 0);
-
- b->synced = True;
-}
-
-
-/****************************************************************************
- search through browser list for an entry to sync with
- **************************************************************************/
-void do_browser_lists(time_t t)
-{
- struct browse_cache_record *b;
- static time_t last = 0;
-
- if (t-last < 20)
- {
- DEBUG(9,("do_browser_lists: returning due to t(%d) - last(%d) < 20\n",
- t, last));
- 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;
-
- /* pick any entry in the list, preferably one whose time is up */
- for (b = browserlist; b && b->next; b = b->next)
- {
- if (b->sync_time < t && b->synced == False) break;
- }
-
- if (b && !b->synced)
- {
- /* sync with the selected entry then remove some dead entries */
- DEBUG(4,("do_browser_lists: Initiating sync with %s, workgroup %s\n",
- b->name, b->group));
- start_sync_browse_entry(b);
- }
- else
- {
- DEBUG(9, ("do_browser_lists: no entries to sync.\n"));
- }
-
- expire_browse_cache(t - 60);
-}
-
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.1
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: namebrowse.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-
- 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
- tridge's comments on first revision
-*/
-
-this module deals with queueing servers that samba must sync browse
-lists with. it will always issue a name query immediately before
-actually carrying out the NetServerEnum call, to ensure that time
-is not wasted by a remote server's failure.
-
-this module was created to minimise the amount of NetServerEnum calls
-that samba may be asked to perform, by maintaining the name of a server
-for up to a minute after the NetServerEnum call was issued, and
-disallowing further NetServerEnum calls to this remote server until
-the entry is removed.
-
-samba can ask for a NetServerEnum call to be issued to grab a remote
-server's list of servers and workgroups either in its capacity as
-a domain master browser, as a local master browser.
-
-samba does not deal with becoming a backup master browser properly
-at present.
-
--------------
-NOTE FROM TRIDGE:
-
-Yes, samba can send these either in its capacity as a DMB or as a
-MB. There are only two situations:
-
-- If samba is a DMB then it should sync with the "local only" bit set
-with any master browser that has sent it a "master announce".
-
-- if samba is not a DMB then it can only sync with the DMB, and should
-not set the "local only" bit.
-
-Note that samba should never sync with other non-DMB servers when it
-is not a DMB.
-
-Try to do a sync under any other circumstances is dangerous without a
-multi-threaded nmbd. I have a print server at home that knows some SMB
-and NBT, but if you try to sync browse lists with it then it clogs up,
-and also clogs up nmbd while it times out the connection. If we
-follow the above two rules then we can't get into this sort of
-trouble as:
-
-- if we are a DMB and a master browser sends us a "master announce"
-then it is expecting to receive a NetServerEnum SMB connection soon,
-and must be capabable of handling it.
-
-- if we are not a DMB then we will only sync with the DMB, which must
-be capable of doing this stuff or things are really in a mess :-)
---------------
-
-
-/*************************************************************************
- do_browser_lists()
- *************************************************************************/
-
-this function is responsible for finding an appropriate entry in the
-sync browser cache, initiating a name query (which results in a
-NetServerEnum call if there is a positive response), and then
-removing all entries that have been actioned and have been around
-for over a minute.
-
-
-/*************************************************************************
- start_sync_browse_entry()
- *************************************************************************/
-
-this function is responsible for initiating a name query. if a
-positive response is received, then this will result in a
-NetServerEnum api call.
-
-samba will only initiate this process if it is a master browser
-for this workgroup.
-
------------
-NOTE FROM TRIDGE:
-
-I'd actually prefer to skip the name query completely if we can
-resolve the DMBs name via gethostbyname(). For the name query to work
-we either have to have WINS working, or we need to know the broadcast
-address of the network that the DMB is on. This makes us too dependent
-on too many thing being right.
-
-If the gethostbyname() fails then sure, go for a normal name query,
-but if it works then we have saved ourselves a lot of trouble and
-gained a lot of robustness.
-
-This is best handled by a generic "resolve netbios name" routine that
-tries DNS first then resorts to WINS or bcast if that fails. It also
-needs to cache the results.
--------------
-
-
-/*************************************************************************
- add_browser_entry()
- *************************************************************************/
-
-this function is responsible for adding a browser into the list of
-servers to sync browse lists with. if the server entry has already
-been added and syncing browse lists has already been initiated, it
-will not be added again.
-
-
-/*************************************************************************
- expire_browse_cache()
- *************************************************************************/
-
-this function is responsible for removing entries that have had the
-sync browse list initiated (whether that succeeded or not is beyond
-this function's scope) and have been in the cache for a while.
-
-
-/*************************************************************************
- add_browse_entry()
- *************************************************************************/
-
-this function is responsible for adding a new entry into the list
-of servers to sync browse lists with at some point in the near future.
-
-
-
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Module name: namedbname.c
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- created module namedbname containing name database functions
-*/
-
-#include "includes.h"
-
-extern int DEBUGLEVEL;
-
-extern pstring scope;
-extern struct in_addr ipzero;
-extern struct in_addr wins_ip;
-extern BOOL updatedlists;
-
-extern struct subnet_record *subnetlist;
-
-#define WINS_LIST "wins.dat"
-
-uint16 nb_type = 0; /* samba's NetBIOS name type */
-
-
-/****************************************************************************
- samba's NetBIOS name type
-
- XXXX maybe functionality could be set: B, M, P or H name registration
- and resolution could be set through nb_type. just a thought.
- ****************************************************************************/
-void set_samba_nb_type(void)
-{
- if (lp_wins_support() || (*lp_wins_server()))
- {
- nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */
- }
- else
- {
- nb_type = NB_BFLAG; /* samba is broadcast-only node type */
- }
-}
-
-
-/****************************************************************************
- true if two netbios names are equal
-****************************************************************************/
-BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
-{
- return n1->name_type == n2->name_type &&
- strequal(n1->name ,n2->name ) &&
- strequal(n1->scope,n2->scope);
-}
-
-
-/****************************************************************************
- true if the netbios name is ^1^2__MSBROWSE__^2^1
-
- note: this name is registered if as a master browser or backup browser
- you are responsible for a workgroup (when you announce a domain by
- broadcasting on your local subnet, you announce it as coming from this
- name: see announce_host()).
-
- **************************************************************************/
-BOOL ms_browser_name(char *name, int type)
-{
- return strequal(name,MSBROWSE) && type == 0x01;
-}
-
-
-/****************************************************************************
- add a netbios name into the namelist
- **************************************************************************/
-static void add_name(struct subnet_record *d, struct name_record *n)
-{
- struct name_record *n2;
-
- if (!d) return;
-
- if (!d->namelist)
- {
- d->namelist = n;
- n->prev = NULL;
- n->next = NULL;
- return;
- }
-
- for (n2 = d->namelist; n2->next; n2 = n2->next) ;
-
- n2->next = n;
- n->next = NULL;
- n->prev = n2;
-
- if((d == wins_client_subnet) && lp_wins_support())
- updatedlists = True;
-}
-
-
-/****************************************************************************
- remove a name from the namelist. The pointer must be an element just
- retrieved
- **************************************************************************/
-void remove_name(struct subnet_record *d, struct name_record *n)
-{
- struct name_record *nlist;
- if (!d) return;
-
- nlist = d->namelist;
-
- while (nlist && nlist != n) nlist = nlist->next;
-
- if (nlist)
- {
- if (nlist->next) nlist->next->prev = nlist->prev;
- if (nlist->prev) nlist->prev->next = nlist->next;
-
- if(nlist == d->namelist)
- d->namelist = nlist->next;
-
- if(nlist->ip_flgs != NULL)
- free(nlist->ip_flgs);
- free(nlist);
- }
-
- if((d == wins_client_subnet) && lp_wins_support())
- updatedlists = True;
-}
-
-
-/****************************************************************************
- find a name in a subnet.
- **************************************************************************/
-struct name_record *find_name_on_subnet(struct subnet_record *d,
- struct nmb_name *name, BOOL self_only)
-{
- struct name_record *n = d->namelist;
- struct name_record *ret;
-
- for (ret = n; ret; ret = ret->next)
- {
- if (name_equal(&ret->name,name))
- {
- /* self search: self names only */
- if (self_only && (ret->source != SELF))
- {
- continue;
- }
- DEBUG(9,("find_name_on_subnet: on subnet %s - found name %s(%02x) source=%d\n",
- inet_ntoa(d->bcast_ip), name->name, name->name_type, ret->source));
- return ret;
- }
- }
- DEBUG(9,("find_name_on_subnet: on subnet %s - name %s(%02x) NOT FOUND\n",
- inet_ntoa(d->bcast_ip), name->name, name->name_type));
- return NULL;
-}
-
-/****************************************************************************
- dump a copy of the name table
- **************************************************************************/
-void dump_names(void)
-{
- struct name_record *n;
- fstring fname, fnamenew;
- time_t t = time(NULL);
-
- FILE *f;
-
- if(lp_wins_support() == False || wins_client_subnet == NULL)
- return;
-
- fstrcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,WINS_LIST);
- fstrcpy(fnamenew,fname);
- strcat(fnamenew,".");
-
- f = fopen(fnamenew,"w");
-
- if (!f)
- {
- DEBUG(3,("Can't open %s - %s\n",fnamenew,strerror(errno)));
- return;
- }
-
- DEBUG(4,("Dump of WINS name table:\n"));
-
- for (n = wins_client_subnet->namelist; n; n = n->next)
- {
- int i;
-
- DEBUG(4,("%15s ", inet_ntoa(wins_client_subnet->bcast_ip)));
- DEBUG(4,("%15s ", inet_ntoa(wins_client_subnet->mask_ip)));
- DEBUG(4,("%-19s TTL=%ld ",
- namestr(&n->name),
- n->death_time?n->death_time-t:0));
-
- for (i = 0; i < n->num_ips; i++)
- {
- DEBUG(4,("%15s NB=%2x source=%d",
- inet_ntoa(n->ip_flgs[i].ip),
- n->ip_flgs[i].nb_flags,n->source));
-
- }
- DEBUG(4,("\n"));
-
- if (f && ((n->source == REGISTER) || (n->source == SELF)))
- {
- /* XXXX i have little imagination as to how to output nb_flags as
- anything other than as a hexadecimal number :-) */
-
- fprintf(f, "%s#%02x %ld ",
- n->name.name,n->name.name_type, /* XXXX ignore scope for now */
- n->death_time);
-
- for (i = 0; i < n->num_ips; i++)
- {
- fprintf(f, "%s %2x%c ",
- inet_ntoa(n->ip_flgs[i].ip),
- n->ip_flgs[i].nb_flags, (n->source == REGISTER ? 'R' : 'S'));
- }
- fprintf(f, "\n");
- }
-
- }
-
- fclose(f);
- unlink(fname);
- chmod(fnamenew,0644);
- rename(fnamenew,fname);
-
- DEBUG(3,("Wrote wins database %s\n",fname));
-}
-
-
-/****************************************************************************
- load a netbios name database file
-
- XXXX we cannot cope with loading Internet Group names, yet
- ****************************************************************************/
-void load_netbios_names(void)
-{
- struct subnet_record *d = wins_client_subnet;
- fstring fname;
-
- FILE *f;
- pstring line;
-
- if (!d) return;
-
- fstrcpy(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;
- unsigned 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,ttd_str ,NULL)) ++count;
- if (next_token(&ptr,ip_str ,NULL)) ++count;
- if (next_token(&ptr,nb_flags_str,NULL)) ++count;
-
- if (count <= 0) continue;
-
- if (count != 4) {
- DEBUG(0,("Ill formed wins line"));
- DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line));
- continue;
- }
-
- /* Deal with SELF or REGISTER name encoding. Default is REGISTER
- for compatibility with old nmbds. */
- if(nb_flags_str[strlen(nb_flags_str)-1] == 'S')
- {
- DEBUG(5,("Ignoring SELF name %s\n", line));
- continue;
- }
-
- if(nb_flags_str[strlen(nb_flags_str)-1] == 'R')
- nb_flags_str[strlen(nb_flags_str)-1] = '\0';
-
- /* netbios name. # divides the name from the type (hex): netbios#xx */
- pstrcpy(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 %ld %s %2x\n",
- name,type, ttd, inet_ntoa(ipaddr), nb_flags));
-
- /* add all entries that have 60 seconds or more to live */
- if (ttd - 60 > time(NULL) || ttd == 0)
- {
- 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);
- }
- }
-
- fclose(f);
-}
-
-
-/****************************************************************************
- remove an entry from the name list
- ****************************************************************************/
-void remove_netbios_name(struct subnet_record *d,
- char *name,int type, enum name_source source)
-{
- struct nmb_name nn;
- struct name_record *n;
-
- make_nmb_name(&nn, name, type, scope);
- n = find_name_on_subnet(d, &nn, FIND_ANY_NAME);
-
- if (n && n->source == source) remove_name(d,n);
-}
-
-
-/****************************************************************************
- 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.
-
- ****************************************************************************/
-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)
-{
- struct name_record *n;
- struct name_record *n2=NULL;
- BOOL self = (source == SELF) ? FIND_SELF_NAME : FIND_ANY_NAME;
- /* It's a WINS add if we're adding to the wins_client_subnet. */
- BOOL wins = ( wins_client_subnet && (d == wins_client_subnet));
-
- if(d == NULL)
- {
- DEBUG(0,("add_netbios_entry: called with NULL subnet record. This is a bug - \
-please report this.!\n"));
- return NULL;
- }
-
- if (!self)
- {
- if (!wins && (type != 0x1b))
- {
- /* the only broadcast (non-WINS) names we are adding are ours
- (SELF) and Domain Master type names */
- return NULL;
- }
- if(wins && (type == 0x1d))
- {
- /* Do not allow any 0x1d names to be registered in a WINS,
- database although we return success for them.
- */
- return NULL;
- }
- }
-
- n = (struct name_record *)malloc(sizeof(*n));
- if (!n) return(NULL);
-
- bzero((char *)n,sizeof(*n));
-
- n->num_ips = 1; /* XXXX ONLY USE THIS FUNCTION FOR ONE ENTRY */
- n->ip_flgs = (struct nmb_ip*)malloc(sizeof(*n->ip_flgs) * n->num_ips);
- if (!n->ip_flgs)
- {
- free(n);
- return NULL;
- }
-
- bzero((char *)n->ip_flgs, sizeof(*n->ip_flgs) * n->num_ips);
-
- make_nmb_name(&n->name,name,type,scope);
-
- if ((n2 = find_name_on_subnet(d, &n->name, self)))
- {
- free(n->ip_flgs);
- free(n);
- if (new_only || (n2->source==SELF && source!=SELF)) return n2;
- n = n2;
- }
-
- if (ttl)
- n->death_time = time(NULL)+ttl*3;
- n->refresh_time = time(NULL)+GET_TTL(ttl);
-
- /* XXXX only one entry expected with this function */
- n->ip_flgs[0].ip = ip;
- n->ip_flgs[0].nb_flags = nb_flags;
-
- n->source = source;
-
- if (!n2) add_name(d,n);
-
- DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x to interface %s\n",
- namestr(&n->name),inet_ntoa(ip),ttl,nb_flags,
- wins ? "WINS" : (char *)inet_ntoa(d->bcast_ip)));
-
- return(n);
-}
-
-
-/*******************************************************************
- 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 (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- for (n = d->namelist; n; n = next)
- {
- next = n->next;
- if (n->death_time && n->death_time < t)
- {
- if (n->source == SELF)
- {
- DEBUG(3,("not expiring SELF name %s\n", namestr(&n->name)));
- n->death_time += 300;
- continue;
- }
- DEBUG(3,("Removing dead name %s\n", namestr(&n->name)));
-
- if (n->prev) n->prev->next = n->next;
- if (n->next) n->next->prev = n->prev;
-
- if (d->namelist == n) d->namelist = n->next;
-
- if(n->ip_flgs != NULL)
- free(n->ip_flgs);
- free(n);
- }
- }
- }
-}
-
-
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.0
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: namedbname.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-*/
-
-this module deals with the NetBIOS name database for samba. it deals
-directly with adding, removing, finding, loading and saving of names.
-
-/*************************************************************************
- search_for_name()
- *************************************************************************/
-
-this function is responsible for finding a name in the appropriate part
-of samba's NetBIOS name database. if the name cannot be found, then it
-should look the name up using DNS. later modifications will be to
-forward the request on to another WINS server, should samba not be able
-to find out about the requested name (this will be implemented through
-issuing a new type of samba 'state').
-
-the name is first searched for in the NetBIOS cache. if it cannot be
-found, then it if the name looks like it's a server-type name (0x20
-0x0 or 0x1b) then DNS is used to look for the name.
-
-if DNS fails, then a record of this failure is kept. if it succeeds, then
-a new NetBIOS entry is added.
-
-the successfully found name is returned. on failure, NULL is returned.
-
-
-/*************************************************************************
- expire_names()
- *************************************************************************/
-
-this function is responsible for removing old NetBIOS names from its
-database. no further action is required.
-
-for over-zealous WINS systems, the use of query_refresh_names() is
-recommended. this function initiates polling of hosts that have
-registered with samba in its capacity as a WINS server. an alternative
-means to achieve the same end as query_refresh_names() is to
-reduce the time to live when the name is registered with samba,
-except that in this instance the responsibility for refreshing the
-name is with the owner of the name, not the server with which the name
-is registered.
-
-
-/*************************************************************************
- add_netbios_entry()
- *************************************************************************/
-
-this function is responsible for adding or updating a NetBIOS name
-in the database. into the local interface records, the only names
-that will be added are those of domain master browsers and
-samba's own names. into the WINS records, all names are added.
-
-the name to be added / updated will be looked up in the records.
-if it is found, then we will not overwrite the entry if the flag
-'newonly' is True, or if the name is being added as a non-SELF
-(non-samba) name and the records indicate that samba owns the
-name.
-
-otherwise, the name is added or updated with the new details.
-
-
-/*************************************************************************
- remove_netbios_entry()
- *************************************************************************/
-
-this function is responsible for removing a NetBIOS entry from
-the database. the name is searched for in the records using
-find_name_search(). if the ip is zero, then the ip is ignored.
-
-the name is removed if the expected source (e.g SELF, REGISTER)
-matches that in the database.
-
-
-/*************************************************************************
- load_netbios_names()
- *************************************************************************/
-
-this function is responsible for loading any NetBIOS names that samba,
-in its WINS capacity, has written out to disk. all the relevant details
-are recorded in this file, including the time-to-live. should the
-time left to live be small, the name is not added back in to samba's
-WINS database.
-
-
-/*************************************************************************
- dump_names()
- *************************************************************************/
-
-this function is responsible for outputting NetBIOS names in two formats.
-firstly, as debugging information, and secondly, all names that have been
-registered with samba in its capacity as a WINS server are written to
-disk.
-
-writing all WINS names allows two things. firstly, if samba's NetBIOS
-daemon dies or is terminated, on restarting the daemon most if not all
-of the registered WINS names will be preserved (which is a good reason
-why query_netbios_names() should be used).
-
-
-/*************************************************************************
- find_name_search()
- *************************************************************************/
-
-this function is a wrapper around find_name(). find_name_search() can
-be told whether to search for the name in a local subnet structure or
-in the WINS database. on top of this, it can be told to search only
-for samba's SELF names.
-
-if it finds the name in the WINS database, it will set the subnet_record
-and also return the name it finds.
-
-
-/*************************************************************************
- find_name()
- *************************************************************************/
-
-this function is a low-level search function that searches a single
-interface's NetBIOS records for a name. if the ip to be found is
-zero then the ip address is ignored. this is to enable a name to
-be found without knowing its ip address, and also to find the exact
-name if a large number of group names are added with different ip
-addresses.
-
-
-/*************************************************************************
- remove_name()
- *************************************************************************/
-
-this function is responsible for removing a specific NetBIOS entry
-from a subnet list's records. only if the pointer to the entry is
-in the list will the name be removed.
-
-
-/*************************************************************************
- add_name()
- *************************************************************************/
-
-this function is responsible for adding a NetBIOS entry into a
-subnet list's records.
-
-
-/*************************************************************************
- ms_browser_name()
- *************************************************************************/
-
-this function returns True if the NetBIOS name passed to it is
-^1^2__MSBROWSE__^2^1
-
-
-/*************************************************************************
- name_equal()
- *************************************************************************/
-
-this function returns True if the two NetBIOS names passed to it
-match in name, type and scope: the NetBIOS names are equal.
-
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios library routines
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Module name: namedbresp.c
-
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-
-extern struct subnet_record *subnetlist;
-
-extern int DEBUGLEVEL;
-
-extern pstring scope;
-extern pstring myname;
-extern struct in_addr ipzero;
-
-int num_response_packets = 0;
-
-/***************************************************************************
- add an expected response record into the list
- **************************************************************************/
-void add_response_record(struct subnet_record *d,
- struct response_record *n)
-{
- struct response_record *n2;
-
- if (!d) return;
-
- num_response_packets++; /* count of total number of packets still around */
-
- DEBUG(4,("adding response record id:%d num_records:%d\n",
- n->response_id, num_response_packets));
-
- if (!d->responselist)
- {
- d->responselist = n;
- n->prev = NULL;
- n->next = NULL;
- return;
- }
-
- for (n2 = d->responselist; n2->next; n2 = n2->next) ;
-
- n2->next = n;
- n->next = NULL;
- n->prev = n2;
-}
-
-
-/***************************************************************************
- remove an expected response record from the list
- **************************************************************************/
-void remove_response_record(struct subnet_record *d,
- struct response_record *n)
-{
- if (!d) return;
-
- 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--; /* count of total number of packets still around */
-}
-
-
-/****************************************************************************
- create a name query response record
- **************************************************************************/
-struct response_record *make_response_queue_record(enum state_type state,
- int id,uint16 fd,
- int quest_type, char *name,int type, int nb_flags, time_t ttl,
- int server_type, char *my_name, char *my_comment,
- BOOL bcast,BOOL recurse,
- struct in_addr send_ip, struct in_addr reply_to_ip,
- int reply_id)
-{
- struct response_record *n;
-
- if (!name || !name[0]) return NULL;
-
- if (!(n = (struct response_record *)malloc(sizeof(*n))))
- return(NULL);
-
- bzero((char *)n, sizeof(*n));
-
- n->response_id = id;
- n->state = state;
- 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->server_type = server_type;
- n->bcast = bcast;
- n->recurse = recurse;
- n->send_ip = send_ip;
- n->reply_to_ip = reply_to_ip;
- n->reply_id = reply_id;
- if(my_name)
- StrnCpy(n->my_name, my_name, sizeof(n->my_name)-1);
- else
- *n->my_name = 0;
- if(my_comment)
- StrnCpy(n->my_comment, my_comment, sizeof(n->my_comment)-1);
- else
- *n->my_comment = 0;
- n->repeat_interval = 1; /* XXXX should be in ms */
- n->repeat_count = 3; /* 3 retries */
- n->repeat_time = time(NULL) + n->repeat_interval; /* initial retry time */
-
- n->num_msgs = 0;
-
- return n;
-}
-
-
-/****************************************************************************
- find a response in a subnet's name query response list.
- **************************************************************************/
-struct response_record *find_response_record(struct subnet_record **d,
- uint16 id)
-{
- struct response_record *n;
-
- if (!d) return NULL;
-
- for ((*d) = FIRST_SUBNET; (*d); (*d) = NEXT_SUBNET_INCLUDING_WINS(*d))
- {
- for (n = (*d)->responselist; n; n = n->next)
- {
- if (n->response_id == id) {
- DEBUG(4, ("found response record on %s: %d\n",
- inet_ntoa((*d)->bcast_ip), id));
- return n;
- }
- }
- }
-
- *d = NULL;
-
- return NULL;
-}
-
-
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.1
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: namedbresp.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-
- 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
- tridge's comments on first revision
-*/
-
-module namedbresp deals with the maintenance of the list of expected
-responses - creating, finding and removal.
-
-module nameresp deals with the initial transmission, re-transmission
-and time-out of netbios response records.
-
-
-/*************************************************************************
- find_response_record()
- *************************************************************************/
-
-this function is responsible for matching the unique response transaction
-id with an expected response record. as a side-effect of this search,
-it will find the subnet (or the WINS pseudo-subnet) that samba expected
-the response to come from.
-
-
-/*************************************************************************
- make_response_queue_record()
- *************************************************************************/
-
-this function is responsible for creating a response record, which will
-be queued awaiting a response.
-
-the number of retries is set to 3, and the retry period set to 1 second.
-if no response is received, then the packet is re-transmitted, which is
-why so much information is stored in the response record.
-
-the number of expected responses queued is kept, so listen_for_packets()
-knows it must time-out after 1 second if one or more responses are
-expected.
-
-
-/*************************************************************************
- remove_response_record()
- *************************************************************************/
-
-this function is responsible for removing a response record from the
-expected response queue. the number of expected responses is decreased.
-
-
-/*************************************************************************
- add_response_record()
- *************************************************************************/
-
-this function is responsible for adding the response record created by
-make_response_queue_record() into the appropriate response record queue.
-
-
------------------
-NOTE FROM TRIDGE:
-
-namedbresp.c is interesting because it implements a novel way of
-getting most of the advantages of a multi-threaded nmbd daemon without
-the portability problems.
-
-The NBT specs (rfc1001/1002) talk about the 16 bit IDs in the packets
-as being used to ensure that packets are unique, and to stop packets
-from being confused. It suggests incrementing the ID by 1 each time.
-
-Instead Luke uses these IDs to identify individual threads of control
-in nmbd. So when nmbd sends out a NBT packet as part of some complex
-processing, it adds to a linked list the information required to
-continue the processing when the reply comes in (or it times
-out). When a reply arrives this list can be searched to find the
-matching query and the next step in the processing can be carried out.
-
-This is really good stuff, and allows for much more complex behaviour
-than was possible with the old nmbd.
-----------------
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- created module namedbserver containing server database functions
-
-*/
-
-#include "includes.h"
-#include "smb.h"
-
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-extern pstring myname;
-extern fstring myworkgroup;
-
-/* this is our domain/workgroup/server database */
-extern struct subnet_record *subnetlist;
-
-extern BOOL updatedlists;
-
-
-/*******************************************************************
- expire old servers in the serverlist
- time of -1 indicates everybody dies except those with time of 0
- remove_all_servers indicates everybody dies.
- ******************************************************************/
-void remove_old_servers(struct work_record *work, time_t t,
- BOOL remove_all)
-{
- struct server_record *s;
- struct server_record *nexts;
-
- /* expire old entries in the serverlist */
- for (s = work->serverlist; s; s = nexts)
- {
- nexts = s->next;
- if (remove_all ||
- (s->death_time && (t == -1 || s->death_time < t))) {
- DEBUG(3,("Removing dead server %s\n",s->serv.name));
- updatedlists = True;
-
- if (s->prev) s->prev->next = s->next;
- if (s->next) s->next->prev = s->prev;
-
- if (work->serverlist == s)
- work->serverlist = s->next;
-
- free(s);
- }
- }
-}
-
-
-/***************************************************************************
- add a server into the list
- **************************************************************************/
-static void add_server(struct work_record *work,struct server_record *s)
-{
- struct server_record *s2;
-
- if (!work->serverlist) {
- work->serverlist = s;
- s->prev = NULL;
- s->next = NULL;
- return;
- }
-
- for (s2 = work->serverlist; s2->next; s2 = s2->next) ;
-
- s2->next = s;
- s->next = NULL;
- s->prev = s2;
-}
-
-
-/****************************************************************************
- find a server in a server list.
- **************************************************************************/
-struct server_record *find_server(struct work_record *work, char *name)
-{
- struct server_record *ret;
-
- if (!work) return NULL;
-
- for (ret = work->serverlist; ret; ret = ret->next)
- {
- if (strequal(ret->serv.name,name))
- {
- return ret;
- }
- }
- return NULL;
-}
-
-
-/****************************************************************************
- add a server entry
- ****************************************************************************/
-struct server_record *add_server_entry(struct subnet_record *d,
- struct work_record *work,
- char *name,int servertype,
- int ttl,char *comment,
- BOOL replace)
-{
- BOOL newentry=False;
- struct server_record *s;
-
- if (name[0] == '*')
- {
- return (NULL);
- }
-
- s = find_server(work, name);
-
- if (s && !replace)
- {
- DEBUG(4,("Not replacing %s\n",name));
- return(s);
- }
-
- if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment))
- updatedlists=True;
-
- if (!s)
- {
- newentry = True;
- s = (struct server_record *)malloc(sizeof(*s));
-
- if (!s) return(NULL);
-
- bzero((char *)s,sizeof(*s));
- }
-
-
- /* update the entry */
- StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
- StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
- strupper(s->serv.name);
- s->serv.type = servertype;
- 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 */
-
- if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
-
- if (newentry)
- {
- add_server(work, s);
-
- DEBUG(3,("Added "));
- }
- else
- {
- DEBUG(3,("Updated "));
- }
-
- DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
- name,servertype,comment,
- work->work_group,inet_ntoa(d->bcast_ip)));
-
- return(s);
-}
-
-
-/*******************************************************************
- expire old servers in the serverlist
- ******************************************************************/
-void expire_servers(time_t t)
-{
- struct subnet_record *d;
-
- for (d = FIRST_SUBNET; d ; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- struct work_record *work;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- remove_old_servers(work, t, False);
- }
- }
-}
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- created module namedbsubnet containing subnet database functions
-
-*/
-
-#include "includes.h"
-#include "smb.h"
-
-extern int ClientNMB;
-extern int ClientDGRAM;
-extern int global_nmb_port;
-
-extern int DEBUGLEVEL;
-
-extern struct in_addr wins_ip;
-extern struct in_addr ipzero;
-
-extern pstring myname;
-extern fstring myworkgroup;
-extern char **my_netbios_names;
-
-BOOL updatedlists = True;
-int updatecount = 0;
-
-/* local interfaces structure */
-extern struct interface *local_interfaces;
-
-/* this is our domain/workgroup/server database */
-struct subnet_record *subnetlist = NULL;
-
-/* WINS subnet - keep this separate so enumeration code doesn't
- run onto it by mistake. */
-struct subnet_record *wins_client_subnet = NULL;
-
-extern uint16 nb_type; /* samba's NetBIOS name type */
-
-/****************************************************************************
- add a domain into the list
- **************************************************************************/
-static void add_subnet(struct subnet_record *d)
-{
- struct subnet_record *d2;
-
- if (!subnetlist)
- {
- subnetlist = d;
- d->prev = NULL;
- d->next = NULL;
- return;
- }
-
- for (d2 = subnetlist; d2->next; d2 = d2->next);
-
- d2->next = d;
- d->next = NULL;
- d->prev = d2;
-}
-
-
-/****************************************************************************
- find a subnet in the subnetlist that a given IP address could
- match - not including WINS. Returns NULL if no match.
- **************************************************************************/
-struct subnet_record *find_subnet(struct in_addr ip)
-{
- struct subnet_record *d = NULL;
-
- /* search through subnet list for broadcast/netmask that matches
- the source ip address. */
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- if (same_net(ip, d->bcast_ip, d->mask_ip))
- break;
- }
-
- return d;
-}
-
-/****************************************************************************
- find a subnet in the subnetlist - if the subnet is not found
- then return the WINS client subnet.
- **************************************************************************/
-struct subnet_record *find_subnet_all(struct in_addr ip)
-{
- struct subnet_record *d = find_subnet(ip);
- if(!d)
- return wins_client_subnet;
- return d;
-}
-
-/****************************************************************************
- create a subnet entry
- ****************************************************************************/
-static struct subnet_record *make_subnet(struct in_addr myip, struct in_addr bcast_ip,
- struct in_addr mask_ip, BOOL add)
-{
- struct subnet_record *d = NULL;
- int nmb_sock, dgram_sock;
-
- /* Check if we are creating the WINS subnet - if so don't create
- sockets, use the ClientNMB and ClientDGRAM sockets instead.
- */
-
- if(ip_equal(bcast_ip, wins_ip))
- {
- nmb_sock = -1;
- dgram_sock = -1;
- }
- else
- {
- /*
- * Attempt to open the sockets on port 137/138 for this interface
- * and bind them.
- * Fail the subnet creation if this fails.
- */
-
- if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr)) == -1)
- {
- DEBUG(0,("make_subnet: Failed to open nmb socket on interface %s \
-for port %d. Error was %s\n", inet_ntoa(myip), global_nmb_port, strerror(errno)));
- return NULL;
- }
-
- if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr)) == -1)
- {
- DEBUG(0,("make_subnet: Failed to open dgram socket on interface %s \
-for port %d. Error was %s\n", inet_ntoa(myip), DGRAM_PORT, strerror(errno)));
- return NULL;
- }
-
- /* Make sure we can broadcast from these sockets. */
- set_socket_options(nmb_sock,"SO_BROADCAST");
- set_socket_options(dgram_sock,"SO_BROADCAST");
-
- }
-
- d = (struct subnet_record *)malloc(sizeof(*d));
-
- if (!d)
- {
- DEBUG(0,("make_subnet: malloc fail !\n"));
- close(nmb_sock);
- close(dgram_sock);
- return(NULL);
- }
-
- bzero((char *)d,sizeof(*d));
-
- DEBUG(4, ("making subnet %s ", inet_ntoa(bcast_ip)));
- DEBUG(4, ("%s\n", inet_ntoa(mask_ip)));
-
- d->bcast_ip = bcast_ip;
- d->mask_ip = mask_ip;
- d->myip = myip;
- d->nmb_sock = nmb_sock;
- d->dgram_sock = dgram_sock;
- d->workgrouplist = NULL;
-
- if(add)
- add_subnet(d);
-
- return d;
-}
-
-/****************************************************************************
- add a domain entry. creates a workgroup, if necessary, and adds the domain
- to the named a workgroup.
- ****************************************************************************/
-static struct subnet_record *add_subnet_entry(struct in_addr myip,
- struct in_addr bcast_ip,
- struct in_addr mask_ip, char *name,
- BOOL create_subnets, BOOL add)
-{
- struct subnet_record *d = NULL;
-
- if (zero_ip(bcast_ip))
- bcast_ip = *iface_bcast(bcast_ip);
-
- /* Note that we should also add into the WINS subnet as add_subnet_entry
- should be called to add NetBIOS names and server entries on all
- interfaces, including the WINS interface
- */
-
- if(create_subnets == True)
- {
- /* Create new subnets. */
- if((d = make_subnet(myip, bcast_ip, mask_ip, add)) == NULL)
- {
- DEBUG(0,("add_subnet_entry: Unable to create subnet %s\n",
- inet_ntoa(bcast_ip) ));
- return NULL;
- }
- return d;
- }
- if(ip_equal(bcast_ip, wins_ip))
- return wins_client_subnet;
- return find_subnet(bcast_ip);
-}
-
-/****************************************************************************
- Add a workgroup into a subnet, and if it's our primary workgroup,
- add the required names to it.
-**************************************************************************/
-
-void add_workgroup_to_subnet( struct subnet_record *d, char *group)
-{
- struct work_record *w = NULL;
-
- DEBUG(5,("add_workgroup_to_subnet: Adding workgroup %s to subnet %s\n",
- group, inet_ntoa(d->bcast_ip)));
-
- /* This next statement creates the workgroup struct if it doesn't
- already exist.
- */
- if((w = find_workgroupstruct(d, group, True)) == NULL)
- {
- DEBUG(0,("add_workgroup_to_subnet: Unable to add workgroup %s to subnet %s\n",
- group, inet_ntoa(d->bcast_ip) ));
- return;
- }
-
- /* add WORKGROUP(00) entries into name database
- or register with WINS server, if it's our workgroup.
- */
- if (strequal(myworkgroup, group))
- {
- int n;
-
- add_my_name_entry(d,group,0x0 ,nb_type|NB_ACTIVE|NB_GROUP);
-
- /* Register the WORKGROUP<0x1e> name. */
- add_my_name_entry(d,group,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
-
- /* Add all our server names to the workgroup list. We remove any
- browser or logon server flags from all but the primary name.
- */
- for( n = 0; my_netbios_names[n]; n++)
- {
- char *name = my_netbios_names[n];
- int stype = w->ServerType;
-
- if(!strequal(myname, name))
- stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
- SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
-
- add_server_entry(d,w,name,stype|SV_TYPE_LOCAL_LIST_ONLY,0,
- lp_serverstring(),True);
- DEBUG(3,("add_workgroup_to_subnet: Added server name entry %s \
-to subnet %s\n", name, inet_ntoa(d->bcast_ip)));
- }
- }
-}
-
-/****************************************************************************
- create subnet / workgroup / server entries
-
- - add or create the subnet lists
- - add or create the workgroup entries in each subnet entry
- - register appropriate NetBIOS names for the workgroup entries
-
-**************************************************************************/
-void add_my_subnets(char *group)
-{
- static BOOL create_subnets = True;
- struct subnet_record *d = NULL;
- struct interface *i = NULL;
-
- if (*group == '*') return;
-
- /* Create subnets from all the local interfaces and thread them onto
- the linked list.
- */
- for (i = local_interfaces; i; i = i->next)
- {
- add_subnet_entry(i->ip, i->bcast,i->nmask,group, create_subnets, True);
- }
-
- /* If we are using WINS, then we must add the workgroup to the WINS
- subnet. This is used as a place to keep collated server lists.
- */
-
- /* Create the WINS subnet if we are using WINS - but don't thread it
- onto the linked subnet list.
- */
- if (lp_wins_support() || lp_wins_server())
- {
- struct in_addr wins_nmask = ipzero;
- wins_client_subnet = add_subnet_entry(ipzero, wins_ip, wins_nmask, group, create_subnets, False);
- }
-
- /* Ensure we only create the subnets once. */
- create_subnets = False;
-
- /* Now we have created all the subnets - we can add the names
- that make us a client member in the workgroup.
- */
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- add_workgroup_to_subnet(d, group);
-}
-
-/*******************************************************************
- write out browse.dat
- ******************************************************************/
-void write_browse_list(time_t t)
-{
- struct subnet_record *d;
- pstring fname,fnamenew;
- FILE *f;
-
- static time_t lasttime = 0;
-
- if (!lasttime) lasttime = t;
- if (!updatedlists || t - lasttime < 5) return;
-
- lasttime = t;
- updatedlists = False;
- updatecount++;
-
- dump_names();
- dump_workgroups();
-
- pstrcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,SERVER_LIST);
- pstrcpy(fnamenew,fname);
- strcat(fnamenew,".");
-
- f = fopen(fnamenew,"w");
-
- if (!f)
- {
- DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
- return;
- }
-
- for (d = FIRST_SUBNET; d ; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- struct work_record *work;
- for (work = d->workgrouplist; work ; work = work->next)
- {
- struct server_record *s;
- for (s = work->serverlist; s ; s = s->next)
- {
- fstring tmp;
-
- /* don't list domains I don't have a master for */
- if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0])
- {
- continue;
- }
-
- /* output server details, plus what workgroup/domain
- they're in. without the domain information, the
- combined list of all servers in all workgroups gets
- sent to anyone asking about any workgroup! */
-
- sprintf(tmp, "\"%s\"", s->serv.name);
- fprintf(f, "%-25s ", tmp);
- fprintf(f, "%08x ", s->serv.type);
- sprintf(tmp, "\"%s\" ", s->serv.comment);
- fprintf(f, "%-30s", tmp);
- fprintf(f, "\"%s\"\n", work->work_group);
- }
- }
- }
-
- fclose(f);
- unlink(fname);
- chmod(fnamenew,0644);
- rename(fnamenew,fname);
- DEBUG(3,("Wrote browse list %s\n",fname));
-}
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- created module namedbwork containing workgroup database functions
-
-*/
-
-#include "includes.h"
-#include "smb.h"
-
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-/* this is our domain/workgroup/server database */
-extern struct subnet_record *subnetlist;
-
-extern struct in_addr wins_ip;
-
-extern fstring myworkgroup;
-
-int workgroup_count = 0; /* unique index key: one for each workgroup */
-
-
-
-/****************************************************************************
- add a workgroup into the domain list
- **************************************************************************/
-static void add_workgroup(struct work_record *work, struct subnet_record *d)
-{
- struct work_record *w2;
-
- if (!work || !d) return;
-
- if (!d->workgrouplist)
- {
- d->workgrouplist = work;
- work->prev = NULL;
- work->next = NULL;
- return;
- }
-
- for (w2 = d->workgrouplist; w2->next; w2 = w2->next);
-
- w2->next = work;
- work->next = NULL;
- work->prev = w2;
-}
-
-
-/****************************************************************************
- create a blank workgroup
- **************************************************************************/
-static struct work_record *make_workgroup(char *name)
-{
- struct work_record *work;
- struct subnet_record *d;
- int t = -1;
-
- if (!name || !name[0]) return NULL;
-
- work = (struct work_record *)malloc(sizeof(*work));
- if (!work) return(NULL);
- bzero((char *)work, sizeof(*work));
-
- StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
- work->serverlist = NULL;
-
- /* set up initial value for server announce type */
- work->ServerType = lp_default_server_announce();
- work->ServerType |= lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0;
- work->ServerType |= lp_domain_controller() ? SV_TYPE_DOMAIN_CTRL : 0;
-
- work->RunningElection = False;
- work->ElectionCount = 0;
- work->announce_interval = 0;
- work->needelection = False;
- work->needannounce = True;
- work->mst_state = MST_POTENTIAL;
- work->dom_state = DOMAIN_NONE;
- work->log_state = LOGON_NONE;
-
- /* make sure all token representations of workgroups are unique */
-
- for (d = FIRST_SUBNET; d && t == -1; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- struct work_record *w;
- for (w = d->workgrouplist; w && t == -1; w = w->next)
- {
- if (strequal(w->work_group, work->work_group)) t = w->token;
- }
- }
-
- if (t == -1)
- {
- work->token = ++workgroup_count;
- }
- else
- {
- work->token = t;
- }
-
-
- /* WfWg uses 01040b01 */
- /* Win95 uses 01041501 */
- /* NTAS uses ???????? */
- work->ElectionCriterion = (MAINTAIN_LIST)|(ELECTION_VERSION<<8);
- work->ElectionCriterion |= (lp_os_level() << 24);
- if (lp_domain_master()) {
- work->ElectionCriterion |= 0x80;
- }
-
- return work;
-}
-
-
-/*******************************************************************
- remove workgroups
- ******************************************************************/
-struct work_record *remove_workgroup(struct subnet_record *d,
- struct work_record *work,
- BOOL remove_all_servers)
-{
- struct work_record *ret_work = NULL;
-
- if (!d || !work) return NULL;
-
- DEBUG(3,("Removing old workgroup %s\n", work->work_group));
-
- ret_work = work->next;
-
- remove_old_servers(work, -1, remove_all_servers);
-
- if (!work->serverlist)
- {
- if (work->prev) work->prev->next = work->next;
- if (work->next) work->next->prev = work->prev;
-
- if (d->workgrouplist == work) d->workgrouplist = work->next;
-
- free(work);
- }
-
- return ret_work;
-}
-
-
-/****************************************************************************
- find a workgroup in the workgrouplist
- only create it if the domain allows it, or the parameter 'add' insists
- that it get created/added anyway. this allows us to force entries in
- lmhosts file to be added.
- **************************************************************************/
-struct work_record *find_workgroupstruct(struct subnet_record *d,
- fstring name, BOOL add)
-{
- struct work_record *ret, *work;
-
- if (!d) return NULL;
-
- DEBUG(4, ("workgroup search for %s: ", name));
-
- for (ret = d->workgrouplist; ret; ret = ret->next) {
- if (!strcmp(ret->work_group,name)) {
- DEBUG(4, ("found\n"));
- return(ret);
- }
- }
-
- if (!add) {
- DEBUG(4, ("not found\n"));
- return NULL;
- }
-
- DEBUG(4,("not found: creating\n"));
-
- if ((work = make_workgroup(name)))
- {
- if (!ip_equal(d->bcast_ip, wins_ip) &&
- lp_preferred_master() && lp_local_master() &&
- strequal(myworkgroup, name))
- {
- DEBUG(3, ("preferred master startup for %s\n", work->work_group));
- work->needelection = True;
- work->ElectionCriterion |= (1<<3);
- }
- add_workgroup(work, d);
- return(work);
- }
- return NULL;
-}
-
-
-/****************************************************************************
- dump a copy of the workgroup/domain database
- **************************************************************************/
-void dump_workgroups(void)
-{
- struct subnet_record *d;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- if (d->workgrouplist)
- {
- struct work_record *work;
-
- DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip)));
- DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip)));
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- DEBUG(4,("\t%s(%d)\n", work->work_group, work->token));
- if (work->serverlist)
- {
- struct server_record *s;
- for (s = work->serverlist; s; s = s->next)
- {
- DEBUG(4,("\t\t%s %8x (%s)\n",
- s->serv.name, s->serv.type, s->serv.comment));
- }
- }
- }
- }
- }
-}
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Module name: nameelect.c
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- added system to become a master browser by stages.
-
-
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-extern int ClientDGRAM;
-
-extern int DEBUGLEVEL;
-extern pstring scope;
-
-extern pstring myname;
-extern fstring myworkgroup;
-extern struct in_addr ipzero;
-extern struct in_addr wins_ip;
-
-/* here are my election parameters */
-
-extern time_t StartupTime;
-
-extern struct subnet_record *subnetlist;
-
-extern uint16 nb_type; /* samba's NetBIOS name type */
-
-
-/*******************************************************************
- occasionally check to see if the master browser is around
- ******************************************************************/
-void check_master_browser(time_t t)
-{
- static time_t lastrun=0;
- struct subnet_record *d;
-
- if (!lastrun) lastrun = t;
- if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return;
-
- lastrun = t;
-
- dump_workgroups();
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- struct work_record *work;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- if (strequal(work->work_group, myworkgroup) && !AM_MASTER(work))
- {
- if (lp_local_master() && lp_preferred_master())
- {
- /* potential master browser - not a master browser. force
- becoming a master browser, hence the log message.
- */
-
- DEBUG(2,("%s potential master for %s %s - force election\n",
- timestring(), work->work_group,
- inet_ntoa(d->bcast_ip)));
-
- browser_gone(work->work_group, d->bcast_ip);
- }
- else
- {
- /* if we are not the browse master of a workgroup,
- and we can't find a browser on the subnet, do
- something about it.
- */
-
- queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
- work->work_group,0x1d,0,0,0,NULL,NULL,
- True,False,d->bcast_ip,d->bcast_ip, 0);
- }
- }
- }
- }
-}
-
-
-/*******************************************************************
- what to do if a master browser DOESN't exist.
-
- option 1: force an election, and participate in it
- option 2: force an election, and let everyone else participate.
-
- ******************************************************************/
-void browser_gone(char *work_name, struct in_addr ip)
-{
- struct subnet_record *d = find_subnet(ip);
- struct work_record *work = find_workgroupstruct(d, work_name, False);
-
- /* i don't know about this workgroup, therefore i don't care */
- if (!work || !d) return;
-
- /* don't do election stuff on the WINS subnet */
- if (ip_equal(d->bcast_ip,wins_ip))
- return;
-
- if (strequal(work->work_group, myworkgroup))
- {
-
- if (lp_local_master())
- {
- /* we have discovered that there is no local master
- browser, and we are configured to initiate
- an election under exactly such circumstances.
- */
- DEBUG(2,("Forcing election on %s %s\n",
- work->work_group,inet_ntoa(d->bcast_ip)));
-
- /* we can attempt to become master browser */
- work->needelection = True;
- }
- else
- {
- /* we need to force an election, because we are configured
- not to _become_ the local master, but we still _need_ one,
- having detected that one doesn't exist.
- */
-
- /* local interfaces: force an election */
- send_election(d, work->work_group, 0, 0, myname);
-
- /* only removes workgroup completely on a local interface
- persistent lmhosts entries on a local interface _will_ be removed).
- */
- remove_workgroup(d, work,True);
- add_workgroup_to_subnet(d, work->work_group);
- }
- }
-}
-
-
-/****************************************************************************
- send an election packet
- **************************************************************************/
-void send_election(struct subnet_record *d, char *group,uint32 criterion,
- int timeup,char *name)
-{
- pstring outbuf;
- char *p;
-
- if (!d) return;
-
- DEBUG(2,("Sending election to %s for workgroup %s\n",
- inet_ntoa(d->bcast_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = ANN_Election; /* election */
- p++;
-
- CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
- SIVAL(p,1,criterion);
- SIVAL(p,5,timeup*1000); /* ms - despite the spec */
- p += 13;
- pstrcpy(p,name);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
- outbuf,PTR_DIFF(p,outbuf),
- name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
-}
-
-
-/****************************************************************************
- un-register a SELF name that got rejected.
-
- if this name happens to be rejected when samba is in the process
- of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
- or WORKGROUP(1b)) then we must stop being a master browser. sad.
-
- **************************************************************************/
-void name_unregister_work(struct subnet_record *d, char *name, int name_type)
-{
- struct work_record *work;
- int remove_type_local = 0;
- int remove_type_domain = 0;
- int remove_type_logon = 0;
-
- remove_netbios_name(d,name,name_type,SELF);
-
- if (!(work = find_workgroupstruct(d, name, False))) return;
-
- /* work out what to unbecome, from the name type being removed */
-
- if (ms_browser_name(name, name_type))
- {
- remove_type_local |= SV_TYPE_MASTER_BROWSER;
- }
- if (AM_MASTER(work) && strequal(name, myworkgroup) && name_type == 0x1d)
- {
- remove_type_local |= SV_TYPE_MASTER_BROWSER;
- }
- if (AM_DOMMST(work) && strequal(name, myworkgroup) && name_type == 0x1b)
- {
- remove_type_domain |= SV_TYPE_DOMAIN_MASTER;
- }
- if (AM_DOMMEM(work) && strequal(name, myworkgroup) && name_type == 0x1c)
- {
- remove_type_logon|= SV_TYPE_DOMAIN_MEMBER;
- }
-
- if (remove_type_local ) unbecome_local_master (d, work, remove_type_local );
- if (remove_type_domain) unbecome_domain_master(d, work, remove_type_domain);
- if (remove_type_logon ) unbecome_logon_server (d, work, remove_type_logon );
-}
-
-
-/****************************************************************************
- registers a name.
-
- if the name being added is a SELF name, we must additionally check
- whether to proceed to the next stage in samba becoming a master browser.
-
- **************************************************************************/
-void name_register_work(struct subnet_record *d, char *name, int name_type,
- int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
-{
- enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
- SELF : REGISTER;
-
- if (source == SELF)
- {
- struct work_record *work = find_workgroupstruct(d,
- myworkgroup, False);
-
- struct subnet_record *add_subnet = (!bcast) ? wins_client_subnet : d;
- add_netbios_entry(add_subnet,name,name_type,nb_flags,ttl,source,ip,True);
-
- if (work)
- {
- int add_type_local = False;
- int add_type_domain = False;
- int add_type_logon = False;
-
- DEBUG(4,("checking next stage: name_register_work %s\n", name));
-
- /* work out what to become, from the name type being added */
-
- if (ms_browser_name(name, name_type))
- {
- add_type_local = True;
- }
- if (strequal(name, myworkgroup) && name_type == 0x1d)
- {
- add_type_local = True;
- }
- if (strequal(name, myworkgroup) && name_type == 0x1b)
- {
- add_type_domain = True;
- }
- if (strequal(name, myworkgroup) && name_type == 0x1c)
- {
- add_type_logon = True;
- }
-
- if (add_type_local ) become_local_master (d, work);
- if (add_type_domain) become_domain_master(d, work);
- if (add_type_logon ) become_logon_server (d, work);
- }
- }
-}
-
-
-/*******************************************************************
- become the local master browser.
-
- this is done in stages. note that this could take a while,
- particularly on a broadcast subnet, as we have to wait for
- the implicit registration of each name to be accepted.
-
- as each name is successfully registered, become_local_master() is
- called again, in order to initiate the next stage. see
- dead_netbios_entry() - deals with implicit name registration
- and response_name_reg() - deals with explicit registration
- with a WINS server.
-
- stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1.
- stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d)
- stage 3: was MST_MSB - go to MST_BROWSER and stay there
-
- XXXX note: this code still does not cope with the distinction
- between different types of nodes, particularly between M and P
- nodes. that comes later.
-
- ******************************************************************/
-void become_local_master(struct subnet_record *d, struct work_record *work)
-{
- /* domain type must be limited to domain enum + server type. it must
- not have SV_TYPE_SERVER or anything else with SERVER in it, else
- clients get confused and start thinking this entry is a server
- not a workgroup
- */
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
-
- if (lp_domain_controller()) domain_type |= SV_TYPE_DOMAIN_CTRL;
-
- if (!work || !d)
- return;
-
- if (!lp_local_master())
- {
- DEBUG(0,("Samba not configured as a local master browser.\n"));
- return;
- }
-
- DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
- work->work_group,inet_ntoa(d->bcast_ip),work->mst_state));
-
- switch (work->mst_state)
- {
- case MST_POTENTIAL: /* while we were nothing but a server... */
- {
- DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
- work->mst_state = MST_BACK; /* an election win was successful */
-
- work->ElectionCriterion |= 0x5;
-
- /* update our server status */
- work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
- add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY,
- 0,lp_serverstring(),True);
-
- /* add special browser name */
- add_my_name_entry(d,MSBROWSE,0x01,nb_type|NB_ACTIVE|NB_GROUP);
-
- /* DON'T do anything else after calling add_my_name_entry() */
- break;
- }
-
- case MST_BACK: /* while nothing had happened except we won an election... */
- {
- DEBUG(3,("go to second stage: register as master browser\n"));
- work->mst_state = MST_MSB; /* registering MSBROWSE was successful */
-
- /* add server entry on successful registration of MSBROWSE */
- add_server_entry(d,work,work->work_group,domain_type|SV_TYPE_LOCAL_LIST_ONLY,
- 0,myname,True);
-
- /* add master name */
- add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE);
-
- /* DON'T do anything else after calling add_my_name_entry() */
- break;
- }
-
- case MST_MSB: /* while we were still only registered MSBROWSE state... */
- {
- int i = 0;
- struct server_record *sl;
-
- DEBUG(3,("2nd stage complete: registered as master browser for workgroup %s \
-on subnet %s\n", work->work_group, inet_ntoa(d->bcast_ip)));
- work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
-
- /* update our server status */
- work->ServerType |= SV_TYPE_MASTER_BROWSER;
-
- DEBUG(3,("become_local_master: updating our server %s to type %x\n",
- myname, work->ServerType));
-
- add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY,
- 0,lp_serverstring(),True);
-
- /* Count the number of servers we have on our list. If it's
- less than 10 (just a heuristic) request the servers
- to announce themselves.
- */
- for( sl = work->serverlist; sl != NULL; sl = sl->next)
- i++;
-
- if (i < 10)
- {
- /* ask all servers on our local net to announce to us */
- announce_request(work, d->bcast_ip);
- }
-
- /* Reset the announce master timer so that we do an announce as soon as possible
- now we are a master. */
- reset_announce_timer();
-
- DEBUG(0,("Samba is now a local master browser for workgroup %s on subnet %s\n",
- work->work_group, inet_ntoa(d->bcast_ip)));
-
- break;
- }
-
- case MST_BROWSER:
- {
- /* don't have to do anything: just report success */
- DEBUG(3,("3rd stage: become master browser!\n"));
- break;
- }
- }
-}
-
-
-/*******************************************************************
- become the domain master browser.
-
- this is done in stages. note that this could take a while,
- particularly on a broadcast subnet, as we have to wait for
- the implicit registration of each name to be accepted.
-
- as each name is successfully registered, become_domain_master() is
- called again, in order to initiate the next stage. see
- dead_netbios_entry() - deals with implicit name registration
- and response_name_reg() - deals with explicit registration
- with a WINS server.
-
- stage 1: was DOMAIN_NONE - go to DOMAIN_MST
-
- XXXX note: this code still does not cope with the distinction
- between different types of nodes, particularly between M and P
- nodes. that comes later.
-
- ******************************************************************/
-void become_domain_master(struct subnet_record *d, struct work_record *work)
-{
- /* domain type must be limited to domain enum + server type. it must
- not have SV_TYPE_SERVER or anything else with SERVER in it, else
- clients get confused and start thinking this entry is a server
- not a workgroup
- */
-
- if (!work || !d) return;
-
- if (!lp_domain_master())
- {
- DEBUG(0,("Samba not configured as a domain master browser.\n"));
- return;
- }
-
- DEBUG(2,("Becoming domain master for %s %s (currently at stage %d)\n",
- work->work_group,inet_ntoa(d->bcast_ip),work->dom_state));
-
- switch (work->dom_state)
- {
- case DOMAIN_NONE: /* while we were nothing but a server... */
- {
- DEBUG(3,("become_domain_master: go to first stage: register <1b> name\n"));
- work->dom_state = DOMAIN_WAIT;
-
- /* XXXX the 0x1b is domain master browser name */
- add_my_name_entry(d, work->work_group,0x1b,nb_type|NB_ACTIVE);
-
- /* DON'T do anything else after calling add_my_name_entry() */
- break;
- }
-
- case DOMAIN_WAIT:
- {
- work->dom_state = DOMAIN_MST; /* ... become domain master */
- DEBUG(3,("become_domain_master: first stage - register as domain member\n"));
-
- /* update our server status */
- work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER;
- add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY,
- 0, lp_serverstring(),True);
-
- DEBUG(0,("Samba is now a domain master browser for workgroup %s on subnet %s\n",
- work->work_group, inet_ntoa(d->bcast_ip)));
-
- if (d == wins_client_subnet)
- {
- /* ok! we successfully registered by unicast with the
- WINS server. we now expect to become the domain
- master on the local subnets. if this fails, it's
- probably a 1.9.16p2 to 1.9.16p11 server's fault.
-
- this is a configuration issue that should be addressed
- by the network administrator - you shouldn't have
- several machines configured as a domain master browser
- for the same WINS scope (except if they are 1.9.17 or
- greater, and you know what you're doing.
-
- see DOMAIN.txt.
-
- */
- add_domain_master_bcast();
- }
- break;
- }
-
- case DOMAIN_MST:
- {
- /* don't have to do anything: just report success */
- DEBUG(3,("domain second stage: there isn't one!\n"));
- break;
- }
- }
-}
-
-
-/*******************************************************************
- become a logon server.
- ******************************************************************/
-void become_logon_server(struct subnet_record *d, struct work_record *work)
-{
- if (!work || !d) return;
-
- if (!lp_domain_logons())
- {
- DEBUG(0,("samba not configured as a logon master.\n"));
- return;
- }
-
- DEBUG(2,("Becoming logon server for %s %s (currently at stage %d)\n",
- work->work_group,inet_ntoa(d->bcast_ip),work->log_state));
-
- switch (work->log_state)
- {
- case LOGON_NONE: /* while we were nothing but a server... */
- {
- DEBUG(3,("go to first stage: register <1c> name\n"));
- work->log_state = LOGON_WAIT;
-
- /* XXXX the 0x1c is apparently something to do with domain logons */
- add_my_name_entry(d, myworkgroup,0x1c,nb_type|NB_ACTIVE|NB_GROUP);
-
- /* DON'T do anything else after calling add_my_name_entry() */
- break;
- }
-
- case LOGON_WAIT:
- {
- work->log_state = LOGON_SRV; /* ... become logon server */
- DEBUG(3,("logon second stage: register \n"));
-
- /* update our server status */
- work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER;
- add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY
- ,0, lp_serverstring(),True);
-
- /* DON'T do anything else after calling add_my_name_entry() */
- break;
- }
-
- case LOGON_SRV:
- {
- DEBUG(3,("logon third stage: there isn't one!\n"));
- break;
- }
- }
-}
-
-
-/*******************************************************************
- unbecome the local master browser. initates removal of necessary netbios
- names, and tells the world that we are no longer a master browser.
-
- XXXX this _should_ be used to demote to a backup master browser, without
- going straight to non-master browser. another time.
-
- ******************************************************************/
-void unbecome_local_master(struct subnet_record *d, struct work_record *work,
- int remove_type)
-{
- /* can only remove master types with this function */
-
- if (remove_type & SV_TYPE_MASTER_BROWSER)
- {
- DEBUG(2,("Becoming local non-master for %s\n",work->work_group));
-
- /* no longer a master browser of any sort */
-
- work->ServerType &= ~SV_TYPE_MASTER_BROWSER;
- work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
- work->ElectionCriterion &= ~0x4;
- work->mst_state = MST_POTENTIAL;
-
- /* announce ourselves as no longer active as a master browser. */
- announce_server(d, work, work->work_group, myname, 0, 0);
- remove_name_entry(d,MSBROWSE ,0x01);
- remove_name_entry(d,work->work_group,0x1d);
- }
-}
-
-
-/*******************************************************************
- unbecome the domain master browser. initates removal of necessary netbios
- names, and tells the world that we are no longer a domain browser.
- ******************************************************************/
-void unbecome_domain_master(struct subnet_record *d, struct work_record *work,
- int remove_type)
-{
- DEBUG(2,("Becoming domain non-master for %s\n",work->work_group));
-
- /* can only remove master or domain types with this function */
- if (remove_type & SV_TYPE_DOMAIN_MASTER)
- {
- /* no longer a domain master browser of any sort */
-
- work->ServerType &= ~SV_TYPE_DOMAIN_MASTER;
- work->dom_state = DOMAIN_NONE;
-
- /* announce ourselves as no longer active as a master browser on
- all our local subnets. */
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- work = find_workgroupstruct(d, myworkgroup, False);
-
- /* Remove the name entry without any NetBIOS traffic as that's
- how it was registered. */
- remove_name_entry(d,work->work_group,0x1b);
- }
-
- /* Unregister the 1b name from the WINS server. */
- if(wins_client_subnet != NULL)
- remove_name_entry(wins_client_subnet, myworkgroup, 0x1b);
- }
-}
-
-
-/*******************************************************************
- unbecome the logon server. initates removal of necessary netbios
- names, and tells the world that we are no longer a logon server.
- ******************************************************************/
-void unbecome_logon_server(struct subnet_record *d, struct work_record *work,
- int remove_type)
-{
- DEBUG(2,("Becoming logon non-server for %s\n",work->work_group));
-
- /* can only remove master or domain types with this function */
-
- if (remove_type & SV_TYPE_DOMAIN_MEMBER)
- {
- /* no longer a master browser of any sort */
-
- work->ServerType &= ~SV_TYPE_DOMAIN_MEMBER;
- work->log_state = LOGON_NONE;
-
- remove_name_entry(d,work->work_group,0x1c);
- }
-}
-
-
-/*******************************************************************
- run the election
- ******************************************************************/
-void run_elections(time_t t)
-{
- static time_t lastime = 0;
-
- struct subnet_record *d;
-
- /* send election packets once a second */
- if (lastime && t-lastime <= 0) return;
-
- lastime = t;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- struct work_record *work;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- if (work->RunningElection)
- {
- send_election(d,work->work_group, work->ElectionCriterion,
- t-StartupTime,myname);
-
- if (work->ElectionCount++ >= 4)
- {
- /* I won! now what :-) */
- DEBUG(2,(">>> Won election on %s %s <<<\n",
- work->work_group,inet_ntoa(d->bcast_ip)));
-
- work->RunningElection = False;
- work->mst_state = MST_POTENTIAL;
-
- become_local_master(d, work);
- }
- }
- }
- }
-}
-
-
-/*******************************************************************
- work out if I win an election
- ******************************************************************/
-static BOOL win_election(struct work_record *work,int version,uint32 criterion,
- int timeup,char *name)
-{
- int mytimeup = time(NULL) - StartupTime;
- uint32 mycriterion = work->ElectionCriterion;
-
- /* If local master is false then never win
- in election broadcasts. */
- if(!lp_local_master())
- {
- DEBUG(3,("win_election: Losing election as local master == False\n"));
- return False;
- }
-
- DEBUG(4,("election comparison: %x:%x %x:%x %d:%d %s:%s\n",
- version,ELECTION_VERSION,
- criterion,mycriterion,
- timeup,mytimeup,
- name,myname));
-
- if (version > ELECTION_VERSION) return(False);
- if (version < ELECTION_VERSION) return(True);
-
- if (criterion > mycriterion) return(False);
- if (criterion < mycriterion) return(True);
-
- if (timeup > mytimeup) return(False);
- if (timeup < mytimeup) return(True);
-
- if (strcasecmp(myname,name) > 0) return(False);
-
- return(True);
-}
-
-
-/*******************************************************************
- process a election packet
-
- An election dynamically decides who will be the master.
- ******************************************************************/
-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_subnet(ip);
- int version = CVAL(buf,0);
- uint32 criterion = IVAL(buf,1);
- int timeup = IVAL(buf,5)/1000;
- char *name = buf+13;
- struct work_record *work;
-
- if (!d) return;
-
- if (ip_equal(d->bcast_ip,wins_ip))
- {
- DEBUG(0,("Unexpected election request from %s %s on WINS net\n",
- name, inet_ntoa(p->ip)));
- return;
- }
-
- name[15] = 0;
-
- DEBUG(3,("Election request from %s %s vers=%d criterion=%08x timeup=%d\n",
- name,inet_ntoa(p->ip),version,criterion,timeup));
-
- if (same_context(dgram)) return;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- if (!strequal(work->work_group, myworkgroup))
- continue;
-
- if (win_election(work, version,criterion,timeup,name))
- {
- if (!work->RunningElection)
- {
- work->needelection = True;
- work->ElectionCount=0;
- work->mst_state = MST_POTENTIAL;
- }
- }
- else
- {
- work->needelection = False;
-
- if (work->RunningElection || AM_MASTER(work))
- {
- work->RunningElection = False;
- DEBUG(3,(">>> Lost election on %s %s <<<\n",
- work->work_group,inet_ntoa(d->bcast_ip)));
- if (AM_MASTER(work))
- {
- unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER);
- }
- }
- }
- }
-}
-
-
-/****************************************************************************
- checks whether a browser election is to be run on any workgroup
-
- this function really ought to return the time between election
- packets (which depends on whether samba intends to be a domain
- master or a master browser) in milliseconds.
-
- ***************************************************************************/
-BOOL check_elections(void)
-{
- struct subnet_record *d;
- BOOL run_any_election = False;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- struct work_record *work;
- for (work = d->workgrouplist; work; work = work->next)
- {
- run_any_election |= work->RunningElection;
-
- if (work->needelection && !work->RunningElection)
- {
- DEBUG(3,(">>> Starting election on %s %s <<<\n",
- work->work_group,inet_ntoa(d->bcast_ip)));
- work->ElectionCount = 0;
- work->RunningElection = True;
- work->needelection = False;
- }
- }
- }
- return run_any_election;
-}
-
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.1
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: nameelect.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-
- 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
- tridge's comments on first revision
-*/
-
-the module nameelect.c deals with initiating, winning, losing
-browsing elections, and checking if browsers are still around,
-and the consequences of getting involved in all this.
-
-an election packet can be received at any time, which will initiate
-an election. samba can also detect that there is no longer a
-master browser and will initiate an election.
-
-there is one way to become a master browser, but there are two
-ways to un-become a master browser. if you lose an election, you
-must stop being a master browser. if you fail to register your
-unique special browser names (either on your local subnet or with
-the WINS server) then you must stop being a master browser.
-
-this is a double fail-safe mechanism to ensure that there is only
-one master browser per workgroup per subnet (and one domain master
-browser - per domain (workgroup) per wide area network).
-
-(a wide area network is created when one or more servers on a
-broadcast-isolated subnet point to the same WINS server).
-
---------
-NOTE FROM TRIDGE:
-
-I'd say "domain master browser" not "WINS server" here. WINS doesn't
-have much to do with browsing, it is the WAN varient of name
-resolution. The name resolution and browsing functions of a netbios
-network are almost entirely separate. Both grew out of systems that
-could only be used on local networks.
-
-To adapt them to WANs, WINS was added for name resolution, and "domain
-master browsers" were added for browse lists. It would be perfectly
-possible to have a WINS server that doesn't even listen to UDP port
-138.
---------
-
-/*************************************************************************
- check_elections()
- *************************************************************************/
-
-this function returns True if samba is in the process of running an
-election on any of its interfaces. a better version of this function
-should return the time-out period in between election packets, in
-milliseconds.
-
-
-/*************************************************************************
- process_election()
- *************************************************************************/
-
-this function is responsible for dealing with the receipt of an election
-browse MAILSLOT packet.
-
-if samba is running an election, it checks the criteria in the packet
-received using win_election() to see if it has lost the election or if
-it should join in the election.
-
-if it loses the election, then it becomes a non-master.
-
-
-/*************************************************************************
- win_election()
- *************************************************************************/
-
-this function returns True if samba has won an election. the criteria
-in order of precedence are:
-
-the election version; the election criteria; the time since samba was
-started; and as a last resort, a name comparison is used.
-
-
-/*************************************************************************
- run_elections()
- *************************************************************************/
-
-this function is responsible for sending out election packets if
-samba is running in an election. once the fourth packet is sent
-out, it is assumed that we have won, and samba initiates becoming
-a master browser.
-
-(it looks like samba sends out an extra packet just to be sure...)
-
-
-/*************************************************************************
- become_nonmaster()
- *************************************************************************/
-
-this function is responsible for down-grading samba's status from
-either domain master to master browser or nothing, or master browser
-to nothing, depending on its current status.
-
-samba can become a non-master in three ways: by losing an election -
-see process_election(); by having one of its special browser names
-de-registered - see name_unregister_work(); by receiving and
-processing a browser reset packet - see process_reset_browser().
-
-when samba stops being a domain master, it must release its unique
-0x1b name. when samba stops being a master browser, it must release
-its unique 0x1d name.
-
-becoming non-master is done on a per-subnet basis.
-
-
-/*************************************************************************
- become_master()
- *************************************************************************/
-
-this function is responsible for slowly turning samba into a
-local master browser or a domain master browser.
-
-
-this is done in stages. note that this could take a while,
-particularly on a broadcast subnet, as we have to wait for
-the implicit registration of each name to be accepted.
-
-as each name is successfully registered, become_master() is
-called again via name_register_work(), in order to initiate
-the next stage (see dead_netbios_entry() - deals with implicit
-name registration and response_name_reg() - deals with explicit
-registration with a WINS server).
-
-stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
-stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
-stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
-stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
-
-note that this code still does not cope with the distinction
-between different types of nodes, particularly between M and P
-nodes (see rfc1001.txt). that will be developed later.
-
-
-/*************************************************************************
- name_register_work()
- *************************************************************************/
-
-this function is called when a NetBIOS name is successfully
-registered. it will add the registered name into samba's NetBIOS
-records.
-
-it has the additional responsibility that when samba is becoming
-a master browser, it must initiate the next stage in the progress
-towards becoming a master browser.
-
-implicit name registration is done through dead_netbios_entry()
-by time-out. explicit name registration is done through
-response_name_reg() with a WINS server.
-
-
-/*************************************************************************
- name_unregister_work()
- *************************************************************************/
-
-this function is called when there is an objection to a NetBIOS
-name being registered. this will always be done through a negative
-response to a name registration, whether it be by a host that
-already owns the unique name being registered on a subnet, or
-by a WINS server.
-
-the name being objected to must be removed from samba's records.
-
-it has the additional responsibility of checking whether samba is
-currently a master browser or not, and if so it should initiate
-becoming a non-master.
-
-
-
-/*************************************************************************
- send_election()
- *************************************************************************/
-
-this function is responsible for sending a browse mailslot
-datagram election packet (of type ANN_Election). it constructs
-the packet with all the relevant info needed to participate:
-election version; election criteria; time since startup and
-our name.
-
-this function can be used to ensure that initiate but lose an
-election by specifying a criteria and time up of zero. this
-is necessary if we are a master browser and we are about to
-go down (politely!) - see nmbd.c:sig_term().
-
-
-/*************************************************************************
- browser_gone()
- *************************************************************************/
-
-this function is responsible for dealing with the instance when
-the master browser we thought was present on a subnet is no longer
-responding.
-
-if it is samba's workgroup, and it's a local interface, samba
-detects that it can participate in an election on that interface
-and potentially become a master browser or domain master.
-
-if it's a local subnet and not one of samba's workgroups, then
-samba will force an election (which it is not obliged to do).
-remove_workgroup() will be expected to remove all references
-to this workgroup and the servers in it from the database.
-
-if it's a remote subnet and not one of samba's workgroups then
-no election is forced, and remove_workgroup() will be expected
-to remove all server entries from this workgroup _except_ those
-added from the lmhosts file. if there are entries added from
-the lmhosts file, then the workgroup entry will remain,
-otherwise it too will be removed.
-
-
-/*************************************************************************
- check_master_browser()
- *************************************************************************/
-
-this function is responsible for periodically checking whether
-master browsers that samba expects to be alive are alive. this
-is done every CHECK_TIME_MST_BROWSE minutes.
-
-for every workgroup record for which samba is not a master browser,
-on both local and remote interfaces, samba will initiate a
-broadcast query for a master browser on that subnet.
-
-(browser_gone() will be called to deal with the case where no
-response is received to the NAME_QUERY_MST_CHK initiated here.
-no action is required when a response _is_ received, however:
-see nameservresp.c:response_process() and dead_netbios_entry()
-for details)
-
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
-*/
-
-#include "includes.h"
-
-extern int ClientDGRAM;
-
-extern int DEBUGLEVEL;
-
-extern pstring myname;
-
-
-/****************************************************************************
- process a domain logon packet
- **************************************************************************/
-void process_logon_packet(struct packet_struct *p,char *buf,int len,
- char *mailslot)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- pstring my_name;
- fstring reply_name;
- BOOL add_slashes = False;
- pstring outbuf;
- int code,reply_code;
- char unknown_byte = 0;
- uint16 request_count = 0;
- uint16 token = 0;
-
- uint32 ntversion;
- uint16 lmnttoken;
- uint16 lm20token;
- uint32 allowableaccount; /* Control bits, i.e. 0x80 == workstation trust a/c */
- uint32 domainsidsize;
- uint16 requestcount;
- char *domainsid;
- char *getdc;
- char *uniuser; /* Unicode user name */
- pstring ascuser;
- char *unicomp; /* Unicode computer name */
- struct smb_passwd *smb_pass; /* To check if machine account exists */
-
- if (!lp_domain_logons())
- {
- DEBUG(3,("No domain logons\n"));
- return;
- }
-
- strcpy(my_name, myname);
- strupper(my_name);
-
- code = SVAL(buf,0);
- DEBUG(1,("namelogon from %s: %x\n", inet_ntoa(p->ip), code));
-
- switch (code)
- {
- case 0:
- {
- char *q = buf + 2;
- char *machine = q;
- char *user = skip_string(machine,1);
-
- getdc = skip_string(user,1);
- q = skip_string(getdc,1);
- unknown_byte = CVAL(q,0);
- request_count = SVAL(q,1);
- token = SVAL(q,3);
-
- reply_code = 0x6;
- strcpy(reply_name,my_name);
- add_slashes = True;
-
- DEBUG(3,("Domain login request from %s(%s) user=%s token=%x\n",
- machine,inet_ntoa(p->ip),user,token));
-
- q = outbuf;
- SSVAL(q, 0, 6); q += 2;
-
- strcpy(reply_name, "\\\\");
- strcat(reply_name, my_name);
- strcpy(q, reply_name); q = skip_string(q, 1); /* PDC name */
-
- SSVAL(q, 0, token); q += 2;
-
- dump_data(4, outbuf, PTR_DIFF(q, outbuf));
-
- send_mailslot_reply(True, getdc, ClientDGRAM,
- outbuf,PTR_DIFF(q,outbuf),
- dgram->dest_name.name,
- dgram->source_name.name,
- dgram->dest_name.name_type,
- dgram->source_name.name_type,
- p->ip, *iface_ip(p->ip));
- break;
- }
-
- case QUERYFORPDC:
- {
- char *q = buf + 2;
- char *machine = q;
-
- getdc = skip_string(machine,1);
- unicomp = skip_string(getdc,1);
-
- q = align2(unicomp, buf);
-
- q = skip_unicode_string(q, 1);
-
- ntversion = IVAL(q, 0); q += 4;
- lmnttoken = SVAL(q, 0); q += 2;
- lm20token = SVAL(q, 0); q += 2;
-
- /* construct reply */
-
- q = outbuf;
- SSVAL(q, 0, QUERYFORPDC_R); q += 2;
-
- strcpy(reply_name,my_name);
- strcpy(q, reply_name); q = skip_string(q, 1); /* PDC name */
-
- if (strcmp(mailslot, NT_LOGON_MAILSLOT)==0) {
- q = align2(q, buf);
-
- PutUniCode(q, my_name); /* PDC name */
- q = skip_unicode_string(q, 1);
- PutUniCode(q, lp_workgroup()); /* Domain name*/
- q = skip_unicode_string(q, 1);
-
- SIVAL(q, 0, ntversion); q += 4;
- SSVAL(q, 0, lmnttoken); q += 2;
- SSVAL(q, 0, lm20token); q += 2;
- }
-
- DEBUG(3,("GETDC request from %s(%s), reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
- machine,inet_ntoa(p->ip), reply_name, lp_workgroup(),
- QUERYFORPDC_R, (uint32)ntversion, (uint32)lmnttoken,
- (uint32)lm20token));
-
- dump_data(4, outbuf, PTR_DIFF(q, outbuf));
-
- send_mailslot_reply(True, getdc,ClientDGRAM,
- outbuf,PTR_DIFF(q,outbuf),
- dgram->dest_name.name,
- dgram->source_name.name,
- dgram->dest_name.name_type,
- dgram->source_name.name_type,
- p->ip, *iface_ip(p->ip));
- return;
- }
-
- case SAMLOGON:
- {
- char *q = buf + 2;
-
- requestcount = SVAL(q, 0); q += 2;
- unicomp = q;
- uniuser = skip_unicode_string(unicomp,1);
- getdc = skip_unicode_string(uniuser,1);
- q = skip_string(getdc,1);
- allowableaccount = IVAL(q, 0); q += 4;
- domainsidsize = IVAL(q, 0); q += 4;
- domainsid = q;
- q += domainsidsize + 3;
- ntversion = IVAL(q, 0); q += 4;
- lmnttoken = SVAL(q, 0); q += 2;
- lm20token = SVAL(q, 0); q += 2;
-
- DEBUG(3,("SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
-
- /*
- If MACHINE$ is in our password database then respond, else ignore.
- Let's ignore the SID.
- */
-
- strcpy(ascuser, unistr(uniuser));
- DEBUG(3,("SAMLOGON user %s\n", ascuser));
-
- strcpy(reply_name,"\\\\"); /* Here it wants \\LOGONSERVER */
- strcpy(reply_name+2,my_name);
-
- smb_pass = get_smbpwd_entry(ascuser, 0);
-
- if(!smb_pass)
- {
- DEBUG(3,("SAMLOGON request from %s(%s) for %s, not in password file\n",
- unistr(unicomp),inet_ntoa(p->ip), ascuser));
- return;
- }
- else
- {
- DEBUG(3,("SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
- unistr(unicomp),inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(),
- SAMLOGON_R ,lmnttoken));
- }
-
- /* construct reply */
-
- q = outbuf;
- SSVAL(q, 0, SAMLOGON_R); q += 2;
-
- PutUniCode(q, reply_name); q = skip_unicode_string(q, 1);
- unistrcpy(q, uniuser); q = skip_unicode_string(q, 1); /* User name (workstation trust account) */
- PutUniCode(q, lp_workgroup()); q = skip_unicode_string(q, 1); /* Domain name. */
-
- SIVAL(q, 0, ntversion); q += 4;
- SSVAL(q, 0, lmnttoken); q += 2;
- SSVAL(q, 0, lm20token); q += 2;
-
- dump_data(4, outbuf, PTR_DIFF(q, outbuf));
-
- send_mailslot_reply(True, getdc,ClientDGRAM,
- outbuf,PTR_DIFF(q,outbuf),
- dgram->dest_name.name,
- dgram->source_name.name,
- dgram->dest_name.name_type,
- dgram->source_name.name_type,
- p->ip, *iface_ip(p->ip));
- break;
- }
-
- default:
- {
- DEBUG(3,("Unknown domain request %d\n",code));
- return;
- }
- }
-
-}
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.0
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: namelogon.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-*/
-
-this module deals with the first stage of domain logons. there is much
-more work to be done on this: it's all totally undocumented.
-
-
-/*************************************************************************
- process_logon_packet()
- *************************************************************************/
-
-a function that processes logon packets (the most helpful comment yet :-).
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-extern int ClientDGRAM;
-
-extern int DEBUGLEVEL;
-
-extern int num_response_packets;
-
-BOOL CanRecurse = True;
-extern pstring scope;
-extern struct in_addr wins_ip;
-extern struct in_addr loopback_ip;
-
-static uint16 name_trn_id=0;
-
-
-/***************************************************************************
- updates the unique transaction identifier
- **************************************************************************/
-void debug_browse_data(char *outbuf, int len)
-{
- int i,j;
- for (i = 0; i < len; i+= 16)
- {
- DEBUG(4, ("%3x char ", i));
-
- for (j = 0; j < 16; j++)
- {
- unsigned char x = outbuf[i+j];
- if (x < 32 || x > 127) x = '.';
-
- if (i+j >= len) break;
- DEBUG(4, ("%c", x));
- }
-
- DEBUG(4, (" hex ", i));
-
- for (j = 0; j < 16; j++)
- {
- if (i+j >= len) break;
- DEBUG(4, (" %02x", (unsigned char)outbuf[i+j]));
- }
-
- DEBUG(4, ("\n"));
- }
-
-}
-
-
-/***************************************************************************
- updates the unique transaction identifier
- **************************************************************************/
-static void update_name_trn_id(void)
-{
- if (!name_trn_id)
- {
- name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100);
- }
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-}
-
-
-/****************************************************************************
- initiate a netbios packet
- ****************************************************************************/
-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)
-{
- struct packet_struct p;
- struct nmb_packet *nmb = &p.packet.nmb;
- struct res_rec additional_rec;
- 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; }
- if (quest_type == NMB_REG_REFRESH ) { packet_type = "nmb_reg_refresh"; opcode = 9; }
- if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; }
-
- DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
- packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
-
- if (opcode == -1) return;
-
- bzero((char *)&p,sizeof(p));
-
- if (*id == 0xffff) {
- update_name_trn_id();
- *id = name_trn_id; /* allow resending with same id */
- }
-
- nmb->header.name_trn_id = *id;
- nmb->header.opcode = opcode;
- nmb->header.response = False;
-
- nmb->header.nm_flags.bcast = bcast;
- nmb->header.nm_flags.recursion_available = False;
- nmb->header.nm_flags.recursion_desired = recurse;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = False;
-
- nmb->header.rcode = 0;
- nmb->header.qdcount = 1;
- nmb->header.ancount = 0;
- nmb->header.nscount = 0;
- nmb->header.arcount = (quest_type==NMB_REG ||
- quest_type==NMB_REL ||
- quest_type==NMB_REG_REFRESH) ? 1 : 0;
-
- make_nmb_name(&nmb->question.question_name,name,name_type,scope);
-
- nmb->question.question_type = quest_type == NMB_STATUS ? 0x21 : 0x20;
- nmb->question.question_class = 0x1;
-
- if (quest_type == NMB_REG ||
- quest_type == NMB_REG_REFRESH ||
- quest_type == NMB_REL)
- {
- nmb->additional = &additional_rec;
- bzero((char *)nmb->additional,sizeof(*nmb->additional));
-
- nmb->additional->rr_name = nmb->question.question_name;
- nmb->additional->rr_type = 0x20;
- nmb->additional->rr_class = 0x1;
-
- if (quest_type == NMB_REG || quest_type == NMB_REG_REFRESH)
- nmb->additional->ttl = lp_max_ttl();
- else
- nmb->additional->ttl = 0;
-
- nmb->additional->rdlength = 6;
- nmb->additional->rdata[0] = nb_flags;
- putip(&nmb->additional->rdata[2],(char *)iface_ip(to_ip));
- }
-
- p.ip = to_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
- p.locked = False;
-
- debug_nmb_packet(&p);
-
- if (!send_packet(&p)) {
- DEBUG(3,("send_packet to %s %d failed\n",inet_ntoa(p.ip),p.port));
- *id = 0xffff;
- }
-
- return;
-}
-
-
-/****************************************************************************
- reply to a netbios name packet. see rfc1002.txt
- ****************************************************************************/
-void reply_netbios_packet(struct packet_struct *p1,int trn_id,
- int rcode, int rcv_code, int opcode,
- BOOL recursion_available,
- BOOL recursion_desired,
- 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;
-
- switch (rcv_code)
- {
- case NMB_STATUS:
- {
- packet_type = "nmb_status";
- break;
- }
- case NMB_QUERY:
- {
- packet_type = "nmb_query";
- break;
- }
- case NMB_REG:
- {
- packet_type = "nmb_reg";
- break;
- }
- case NMB_REL:
- {
- packet_type = "nmb_rel";
- break;
- }
- case NMB_WAIT_ACK:
- {
- packet_type = "nmb_wack";
- break;
- }
- default:
- {
- DEBUG(1,("replying netbios packet: %s %s %s\n",
- packet_type, namestr(rr_name), inet_ntoa(p.ip)));
-
- return;
- }
- }
-
- DEBUG(4,("replying netbios packet: %s %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 = recursion_available;
- nmb->header.nm_flags.recursion_desired = recursion_desired;
- 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 = rcode;
-
- 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);
-}
-
-
-/*******************************************************************
- the global packet linked-list. incoming entries are added to the
- end of this list. it is supposed to remain fairly short so we
- won't bother with an end pointer.
- ******************************************************************/
-static struct packet_struct *packet_queue = NULL;
-
-/*******************************************************************
- queue a packet into the packet queue
- ******************************************************************/
-void queue_packet(struct packet_struct *packet)
-{
- struct packet_struct *p;
-
- if (!packet_queue) {
- packet->prev = NULL;
- packet->next = NULL;
- packet_queue = packet;
- return;
- }
-
- /* find the bottom */
- for (p=packet_queue;p->next;p=p->next) ;
-
- p->next = packet;
- packet->next = NULL;
- packet->prev = p;
-}
-
-/****************************************************************************
- determine if a packet is for us. Note that to have any chance of
- being efficient we need to drop as many packets as possible at this
- stage as subsequent processing is expensive.
-
- We also must make absolutely sure we don't tread on another machines
- property by answering a packet that is not for us.
- ****************************************************************************/
-static BOOL listening(struct packet_struct *p,struct nmb_name *n)
-{
- struct subnet_record *d;
- struct name_record *n1 = NULL;
-
- if((d = find_subnet_all(p->ip)) != NULL)
- n1 = find_name_on_subnet(d, n, FIND_SELF_NAME);
-
- return (n1 != NULL);
-}
-
-
-/****************************************************************************
- process udp 138 datagrams
- ****************************************************************************/
-static void process_dgram(struct packet_struct *p)
-{
- char *buf;
- char *buf2;
- int len;
- struct dgram_packet *dgram = &p->packet.dgram;
-
- /* if we aren't listening to the destination name then ignore the packet */
- if (!listening(p,&dgram->dest_name))
- {
- DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s(%x) from %s\n",
- dgram->dest_name.name, dgram->dest_name.name_type, inet_ntoa(p->ip)));
- return;
- }
-
- if (dgram->header.msg_type != 0x10 &&
- dgram->header.msg_type != 0x11 &&
- dgram->header.msg_type != 0x12)
- {
- /* don't process error packets etc yet */
- DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s(%d) from %s as it is \
- an error packet of type %x\n",
- dgram->dest_name.name, dgram->dest_name.name_type,
- inet_ntoa(p->ip), dgram->header.msg_type));
- return;
- }
-
- buf = &dgram->data[0];
- buf -= 4; /* XXXX for the pseudo tcp length -
- someday I need to get rid of this */
-
- if (CVAL(buf,smb_com) != SMBtrans) return;
-
- len = SVAL(buf,smb_vwv11);
- buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
-
- DEBUG(4,("process_dgram: datagram from %s to %s(%s)for %s of type %d len=%d\n",
- namestr(&dgram->source_name),namestr(&dgram->dest_name),
- inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
-
-
- if (len <= 0) return;
-
- /* datagram packet received for the browser mailslot */
- if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
- process_browse_packet(p,buf2,len);
- return;
- }
-
- /* datagram packet received for the domain log on mailslot */
- if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
- process_logon_packet(p,buf2,len, NET_LOGON_MAILSLOT);
- return;
- }
-
- /* datagram packet received for the NT domain log on mailslot */
- if (strequal(smb_buf(buf),NT_LOGON_MAILSLOT)) {
- process_logon_packet(p,buf2,len, NT_LOGON_MAILSLOT);
- return;
- }
-}
-
-/****************************************************************************
- process a nmb packet
- ****************************************************************************/
-static void process_nmb(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
-
- debug_nmb_packet(p);
-
- switch (nmb->header.opcode)
- {
- case 8: /* what is this?? */
- case NMB_REG:
- case NMB_REG_REFRESH:
- {
- if (nmb->header.response)
- {
- if (nmb->header.ancount ==0) break;
- response_netbios_packet(p); /* response to registration dealt
- with here */
- }
- else
- {
- if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
- reply_name_reg(p);
- }
- break;
- }
-
- case 0:
- {
- if (nmb->header.response)
- {
- switch (nmb->question.question_type)
- {
- case 0x0:
- {
- response_netbios_packet(p);
- break;
- }
- }
- return;
- }
- else if (nmb->header.qdcount>0)
- {
- switch (nmb->question.question_type)
- {
- case NMB_QUERY:
- {
- reply_name_query(p);
- break;
- }
- case NMB_STATUS:
- {
- reply_name_status(p);
- break;
- }
- }
- return;
- }
- break;
- }
-
- case NMB_REL:
- {
- if (nmb->header.response)
- {
- if (nmb->header.ancount ==0) break;
- response_netbios_packet(p); /* response to release dealt
- with here */
- }
- else
- {
- if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
- reply_name_release(p);
- }
- break;
- }
- }
-}
-
-
-/*******************************************************************
- run elements off the packet queue till its empty
- ******************************************************************/
-void run_packet_queue()
-{
- struct packet_struct *p;
-
- while ((p=packet_queue)) {
- packet_queue = p->next;
- if (packet_queue) packet_queue->prev = NULL;
- p->next = p->prev = NULL;
-
- switch (p->packet_type) {
- case NMB_PACKET:
- process_nmb(p);
- break;
-
- case DGRAM_PACKET:
- process_dgram(p);
- break;
- }
- free_packet(p);
- }
-}
-
-
-/****************************************************************************
- Create an fd_set containing all the sockets in the subnet structures,
- plus the broadcast sockets.
- ***************************************************************************/
-static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number)
-{
- int *sock_array = NULL;
- struct subnet_record *d = NULL;
- int count = 0;
- int num = 0;
- fd_set *pset = (fd_set *)malloc(sizeof(fd_set));
-
- if(pset == NULL)
- {
- DEBUG(0,("create_listen_fdset: malloc fail !\n"));
- return True;
- }
-
- /* Check that we can add all the fd's we need. */
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- count++;
-
- if((count*2) + 2 > FD_SETSIZE)
- {
- DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
-only use %d.\n", (count*2) + 2, FD_SETSIZE));
- return True;
- }
-
- if((sock_array = (int *)malloc(((count*2) + 2)*sizeof(int))) == NULL)
- {
- DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
- return True;
- }
-
- FD_ZERO(pset);
-
- /* Add in the broadcast socket on 137. */
- FD_SET(ClientNMB,pset);
- sock_array[num++] = ClientNMB;
-
- /* Add in the 137 sockets on all the interfaces. */
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- FD_SET(d->nmb_sock,pset);
- sock_array[num++] = d->nmb_sock;
- }
-
- /* Add in the broadcast socket on 138. */
- FD_SET(ClientDGRAM,pset);
- sock_array[num++] = ClientDGRAM;
-
- /* Add in the 138 sockets on all the interfaces. */
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- FD_SET(d->dgram_sock,pset);
- sock_array[num++] = d->dgram_sock;
- }
-
- *listen_number = (count*2) + 2;
- *ppset = pset;
- *psock_array = sock_array;
-
- return False;
-}
-
-/****************************************************************************
- listens for NMB or DGRAM packets, and queues them
- ***************************************************************************/
-BOOL listen_for_packets(BOOL run_election)
-{
- static fd_set *listen_set = NULL;
- static int listen_number = 0;
- static int *sock_array = NULL;
-
- fd_set fds;
- int selrtn;
- struct timeval timeout;
-#ifndef SYNC_DNS
- int dns_fd;
-#endif
-
- if(listen_set == NULL)
- {
- if(create_listen_fdset(&listen_set, &sock_array, &listen_number))
- {
- DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
- return True;
- }
- }
-
- memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
-
-#ifndef SYNC_DNS
- dns_fd = asyncdns_fd();
- if (dns_fd != -1) {
- FD_SET(dns_fd, &fds);
- }
-#endif
-
-
- /* during elections and when expecting a netbios response packet we
- need to send election packets at tighter intervals
-
- ideally 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||num_response_packets) ? 1:NMBD_SELECT_LOOP;
- timeout.tv_usec = 0;
-
- /* We can only take term signals when we are in the select. */
- BlockSignals(False, SIGTERM);
- selrtn = sys_select(&fds,&timeout);
- BlockSignals(True, SIGTERM);
-
- if(selrtn > 0)
- {
- int i;
-
-#ifndef SYNC_DNS
- if (dns_fd != -1 && FD_ISSET(dns_fd,&fds)) {
- run_dns_queue();
- }
-#endif
-
- for(i = 0; i < listen_number; i++)
- {
- if(i < (listen_number/2))
- {
- /* Processing a 137 socket. */
- if (FD_ISSET(sock_array[i],&fds))
- {
- struct packet_struct *packet = read_packet(sock_array[i], NMB_PACKET);
- if (packet)
- {
- /*
- * If we got a packet on the broadcast socket and interfaces
- * only is set then check it came from one of our local nets.
- */
- if(lp_bind_interfaces_only() && (sock_array[i] == ClientNMB) &&
- (!is_local_net(packet->ip)))
- {
- DEBUG(7,("discarding nmb packet sent to broadcast socket from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- }
- else if ((ip_equal(loopback_ip, packet->ip) ||
- ismyip(packet->ip)) && packet->port == NMB_PORT)
- {
- DEBUG(7,("discarding own packet from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- }
- else
- {
- queue_packet(packet);
- }
- }
- }
- }
- else
- {
- /* Processing a 138 socket. */
-
- if (FD_ISSET(sock_array[i],&fds))
- {
- struct packet_struct *packet = read_packet(sock_array[i], DGRAM_PACKET);
- if (packet)
- {
- /*
- * If we got a packet on the broadcast socket and interfaces
- * only is set then check it came from one of our local nets.
- */
- if(lp_bind_interfaces_only() && (sock_array[i] == ClientDGRAM) &&
- (!is_local_net(packet->ip)))
- {
- DEBUG(7,("discarding dgram packet sent to broadcast socket from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- }
- else if ((ip_equal(loopback_ip, packet->ip) ||
- ismyip(packet->ip)) && packet->port == DGRAM_PORT)
- {
- DEBUG(7,("discarding own packet from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- }
- else
- {
- queue_packet(packet);
- }
- }
- }
- } /* end processing 138 socket. */
- } /* end for */
- } /* end if selret > 0 */
- return False;
-}
-
-
-
-/****************************************************************************
- construct and send a netbios DGRAM
-
- Note that this currently sends all answers to port 138. thats the
- wrong things to do! I should send to the requestors port. XXX
- **************************************************************************/
-BOOL send_mailslot_reply(BOOL unique, 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)
-{
- struct packet_struct p;
- struct dgram_packet *dgram = &p.packet.dgram;
- 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));
-
- update_name_trn_id();
-
- /* DIRECT GROUP or UNIQUE datagram */
- dgram->header.msg_type = unique ? 0x10 : 0x11;
- dgram->header.flags.node_type = M_NODE;
- dgram->header.flags.first = True;
- dgram->header.flags.more = False;
- dgram->header.dgm_id = name_trn_id;
- dgram->header.source_ip = src_ip;
- dgram->header.source_port = DGRAM_PORT;
- dgram->header.dgm_length = 0; /* let build_dgram() handle this */
- dgram->header.packet_offset = 0;
-
- make_nmb_name(&dgram->source_name,srcname,src_type,scope);
- make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
-
- ptr = &dgram->data[0];
-
- /* now setup the smb part */
- ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
- memcpy(tmp,ptr,4);
- set_message(ptr,17,17 + len,True);
- memcpy(ptr,tmp,4);
-
- CVAL(ptr,smb_com) = SMBtrans;
- SSVAL(ptr,smb_vwv1,len);
- SSVAL(ptr,smb_vwv11,len);
- SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
- SSVAL(ptr,smb_vwv13,3);
- SSVAL(ptr,smb_vwv14,1);
- SSVAL(ptr,smb_vwv15,1);
- SSVAL(ptr,smb_vwv16,2);
- p2 = smb_buf(ptr);
- strcpy(p2,mailslot);
- p2 = skip_string(p2,1);
-
- memcpy(p2,buf,len);
- p2 += len;
-
- dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
-
- p.ip = dest_ip;
- p.port = DGRAM_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = DGRAM_PACKET;
-
- DEBUG(4,("send mailslot %s from %s %s", mailslot,
- inet_ntoa(src_ip),namestr(&dgram->source_name)));
- DEBUG(4,("to %s %s\n", inet_ntoa(dest_ip),namestr(&dgram->dest_name)));
-
- return(send_packet(&p));
-}
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.0
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: namepacket.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-*/
-
-this module deals with packets: sending, receiving, queueing
-and some basic interpretation (e.g it excludes datagram
-error packets at the moment).
-
-the packet queueing mechanism was originally introduced when
-samba dealt with responses by sending a packet, receiving
-packets and queueing all packets that didn't match up with
-the response expected. this is fine in a single-thread
-environment, but samba now deals with response packets by
-queueing the responses. to some extent, therefore, this
-queue_packet mechanism is redundant.
-
-
-/*************************************************************************
- send_mailslot_reply()
- *************************************************************************/
-
-this function is responsible for sending a MAILSLOT packet.
-
-it will _not_ send packets to the pseudo WINS subnet's address of
-255.255.255.255: this would be disastrous.
-
-each packet sent out has a unique transaction identifier. this is done
-so that responses can be matched later with the original purpose for
-the packet being sent out in the first place.
-
-
-/*************************************************************************
- listen_for_packets()
- *************************************************************************/
-
-this function is responsible for reading NMB and DGRAM packets, and then
-queueing them. it will normally time-out for NMBD_SELECT_LOOP seconds, but
-if there is an election currently running or we are expecting a response
-then this time is reduced to 1 second.
-
-note: the time-out period needs refining to the millisecond level.
-
-
-/*************************************************************************
- queue_packet()
- *************************************************************************/
-
-this function is responsible for queueing any NMB and DGRAM packets passed
-to it. these packets will be removed from the queue in run_packet_queue().
-
-
-/*************************************************************************
- run_packet_queue()
- *************************************************************************/
-
-this function is responsible for taking a packet off the queue,
-identifying whether it is an NMB or a DGRAM packet, processing
-it accordingly and deleting it. this process continues until
-there are no more packets on the queue.
-
-
-/*************************************************************************
- process_nmb()
- *************************************************************************/
-
-this function receives a packet identified as a netbios packet.
-it further identifies whether it is a response or a query packet.
-by identifying the type of packet (name registration, query etc)
-process_nmb() will call the appropriate function to deal with the
-type of packet received.
-
-
-/*************************************************************************
- process_dgram()
- *************************************************************************/
-
-this function is responsible for identifying whether the datagram
-packet received is a browser packet or a domain logon packet. it
-also does some filtering of certain types of packets (e.g it
-filters out error packets).
-
-
-/*************************************************************************
- reply_netbios_packet()
- *************************************************************************/
-
-this function is responsible for sending a reply to another NetBIOS
-packet from another host. it can be used to send a reply to a name
-registration, name release, name query or name status request.
-
-the reply can be either a positive or a negative one.
-
-
-/*************************************************************************
- initiate_netbios_packet()
- *************************************************************************/
-
-this function is responsible for construction a netbios packet and sending
-it. if the packet has not had a unique transaction id allocated to it,
-then initiate_netbios_packet() will give it one.
-
-
-/*************************************************************************
- update_name_trn_id()
- *************************************************************************/
-
-this function is responsible for allocating unique transaction identifiers
-for each new packet sent on the network.
-
-
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.0
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: namequery.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-*/
-
-this module contains non-threaded versions of name status and name
-query functions. if a multi-threaded nmbd was to be written, these
-functions would be the starting point.
-
-at the moment, the expected response queueing system is used to
-replace these functions without needing to multi-thread nmbd.
-
-these functions are used in smbclient and nmblookup at present to
-avoid having the vast quantities of complex and unused code needed
-to support even a simple name query (or providing stubs for the
-unused side of these functions).
-
-there is a down-side to these functions, which is all microsoft's
-fault. microsoft machines always always reply to queries on the
-priveleged ports, rather than following the usual tcp/ip mechanism
-of replying on the client's port (the exception to this i am led
-to believe is windows nt 3.50).
-
-as a result of this, in order to receive a response to a name
-query from a microsoft machine, we must be able to listen on
-the priveleged netbios name server ports. this is simply not
-possible with some versions of unix, unless you have root access.
-
-it is also not possible if you run smbclient or nmblookup on an
-interface that already has been claimed by the netbios name server
-daemon nmbd.
-
-all in all, i wish that microsoft would fix this.
-
-a solution does exist: nmbd _does_ actually reply on the client's
-port, so if smbclient and nmblookup were to use nmbd as a proxy
-forwarder of queries (or to use samba's WINS capabilities) then
-a query could be made without needing access to the priveleged
-ports. in order to do this properly, samba must implement secured
-netbios name server functionality (see rfc1001.txt 15.1.6).
-(lkcl 01aug96: samba now supports secured name registration)
-
-/*************************************************************************
- name_query()
- *************************************************************************/
-
-
-
-/*************************************************************************
- name_status()
- *************************************************************************/
-
-
-
-/*************************************************************************
- _interpret_node_status()
- *************************************************************************/
-
-
-this is a older version of interpret_node_status().
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios library routines
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Module name: nameresp.c
-
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-
-extern struct subnet_record *subnetlist;
-
-extern int DEBUGLEVEL;
-
-extern pstring scope;
-extern struct in_addr ipzero;
-extern struct in_addr wins_ip;
-
-
-/***************************************************************************
- deals with an entry before it dies
- **************************************************************************/
-static void dead_netbios_entry(struct subnet_record *d,
- struct response_record *n)
-{
- DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
- inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs));
-
- debug_state_type(n->state);
-
- switch (n->state)
- {
- case NAME_QUERY_CONFIRM:
- {
- if (!lp_wins_support()) return; /* only if we're a WINS server */
-
- if (n->num_msgs == 0)
- {
- /* oops. name query had no response. check that the name is
- unique and then remove it from our WINS database */
-
- /* IMPORTANT: see query_refresh_names() */
-
- if ((!NAME_GROUP(n->nb_flags)))
- {
- struct subnet_record *d1 = wins_client_subnet;
- if (d1)
- {
- /* remove the name that had been registered with us,
- and we're now getting no response when challenging.
- see rfc1001.txt 15.5.2
- */
- remove_netbios_name(d1, n->name.name, n->name.name_type, REGISTER);
- }
- }
- }
- break;
- }
-
- case NAME_QUERY_MST_CHK:
- {
- /* if no response received, the master browser must have gone
- down on that subnet, without telling anyone. */
-
- /* IMPORTANT: see response_netbios_packet() */
-
- if (n->num_msgs == 0)
- browser_gone(n->name.name, n->send_ip);
- break;
- }
-
- case NAME_RELEASE:
- {
- /* if no response received, it must be OK for us to release the
- name. nobody objected (including a potentially dead or deaf
- WINS server) */
-
- /* IMPORTANT: see response_name_release() */
-
- if (ismyip(n->send_ip))
- {
- name_unregister_work(d,n->name.name,n->name.name_type);
- }
- if (!n->bcast && n->num_msgs == 0)
- {
- DEBUG(0,("WINS server did not respond to name release!\n"));
- /* XXXX whoops. we have problems. must deal with this */
- }
- break;
- }
-
- case NAME_REGISTER_CHALLENGE:
- {
- /* name challenge: no reply. we can reply to the person that
- wanted the unique name and tell them that they can have it
- */
-
- add_name_respond(d,n->fd,d->myip, n->reply_id ,&n->name,
- n->nb_flags, GET_TTL(0),
- n->reply_to_ip, True, n->reply_to_ip);
- break;
- }
-
- case NAME_REGISTER:
- {
- /* if no response received, and we are using a broadcast registration
- method, it must be OK for us to register the name: nobody objected
- on that subnet. if we are using a WINS server, then the WINS
- server must be dead or deaf.
- */
- if (n->num_msgs == 0)
- {
- if (n->bcast)
- {
- /* broadcast method: implicit acceptance of the name registration
- by not receiving any objections. */
-
- /* IMPORTANT: see response_name_reg() */
-
- name_register_work(d,n->name.name,n->name.name_type,
- n->nb_flags, n->ttl, n->reply_to_ip, n->bcast);
- }
- else
- {
- /* received no response. rfc1001.txt states that after retrying,
- we should assume the WINS server is dead, and fall back to
- broadcasting (see bits about M nodes: can't find any right
- now) */
-
- DEBUG(1,("WINS server did not respond to name registration!\n"));
- /* XXXX whoops. we have problems. must deal with this */
- }
- }
- break;
- }
-
- case NAME_QUERY_DOMAIN:
- {
- /* if no response was received, there is no domain controller for
- this DOMAIN registered within WINS. it's ok for us to register
- the DOMAIN<1b> name.
- */
-
- if (n->num_msgs == 0)
- {
- struct work_record *work = find_workgroupstruct(d,n->name.name,False);
- if (work && d)
- {
- become_domain_master(d,work);
- }
- }
- else
- {
- DEBUG(1, ("nmbd configured as domain master and one already exists\n"));
- }
- break;
- }
-
- default:
- {
- /* nothing to do but delete the dead expected-response structure */
- /* this is normal. */
- break;
- }
- }
-}
-
-
-/*******************************************************************
- 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(time_t t)
-{
- struct subnet_record *d;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- struct response_record *n, *nextn;
-
- for (n = d->responselist; n; n = nextn)
- {
- nextn = n->next;
-
- if (n->repeat_time <= t)
- {
- if (n->repeat_count > 0)
- {
- /* resend the entry */
- initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
- n->name.name, n->name.name_type,
- n->nb_flags, n->bcast, n->recurse, n->send_ip);
-
- n->repeat_time += n->repeat_interval; /* XXXX ms needed */
- n->repeat_count--;
-
- }
- else
- {
- DEBUG(4,("timeout response %d for %s %s\n",
- n->response_id, namestr(&n->name),
- inet_ntoa(n->send_ip)));
-
- dead_netbios_entry(d,n); /* process the non-response */
- remove_response_record(d,n); /* remove the non-response */
-
- continue;
- }
- }
- }
- }
-}
-
-
-/****************************************************************************
- wrapper function to override a broadcast message and send it to the WINS
- name server instead, if it exists. if wins is false, and there has been no
- WINS server specified, the packet will NOT be sent.
- ****************************************************************************/
-struct response_record *queue_netbios_pkt_wins(
- int fd,int quest_type,enum state_type state,
- char *name,int name_type,int nb_flags, time_t ttl,
- int server_type, char *my_name, char *my_comment,
- struct in_addr send_ip, struct in_addr reply_to_ip)
-{
- /* XXXX note: please see rfc1001.txt section 10 for details on this
- function: it is currently inappropriate to use this - it will do
- for now - once there is a clarification of B, M and P nodes and
- which one samba is supposed to be
- */
-
- if ((!lp_wins_support()) && (*lp_wins_server()))
- {
- /* samba is not a WINS server, and we are using a WINS server */
- struct in_addr real_wins_ip;
- real_wins_ip = *interpret_addr2(lp_wins_server());
-
- if (!zero_ip(real_wins_ip))
- {
- send_ip = real_wins_ip;
- }
- else
- {
- /* oops. smb.conf's wins server parameter MUST be a host_name
- or an ip_address. */
- DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
- }
- }
-
- if (zero_ip(send_ip)) return NULL;
-
- return queue_netbios_packet(wins_client_subnet,fd, quest_type, state,
- name, name_type, nb_flags, ttl,
- server_type,my_name,my_comment,
- False, True, send_ip, reply_to_ip, 0);
-}
-
-
-/****************************************************************************
- initiate a netbios name query to find someone's or someones' IP
- this is intended to be used (not exclusively) for broadcasting to
- master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
- complete lists across a wide area network
- ****************************************************************************/
-struct response_record *queue_netbios_packet(struct subnet_record *d,
- int fd,int quest_type,enum state_type state,char *name,
- int name_type,int nb_flags, time_t ttl,
- int server_type, char *my_name, char *my_comment,
- BOOL bcast,BOOL recurse,
- struct in_addr send_ip, struct in_addr reply_to_ip,
- int reply_id)
-{
- struct response_record *n;
- uint16 id = 0xffff;
-
- /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
- if (ip_equal(wins_ip, send_ip)) return NULL;
-
- initiate_netbios_packet(&id, fd, quest_type, name, name_type,
- nb_flags, bcast, recurse, send_ip);
-
- if (id == 0xffff) {
- DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip)));
- return NULL;
- }
-
- if ((n = make_response_queue_record(state,id,fd,
- quest_type,name,name_type,nb_flags,ttl,
- server_type,my_name, my_comment,
- bcast,recurse,send_ip,reply_to_ip,
- reply_id)))
- {
- add_response_record(d,n);
- return n;
- }
- return NULL;
-}
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.0
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: nameresp.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-*/
-
-the netbios expected response code is a key part of samba's NetBIOS
-handling capabilities. it allows samba to carry on dealing with
-other things while expecting a response from one or more hosts.
-
-this allows samba to simultaneously deal with registering its names
-with another WINS server, register its names on its local subnets,
-query any hosts that have registered with samba in its capacity as
-a WINS server, and at a later date it will be also be able handle
-END-NODE CHALLENGES (see rfc1001.txt 15.2.2.2 and 15.2.2.3 - secured
-NBNS functionality).
-
-all at once!
-
-when a netbios packet is sent out by samba and it expects a response,
-a record of all the relevant information is kept (most importantly,
-the unique transaction id associated which will come back to us in
-a response packet is recorded, and also recorded is the reason that
-the original packet was sent out by samba in the first place!).
-
-if a response is received, then the unique transaction identifier
-returned in the response packet is searched for in the expected
-response records. the record indicates why the initial request was
-made (and therefore the type of response can be verified) and
-appropriate action can be taken.
-
-when no responses, after a number of retries, are not received, then
-samba may take appropriate action. this is a crucial part of samba's
-operation: for a key number of NetBIOS operations, no response is an
-implicit positive response.
-
-module nameresp deals with the initial transmission, re-transmission
-and time-out of netbios response records.
-
-module namedbresp deals with the maintenance of the list of expected
-responses - creation, finding and removal.
-
-
-/*************************************************************************
- queue_netbios_packet()
- *************************************************************************/
-
-this function is responsible for sending out a netbios packet, and then
-making a record of the information that was sent out. a response will
-be expected later (or not, as the case may be).
-
-if a response is received, response_netbios_packet() will deal with it.
-otherwise, it will be dealt with in expire_netbios_response_entries().
-
-
-/*************************************************************************
- queue_netbios_pkt_wins()
- *************************************************************************/
-
-this function is a wrapper around queue_netbios_packet(). there is
-some confusion about B, M and P nodes (see rfc1001.txt section 10) -
-confusion introduced by luke :-) - which needs sorting out.
-
-for example, rfc1001.txt 15.2.3 - an M node must attempt to register a
-name first as a B node, then attempt to register as an M node. negative
-responses on either of these attempts is a failure to register the
-name.
-
-this is NOT the case with a P node.
-
-
-/*************************************************************************
- expire_netbios_response_entries()
- *************************************************************************/
-
-this function is responsible for dealing with queued response records
-that have not received a response packet matching their unique
-transaction id.
-
-if the retry count for any record is non-zero, and its time-out period
-has expired, the retry count is reduced, the time-out period is stepped
-forward and the packet is re-transmitted (from the information stored
-in the queued response record) with the same unique transaction id of
-the initial attempt at soliciting a response.
-
-if the retry count is zero, then the packet is assumed to have expired.
-dead_netbios_entry() is called to deal with the possibility of an error
-or a problem (or in certain instances, no answer is an implicit
-positive response!).
-
-the expected response record is then deleted, and the number of expected
-responses reduced. when this count gets to zero, listen_for_packets()
-will no longer time-out for 1 second on account of expecting response
-packets.
-
-
-/*************************************************************************
- dead_netbios_entry()
- *************************************************************************/
-
-this function is responsible for dealing with the case when a NetBIOS
-response to a packet sent out by samba was not received. for certain
-transactions, this may be normal. for others, under certain conditions
-it may constitute either an error or a problem with or failure of one
-or more hosts.
-
-- NAME_QUERY_CONFIRM
-
-when a samba 'state' of type NAME_QUERY_CONFIRM is sent, a response
-may or may not be forthcoming. if no response is received to a unique
-name, then the record is removed from samba's WINS database. non-unique
-names are simply expected to die off on a time-to-live basis (see
-rfc1001.txt 15.1.3.4)
-
-query_refresh_names() issues this samba 'state'
-response_name_query_sync() deals with responses to NAME_QUERY_CONFIRM.
-
-- NAME_QUERY_MST_CHK
-
-when a samba 'state' of type NAME_QUERY_MST_CHK is sent, and a response
-is not received, this implies that a master browser will have failed.
-remedial action may need to be taken, for example if samba is a member
-of that workgroup and it is also a potential master browser it could
-force an election.
-
-check_master_browser() issues this samba 'state'.
-response_process() does nothing if a response is received. this is normal.
-
-- NAME_RELEASE
-
-when a samba 'state' of type NAME_RELEASE is sent, and a response is
-not received, it is assumed to be acceptable to release the name. if the
-original response was sent to another WINS server, then that WINS server
-may be inaccessible or may have failed. if so, then at a later date
-samba should take this into account (see rfc1001.txt 10.3).
-
-remove_name_entry() issues this samba 'state'
-response_name_rel() deals with responses to NAME_RELEASE.
-
-- NAME_REGISTER
-
-when a samba 'state' of type NAME_REGISTER is sent, and a response is
-not received, if the registration was done by broadcast, it is assumed
-that there are no objections to the registration of this name, and samba
-adds the name to the appropriate subnet record name database. if the
-registration was point-to-point (i.e with another WINS server) then that
-WINS server may be inaccessible or may have failed. if so, then at a later
-date samba should take this into account (see rfc1001.txt 10.3).
-
-add_my_name_entry() issues this samba 'state'
-response_name_reg() deals with responses to NAME_REGISTER.
-
-no action is taken for any other kinds of samba 'states' if a response
-is not received. this is not to say that action may not be appropriate,
-just that it's not been looked at yet :-)
-
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Module name: nameserv.c
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- module nameserv contains name server management functions
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-extern pstring scope;
-extern pstring myname;
-extern fstring myworkgroup;
-extern char **my_netbios_names;
-extern struct in_addr ipzero;
-extern struct in_addr wins_ip;
-
-extern struct subnet_record *subnetlist;
-
-extern uint16 nb_type; /* samba's NetBIOS type */
-
-/****************************************************************************
- remove an entry from the name list
-
- note: the name will _always_ be removed
- XXXX at present, the name is removed _even_ if a WINS server says keep it.
-
- ****************************************************************************/
-void remove_name_entry(struct subnet_record *d, char *name,int type)
-{
- /* XXXX BUG: if samba is offering WINS support, it should still broadcast
- a de-registration packet to the local subnet before removing the
- name from its local-subnet name database. */
-
- struct name_record n;
- struct name_record *n2=NULL;
-
- make_nmb_name(&n.name,name,type,scope);
-
- if ((n2 = find_name_on_subnet(d, &n.name, FIND_SELF_NAME)))
- {
- /* check name isn't already being de-registered */
- if (NAME_DEREG(n2->ip_flgs[0].nb_flags))
- return;
-
- /* mark the name as in the process of deletion. */
- n2->ip_flgs[0].nb_flags &= NB_DEREG;
- }
-
- if (!n2) return;
-
- /* Only remove names with non-zero death times. */
- if(n2->death_time == 0)
- {
- DEBUG(5,("remove_name_entry: Name %s(%d) has zero ttl - not removing.\n",
- name, type));
- return;
- }
-
- /* remove the name immediately. even if the spec says we should
- first try to release them, this is too dangerous with our current
- name structures as otherwise we will end up replying to names we
- don't really own */
- remove_netbios_name(d,name,type,SELF);
-
- if (ip_equal(d->bcast_ip, wins_ip))
- {
- if (!lp_wins_support())
- {
- /* not a WINS server: we have to release them on the network */
- queue_netbios_pkt_wins(ClientNMB,NMB_REL,NAME_RELEASE,
- name, type, 0, 0,0,NULL,NULL,
- ipzero, ipzero);
- }
- }
- else
- {
- /* local interface: release them on the network */
- queue_netbios_packet(d,ClientNMB,NMB_REL,NAME_RELEASE,
- name, type, 0, 0,0,NULL,NULL,
- True, False, d->bcast_ip, d->bcast_ip, 0);
- }
-}
-
-
-/****************************************************************************
- add an entry to the name list
-
- big note: our name will _always_ be added (if there are no objections).
- it's just a matter of when this will be done (e.g after a time-out).
-
- ****************************************************************************/
-void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
-{
- 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_on_subnet(d, &n, FIND_SELF_NAME))
- re_reg = True;
-
- /* XXXX BUG: if samba is offering WINS support, it should still add the
- name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28
- regarding the point about M-nodes. */
-
- if (ip_equal(d->bcast_ip, wins_ip))
- {
- if (lp_wins_support())
- {
- /* we are a WINS server. */
- if(lp_wins_support())
- {
- DEBUG(4,("add_my_name_entry: samba as WINS server adding: "));
- }
-
- /* this will call add_netbios_entry() */
- name_register_work(d, name, type, nb_flags,0, ipzero, False);
- }
- else
- {
- DEBUG(4,("add_my_name_entry registering name %s with WINS server.\n",
- name));
-
- /* a time-to-live allows us to refresh this name with the WINS server. */
- queue_netbios_pkt_wins(ClientNMB,
- re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
- name, type, nb_flags, GET_TTL(0),0,NULL,NULL,
- ipzero, ipzero);
- }
- }
- else
- {
- /* broadcast the packet */
- queue_netbios_packet(d,ClientNMB,
- re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
- name, type, nb_flags, GET_TTL(0),0,NULL,NULL,
- True, False, d->bcast_ip, ipzero, 0);
- }
-}
-
-
-/****************************************************************************
- add the internet group <1c> domain logon names by wins unicast and broadcast.
- ****************************************************************************/
-void add_domain_logon_names(void)
-{
- struct subnet_record *d;
-
- if (!lp_domain_logons()) return;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- struct work_record *work = find_workgroupstruct(d, myworkgroup, True);
-
- if (work && work->log_state == LOGON_NONE)
- {
- struct nmb_name n;
- make_nmb_name(&n,myworkgroup,0x1c,scope);
-
- if (!find_name_on_subnet(d, &n, FIND_SELF_NAME))
- {
- /* logon servers are group names. don't expect failure */
-
- DEBUG(0,("%s attempting to become logon server for %s %s\n",
- timestring(), myworkgroup, inet_ntoa(d->bcast_ip)));
-
- become_logon_server(d, work);
- }
- }
- }
-}
-
-
-/****************************************************************************
- add the <1b> domain master names by broadcast.
- ****************************************************************************/
-void add_domain_master_bcast(void)
-{
- struct subnet_record *d;
-
- if (!lp_domain_master()) return;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
- {
- struct work_record *work = find_workgroupstruct(d, myworkgroup, True);
-
- if (work && work->dom_state == DOMAIN_NONE)
- {
- struct nmb_name n;
- make_nmb_name(&n,myworkgroup,0x1b,scope);
-
- if (!find_name_on_subnet(d, &n, FIND_SELF_NAME))
- {
- DEBUG(0,("%s add_domain_names: attempting to become domain \
-master browser on workgroup %s %s\n", timestring(), myworkgroup, inet_ntoa(d->bcast_ip)));
-
- /* send out a query to establish whether there's a
- domain controller on the local subnet. if not,
- we can become a domain controller. it's only
- polite that we check, before claiming the
- NetBIOS name 0x1b.
- */
-
- DEBUG(0,("add_domain_names:querying subnet %s \
-for domain master on workgroup %s\n", inet_ntoa(d->bcast_ip), myworkgroup));
-
- queue_netbios_packet(d,ClientNMB,NMB_QUERY,
- NAME_QUERY_DOMAIN,
- myworkgroup, 0x1b,
- 0, 0,0,NULL,NULL,
- True, False,
- d->bcast_ip, d->bcast_ip, 0);
- }
- }
- }
-}
-
-
-/****************************************************************************
- add the <1b> domain master name by wins unicast.
- ****************************************************************************/
-void add_domain_master_wins(void)
-{
- struct work_record *work;
-
- if (!lp_domain_master() || wins_client_subnet == NULL) return;
-
- work = find_workgroupstruct(wins_client_subnet, myworkgroup, True);
-
- if (work && work->dom_state == DOMAIN_NONE)
- {
- struct nmb_name n;
- make_nmb_name(&n,myworkgroup,0x1b,scope);
-
- if (!find_name_on_subnet(wins_client_subnet, &n, FIND_SELF_NAME))
- {
- DEBUG(0,("%s add_domain_names: attempting to become domain \
-master browser on workgroup %s %s\n",
- timestring(), myworkgroup, inet_ntoa(wins_client_subnet->bcast_ip)));
-
- if (lp_wins_support())
- {
- /* use the wins server's capabilities (indirectly). if
- someone has already registered the domain<1b>
- name with the WINS server, then the WINS
- server's job is to _check_ that the owner still
- wants it, before giving it away.
- */
-
- DEBUG(1,("%s initiate become domain master for %s\n",
- timestring(), myworkgroup));
-
- become_domain_master(wins_client_subnet, work);
- }
- else
- {
- /* send out a query to establish whether there's a
- domain controller on the WINS subnet. if not,
- we can become a domain controller. it's only
- polite that we check, before claiming the
- NetBIOS name 0x1b.
- */
-
- DEBUG(0,("add_domain_names:querying WINS \
-for domain master on workgroup %s\n", myworkgroup));
-
- queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
- NAME_QUERY_DOMAIN,
- myworkgroup, 0x1b,
- 0, 0,0,NULL,NULL,
- ipzero, ipzero);
- }
- }
- }
-}
-
-
-/****************************************************************************
- add the domain logon server and domain master browser names
-
- this code was written so that several samba servers can co-operate in
- sharing the task of (one server) being a domain master, and of being
- domain logon servers.
-
- **************************************************************************/
-void add_domain_names(time_t t)
-{
- static time_t lastrun = 0;
-
- if (lastrun != 0 && t < lastrun + CHECK_TIME_ADD_DOM_NAMES * 60) return;
- lastrun = t;
-
- /* do the "internet group" - <1c> names */
- add_domain_logon_names();
-
- /* do the domain master names */
- if (wins_client_subnet != NULL)
- {
- /* if the registration of the <1b> name is successful, then
- add_domain_master_bcast() will be called. this will
- result in domain logon services being gracefully provided,
- as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
-
- which, due to a bug in namelogon.c from 1.9.16p2 to 1.9.16p11
- cannot _provide_ domain master / domain logon services!!!
-
- */
- add_domain_master_wins();
- }
- else
- {
- add_domain_master_bcast();
- }
-}
-
-/****************************************************************************
- add the magic samba names, useful for finding samba servers
- **************************************************************************/
-void add_my_names(void)
-{
- struct subnet_record *d;
- /* each subnet entry, including WINS pseudo-subnet, has SELF names */
-
- /* XXXX if there was a transport layer added to samba (ipx/spx etc) then
- there would be yet _another_ for-loop, this time on the transport type
- */
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- int n;
-
- /* Add all our names including aliases. */
- for (n=0; my_netbios_names[n]; n++)
- {
- add_my_name_entry(d, my_netbios_names[n],0x20,nb_type|NB_ACTIVE);
- add_my_name_entry(d, my_netbios_names[n],0x03,nb_type|NB_ACTIVE);
- add_my_name_entry(d, my_netbios_names[n],0x00,nb_type|NB_ACTIVE);
- }
-
- /* these names are added permanently (ttl of zero) and will NOT be
- refreshed with the WINS server */
- add_netbios_entry(d,"*",0x0,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
- add_netbios_entry(d,"*",0x20,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
- add_netbios_entry(d,"__SAMBA__",0x20,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
- add_netbios_entry(d,"__SAMBA__",0x00,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
- }
-}
-
-
-/****************************************************************************
- remove all the samba names... from a WINS server if necessary.
- **************************************************************************/
-void remove_my_names()
-{
- struct subnet_record *d;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- struct name_record *n, *next;
-
- for (n = d->namelist; n; n = next)
- {
- next = n->next;
- if (n->source == SELF)
- {
- /* get all SELF names removed from the WINS server's database */
- /* XXXX note: problem occurs if this removes the wrong one! */
-
- remove_name_entry(d,n->name.name, n->name.name_type);
- }
- }
- }
-}
-
-
-/*******************************************************************
- refresh my own names
- ******************************************************************/
-void refresh_my_names(time_t t)
-{
- struct subnet_record *d;
-
- for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
- {
- struct name_record *n;
-
- for (n = d->namelist; n; n = n->next)
- {
- /* each SELF name has an individual time to be refreshed */
- if (n->source == SELF && n->refresh_time < t &&
- n->death_time != 0)
- {
- add_my_name_entry(d,n->name.name,n->name.name_type,
- n->ip_flgs[0].nb_flags);
- /* they get a new lease on life :-) */
- n->death_time += GET_TTL(0);
- n->refresh_time += GET_TTL(0);
- }
- }
- }
-}
-
-
-/*******************************************************************
- queries names occasionally. an over-cautious, non-trusting WINS server!
-
- this function has been added because nmbd could be restarted. it
- is generally a good idea to check all the names that have been
- reloaded from file.
-
- XXXX which names to poll and which not can be refined at a later date.
- ******************************************************************/
-void query_refresh_names(time_t t)
-{
- struct name_record *n;
- struct subnet_record *d = wins_client_subnet;
-
- static time_t lasttime = 0;
-
- 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 (!lasttime) lasttime = t;
- if (t - lasttime < NAME_POLL_INTERVAL) return;
-
- lasttime = time(NULL);
-
- for (n = d->namelist; n; n = n->next)
- {
- /* only do unique, registered names */
-
- if (n->source != REGISTER) continue;
- if (!NAME_GROUP(n->ip_flgs[0].nb_flags)) continue;
-
- if (n->refresh_time < t)
- {
- DEBUG(3,("Polling name %s\n", namestr(&n->name)));
-
- queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_CONFIRM,
- n->name.name, n->name.name_type,
- 0,0,0,NULL,NULL,
- False,False,n->ip_flgs[0].ip,n->ip_flgs[0].ip,
- 0);
- 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;
- }
-}
-
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.0
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: nameserv.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-*/
-
-this module deals with general maintenance of NetBIOS names.
-
-/*************************************************************************
- query_refresh_names()
- *************************************************************************/
-
-this function is responsible for polling all names registered in the
-WINS database. it is planned to enable this function should samba
-detect an inconsistency on the network, which could occur if the
-samba NetBIOS daemon dies and is restarted.
-
-polling is done very infrequently, but all names will be covered
-within a period NAME_POLL_REFRESH_TIME. a group of at most ten names
-will be queried at once, at intervals of NAME_POLL_INTERVAL seconds.
-if the total number of names queried in this way will take too long,
-then the time that an individual name will next be polled is
-increased accordingly.
-
-name query polling is functionality over-and-above the normal
-requirement (see rfc1001.txt 15.1.7 point 7). it is normally the
-responsibility of the owner of a name to re-register the name at
-regular intervals.
-
-
-/*************************************************************************
- refresh_my_names()
- *************************************************************************/
-
-this function is responsible for refreshing samba's names that have
-been registered with other servers on a local subnet, or with another
-WINS server if samba is using one.
-
-samba's names' refresh_time will be updated through the use of the function
-add_my_name_entry().
-
-
-/*************************************************************************
- remove_my_names()
- *************************************************************************/
-
-this function is responsible for removing all samba's SELF names. it
-is used when samba receives a SIG_TERM. samba at present does not wait
-for the WINS server to reply to the name releases sent out.
-
-
-/*************************************************************************
- add_my_names()
- *************************************************************************/
-
-this function is responsible for adding and registering if necessary all
-samba's SELF names, on each of its local subnets and with another WINS
-server if samba is using one.
-
-/*************************************************************************
- add_my_name_entry()
- *************************************************************************/
-
-this function is responsible for registering or re-registering one of
-samba's names, either on the local subnet or with another WINS server
-if samba is using one.
-
-if the name is already in samba's database, then it is re-registered,
-otherwise it is simply registered.
-
-if the name is being registered in a WINS capacity (the subnet to which
-the name should be added is the WINS pseudo-subnet) then we add the entry
-immediately if samba is a WINS server. it uses name_register_work()
-because if the name is being added as part of becoming a master browser,
-we want to carry on that process. if the name is registered with another
-WINS server, we must wait for an answer from that WINS server. either
-name_register_work() or name_unregister_work() will be called as a result.
-
-if the name is being registered on a local subnet, then it is
-broadcast. an explicit rejection from another host will result
-in name_unregister_work() being called. no response will, after
-retrying, result in name_register_work() being called.
-
-what ever method is used, the name will either be registered
-or rejected, and what ever process was taking place (becoming
-a master browser for example) will carry on.
-
-expire_netbios_response_entries() is responsible for taking further
-action if no response to the registration is received.
-
-note that there may be a large number of function calls on the
-stack if become_master() is called and samba is configured as
-a WINS server. the loop will be:
-
-become_master(), add_my_name_entry(), name_register_work() and
-back to become_master() with the new value of the workgroup
-'state'.
-
-
-/*************************************************************************
- remove_name_entry()
- *************************************************************************/
-
-this function is responsible for removing a NetBIOS name. if the name
-being removed is registered on a local subnet, a name release should be
-broadcast on the local subnet.
-
-if the name is being released in a WINS capacity (the subnet to
-which the name should be added is the WINS pseudo-subnet) then we
-remove the entry immediately if samba is a WINS server. it uses
-name_unregister_work() because if the name is being added as part of
-becoming a master browser, we want to terminate that process. if the
-name is released from another WINS server, we must wait for an
-answer from that WINS server. name_unregister_work() will
-definitely be called as a result, because at present we ignore
-negative responses for a name release from a WINS server.
-
-if the name is being releasedd on a local subnet, then it is
-broadcast. name_unregister_work() will definitely be called
-because we ignore negative name releases at present.
-
-what ever method is used, the name will be released. (NOT TRUE!
-see response_name_release())
-
-expire_netbios_response_entries() is responsible for taking further action
-if no response to the name release is received.
-
-
-/*************************************************************************
- load_netbios_names()
- *************************************************************************/
-
-this function is responsible for loading any NetBIOS names that samba,
-in its WINS capacity, has written out to disk. all the relevant details
-are recorded in this file, including the time-to-live. should the
-time left to live be small, the name is not added back in to samba's
-WINS database.
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Module name: nameservreply.c
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- created module nameservreply containing NetBIOS reply functions
-
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-extern struct in_addr wins_ip;
-
-/****************************************************************************
-send a registration / release response: pos/neg
-**************************************************************************/
-static void send_name_response(int fd, struct in_addr from_ip,
- int name_trn_id, int opcode, BOOL success,
- BOOL recursion_available, BOOL recursion_desired,
- struct nmb_name *reply_name, int nb_flags, int ttl,
- struct in_addr ip)
-{
- char rdata[6];
- struct packet_struct p;
-
- int rcode = 0;
-
- if (success == False)
- {
- /* NEGATIVE RESPONSE */
- rcode = 6;
- }
- else if (opcode == NMB_REG && !recursion_available)
- {
- /* END-NODE CHALLENGE REGISTRATION RESPONSE */
- rcode = 0;
- }
-
- rdata[0] = nb_flags;
- rdata[1] = 0;
- putip(&rdata[2],(char *)&ip);
-
- p.ip = from_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
-
- reply_netbios_packet(&p,name_trn_id,
- rcode,opcode,opcode,
- recursion_available, recursion_desired,
- reply_name, 0x20, 0x1,
- ttl,
- rdata, 6);
-}
-
-/****************************************************************************
- add a netbios entry. respond to the (possibly new) owner.
- **************************************************************************/
-void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
- uint16 response_id,
- struct nmb_name *name,
- int nb_flags, int ttl, struct in_addr register_ip,
- BOOL new_owner, struct in_addr reply_to_ip)
-{
- /* register the old or the new owners' ip */
- add_netbios_entry(wins_client_subnet,name->name,name->name_type,
- nb_flags,ttl,REGISTER,register_ip,False);
-
- /* reply yes or no to the host that requested the name */
- /* see rfc1002.txt - 4.2.10 and 4.2.11 */
-
- send_name_response(fd, reply_to_ip, response_id, NMB_REG,
- new_owner,
- True, True,
- name, nb_flags, ttl, reply_to_ip);
-}
-
-
-/****************************************************************************
-reply to a name release
-****************************************************************************/
-void reply_name_release(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct in_addr ip;
- int nb_flags = nmb->additional->rdata[0];
- BOOL bcast = nmb->header.nm_flags.bcast;
- struct name_record *n;
- struct subnet_record *d = NULL;
- BOOL success = False;
-
- putip((char *)&ip,&nmb->additional->rdata[2]);
-
- DEBUG(3,("Name release on name %s\n",
- namestr(&nmb->question.question_name)));
-
- if(!bcast)
- d = wins_client_subnet;
- else
- d = find_subnet(p->ip);
-
- if (!d)
- {
- DEBUG(3,("response packet: can't match address %s to subnet\n",
- inet_ntoa(p->ip)));
- return;
- }
-
- n = find_name_on_subnet(d, &nmb->question.question_name, FIND_ANY_NAME);
-
- /* XXXX under what conditions should we reject the removal?? */
- /* For now - remove if the names match and the group bit matches. */
- if (n && (n->source != SELF) && (NAME_GROUP(n->ip_flgs[0].nb_flags) == NAME_GROUP(nb_flags)))
- {
- success = True;
-
- /* If it's a group name not ending in 1c (not an internet name)
- then just allow it to fade out of existance by timing out. */
- if(NAME_GROUP(nb_flags) && (n->name.name_type != 0x1c))
- {
- DEBUG(5, ("reply_name_release: Allow group name %s(%d) to fade out on \
-subnet %s\n", namestr(&nmb->question.question_name), n->name.name_type,
- inet_ntoa(d->bcast_ip)));
- }
- else
- {
- DEBUG(5, ("reply_name_release: Removing name %s on subnet %s\n",
- namestr(&nmb->question.question_name), inet_ntoa(d->bcast_ip)));
- remove_name(d,n);
- n = NULL;
- }
- }
-
- if (bcast) return;
-
- /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
- send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
- success, False, False,
- &nmb->question.question_name, nb_flags, 0, ip);
-}
-
-
-/****************************************************************************
-reply to a reg request
-**************************************************************************/
-void reply_name_reg(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
-
- struct nmb_name *reply_name = question;
-
- char *qname = question->name;
- int qname_type = question->name_type;
-
- BOOL bcast = nmb->header.nm_flags.bcast;
-
- int ttl = GET_TTL(nmb->additional->ttl);
- int nb_flags = nmb->additional->rdata[0];
- BOOL group = NAME_GROUP(nb_flags);
-
- struct subnet_record *d = NULL;
- struct name_record *n = NULL;
-
- BOOL success = True;
- BOOL secured_redirect = False;
-
- struct in_addr ip, from_ip;
-
- putip((char *)&from_ip,&nmb->additional->rdata[2]);
- ip = from_ip;
-
- DEBUG(3,("Name registration for name %s at %s - ",
- namestr(question),inet_ntoa(ip)));
-
- if (group && (qname_type != 0x1c))
- {
- /* apparently we should return 255.255.255.255 for group queries
- (email from MS) */
- ip = *interpret_addr2("255.255.255.255");
- }
-
- if (!bcast)
- d = wins_client_subnet;
- else
- d = find_subnet(p->ip);
-
- if (!d)
- {
- DEBUG(3,("reply_name_reg: can't match address %s to subnet\n",
- inet_ntoa(p->ip)));
- return;
- }
-
- /* see if the name already exists */
- n = find_name_on_subnet(d, question, FIND_ANY_NAME);
-
- if (n)
- {
- DEBUG(3,("found\n"));
- if (!group) /* unique names */
- {
- if (n->source == SELF || NAME_GROUP(n->ip_flgs[0].nb_flags))
- {
- /* no-one can register one of samba's names, nor can they
- register a name that's a group name as a unique name */
-
- success = False;
- }
- else if(!ip_equal(ip, n->ip_flgs[0].ip))
- {
- /* XXXX rfc1001.txt says:
- * 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 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.
- */
-
- secured_redirect = True;
-
- reply_name = &n->name;
- }
- else
- {
- n->ip_flgs[0].ip = ip;
- n->death_time = ttl?p->timestamp+ttl*3:0;
- DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip_flgs[0].ip)));
- }
- }
- else
- {
- /* refresh the name */
- if (n->source != SELF)
- {
- 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
- {
- DEBUG(3,("not found\n"));
- /* add the name to our name/subnet, or WINS, database */
- n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,True);
- }
-
- /* if samba owns a unique name on a subnet, then it must respond and
- disallow the attempted registration. if the registration is
- successful by broadcast, only then is there no need to respond
- (implicit registration: see rfc1001.txt 15.2.1).
- */
-
- if (bcast && success) return;
-
- if (secured_redirect)
- {
- char rdata[2];
-
- /* XXXX i am confused. RSVAL or SSVAL? assume NMB byte ordering */
- RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
-
- /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3
- type = 0x0a; see rfc1002.txt 4.2.1.3
- class = 0x01; see rfc1002.txt 4.2.16
- */
-
- /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
- reply_netbios_packet(p,nmb->header.name_trn_id,
- 0,NMB_WAIT_ACK,NMB_WAIT_ACK,
- False,False,
- reply_name, 0x0a, 0x01,
- 15*1000, /* 15 seconds long enough to wait? */
- rdata, 2);
-
- /* initiate some enquiries to the current owner. */
- queue_netbios_packet(d,ClientNMB,NMB_QUERY,
- NAME_REGISTER_CHALLENGE,
- reply_name->name,reply_name->name_type,
- nb_flags,0,0,NULL,NULL,
- False, False,
- n->ip_flgs[0].ip, p->ip,
- nmb->header.name_trn_id);
- }
- else
- {
- /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.5-6
- or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
- */
-
- send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
- success,
- True, True,
- reply_name, nb_flags, ttl, ip);
- }
-}
-
-/* this is used to sort names for a name status into a sensible order
- we put our own names first, then in alphabetical order */
-static int status_compare(char *n1,char *n2)
-{
- extern pstring myname;
- int l1,l2,l3;
-
- /* its a bit tricky because the names are space padded */
- for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
- for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
- l3 = strlen(myname);
-
- if ((l1==l3) && strncmp(n1,myname,l3) == 0 &&
- (l2!=l3 || strncmp(n2,myname,l3) != 0))
- return -1;
-
- if ((l2==l3) && strncmp(n2,myname,l3) == 0 &&
- (l1!=l3 || strncmp(n1,myname,l3) != 0))
- return 1;
-
- return memcmp(n1,n2,18);
-}
-
-
-/****************************************************************************
- reply to a name status query
-
- combine the list of the local interface on which the query was made with
- the names registered via wins.
- ****************************************************************************/
-void reply_name_status(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- int ques_type = nmb->question.question_name.name_type;
- char rdata[MAX_DGRAM_SIZE];
- char *countptr, *buf, *bufend, *buf0;
- int names_added,i;
- struct name_record *n;
- struct subnet_record *d = wins_client_subnet;
- BOOL bcast = nmb->header.nm_flags.bcast;
-
- /* This query shoud only be made point to point. */
- if(bcast)
- {
- DEBUG(3,("Name status req: ignoring bcast from %s\n",
- inet_ntoa(p->ip)));
- return;
- }
-
- if(d == NULL)
- {
- /* We are working broadcast only (no wins_client_subnet).
- Use the first matching subnet. If none matches
- then return.
- */
- if((d = find_subnet(p->ip)) == NULL)
- {
- DEBUG(3,("Name status req: can't match address %s to subnet\n",
- inet_ntoa(p->ip)));
- return;
- }
- }
-
- DEBUG(3,("Name status for name %s from ip %s\n",
- namestr(&nmb->question.question_name),
- inet_ntoa(p->ip)));
-
- n = find_name_on_subnet(d, &nmb->question.question_name, FIND_SELF_NAME);
-
- if (!n) return;
-
- /* XXXX hack, we should calculate exactly how many will fit */
- bufend = &rdata[MAX_DGRAM_SIZE] - 18;
- countptr = buf = rdata;
- buf += 1;
- buf0 = buf;
-
- names_added = 0;
-
- n = d->namelist;
-
- while (buf < bufend)
- {
- if (n->source == SELF)
- {
- int name_type = n->name.name_type;
-
- /* check if we want to exclude other workgroup names
- from the response. if we don't exclude them, windows clients
- get confused and will respond with an error for NET VIEW */
-
- if (!strequal(n->name.name,"*") &&
- !strequal(n->name.name,"__SAMBA__") &&
- (name_type < 0x1b || name_type >= 0x20 ||
- ques_type < 0x1b || ques_type >= 0x20 ||
- strequal(qname, n->name.name)))
- {
- /* start with first bit of putting info in buffer: the name */
- bzero(buf,18);
- sprintf(buf,"%-15.15s",n->name.name);
- strupper(buf);
-
- /* put name type and netbios flags in buffer */
- buf[15] = name_type;
- buf[16] = n->ip_flgs[0].nb_flags;
-
- buf += 18;
-
- names_added++;
- }
- }
-
- /* remove duplicate names */
- qsort(buf0,names_added,18,QSORT_CAST status_compare);
-
- for (i=1;i<names_added;i++) {
- if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
- names_added--;
- if (names_added == i) break;
- memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
- i--;
- }
- }
-
- buf = buf0 + 18*names_added;
-
- n = n->next;
-
- if (!n)
- {
- /* end of this name list: add wins names too? */
- struct subnet_record *w_d;
-
- if (!(w_d = wins_client_subnet)) break;
-
- if (w_d != d)
- {
- d = w_d;
- n = d->namelist; /* start on the wins name list */
- }
- }
- if (!n) break;
- }
-
- SCVAL(countptr,0,names_added);
-
- /* we don't send any stats as they could be used to attack
- the protocol */
- bzero(buf,64);
-
- buf += 46;
-
- /* Send a POSITIVE NAME STATUS RESPONSE */
- reply_netbios_packet(p,nmb->header.name_trn_id,
- 0,NMB_STATUS,0,False, False,
- &nmb->question.question_name,
- 0x21, 0x01,
- 0, rdata,PTR_DIFF(buf,rdata));
-}
-
-
-/***************************************************************************
-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 bcast = nmb->header.nm_flags.bcast;
- BOOL query_is_to_wins_server = (!bcast &&
- nmb->header.nm_flags.recursion_desired);
- 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 = NULL;
- BOOL acting_as_wins_server = lp_wins_support();
-
- /* directed queries are for WINS server: broadcasts are local SELF queries.
- the exception is Domain Master names. */
-
- if (query_is_to_wins_server)
- {
- /* queries to the WINS server involve the WINS server subnet */
- if (!(d = wins_client_subnet))
- {
- DEBUG(3,("name query: wins server query from %s and no wins subnet being used.\n",
- inet_ntoa(p->ip)));
- success = False;
- }
- }
- else
- {
- /* queries to the WINS client involve, unfortunately, the WINS subnet
- because it contains WINS client (SELF) entries, as _well_ as WINS
- server entries. not good.
- */
-
- if (!(d = find_subnet_all(p->ip)))
- {
- DEBUG(3,("name query: can't match address %s to subnet\n",
- inet_ntoa(p->ip)));
- success = False;
- }
- }
-
- DEBUG(3,("Name query from %s for name %s<0x%x>\n",
- inet_ntoa(p->ip), question->name, question->name_type));
-
- if (!bcast && (name_type == 0x1d) && lp_wins_support())
- {
- /* see WINS manager HELP - 'How WINS Handles Special Names' */
- /* a WINS query (unicasted) for a 0x1d name must always return False */
- success = False;
- }
-
- if (success)
- {
- /* look up the name in the cache */
- n = find_name_on_subnet(d, question, FIND_ANY_NAME);
-
- /* check for a previous DNS lookup (these are stored
- on the wins_client_subnet name list, if it exists */
-
- if (!n && wins_client_subnet && (d != wins_client_subnet) &&
- (n = find_name_on_subnet(wins_client_subnet, question, FIND_ANY_NAME))) {
- if (n->source != DNS && n->source != DNSFAIL) {
- n = NULL;
- } else {
- DEBUG(5,("Found DNS cache entry %s\n", namestr(&n->name)));
- }
- }
-
- /* it is a name that already failed DNS lookup or it's expired */
- if (n && (n->source == DNSFAIL ||
- (n->death_time && n->death_time < p->timestamp))) {
- DEBUG(5,("expired name %s\n", namestr(&n->name)));
- success = False;
- }
-
-
- /* do we want to do dns lookups? */
- if (success && !n && (lp_dns_proxy() || !bcast)) {
- BOOL dns_type = (name_type == 0x20 || name_type == 0);
- if (dns_type && wins_client_subnet) {
- /* add it to the dns name query queue */
- if (queue_dns_query(p, question, &n))
- return;
- }
- }
- }
-
- if (!n) success = False;
-
- if (success)
- {
- if (bcast && n->source != SELF && name_type != 0x1b)
- {
- /* 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 (!lp_wins_proxy() ||
- same_net(p->ip,n->ip_flgs[0].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 Domain Master 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
- */
-
- /* XXXX note: for proxy servers, we should forward the query on to
- another WINS server if the name is not in our database, or we are
- not a WINS server ourselves
- */
- ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
- retip = n->ip_flgs[0].ip;
- nb_flags = n->ip_flgs[0].nb_flags;
- }
-
- if (!success && bcast) return; /* never reply negative response to bcasts */
-
- /* if the IP is 0 then substitute my IP */
- if (zero_ip(retip)) retip = *iface_ip(p->ip);
-
- /* SPECIAL CASE... If we are a WINS server and the request is explicitly
- *to* the WINS server and the name type is WORKGROUP<0x1e> we should
- respond with the local broadcast address 255.255.255.255.
- */
- if(!bcast && (name_type == 0x1e) && lp_wins_support())
- retip = *interpret_addr2("255.255.255.255");
-
- if (success)
- {
- rcode = 0;
- DEBUG(3,("OK %s\n",inet_ntoa(retip)));
- }
- else
- {
- rcode = 3;
- DEBUG(3,("UNKNOWN\n"));
- }
-
- if (success)
- {
- rdata[0] = nb_flags;
- rdata[1] = 0;
- putip(&rdata[2],(char *)&retip);
- }
-
- /* see rfc1002.txt 4.2.13 */
-
- reply_netbios_packet(p,nmb->header.name_trn_id,
- rcode,NMB_QUERY,0,
- (query_is_to_wins_server && acting_as_wins_server ?
- True : False), /* recursion_available flag */
- True, /* recursion_desired_flag */
- &nmb->question.question_name,
- 0x20, 0x01,
- ttl,
- rdata, success ? 6 : 0);
-}
+++ /dev/null
-/*
- Unix SMB/Netbios documentation.
- Version 0.0
- Copyright (C) Luke Leighton Andrew Tridgell 1996
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Document name: nameservreply.doc
-
- Revision History:
-
- 0.0 - 02jul96 : lkcl@pires.co.uk
- created
-*/
-
-/*************************************************************************
- reply_name_query()
- *************************************************************************/
-
-this function is responsible for replying to a NetBIOS name query.
-
-there are two kinds of name queries: directed, and broadcast. directed
-queries are usually sent to samba in its WINS capacity. such hosts are
-termed 'point-to-point' hosts. broadcast queries are usually sent from
-'broadcast' or 'mixed' hosts.
-
-broadcasting is used by either older NetBIOS hosts, new NetBIOS hosts that
-have not had WINS capabilities added and new NetBIOS hosts that think the
-WINS server has died.
-
-the samba NetBIOS name database is divided into sections, on a
-per-subnet basis. there is also a WINS NetBIOS name database, and for
-convenience this is added as a pseudo-subnet with the ip address of
-255.255.255.255.
-
-the local subnet NetBIOS name databases only contain samba's names.
-the reason for this is that if a broadcast query is received, a NetBIOS
-hosts is only expected to respond if that query is for one of its own
-names (the exception to this is if a host is configured as a 'proxy'
-server, in which case, samba should redirect the query to another WINS
-server).
-
-the WINS pseudo-subnet NetBIOS database contains all NetBIOS names
-that are not 'special browser' type names (regarding this i am a
-_bit_ confused :-). names of type 0x01, 0x1d and 0x1e i consider to
-be 'special browser' names. at the moment. maybe.
-
-the type of search to be initiated is determined. if the NetBIOS name
-type is a non-special-browser name, then the WINS database is included
-in the search.
-
-if the name is not a special browser name, then we need to find the
-right subnet that the query came from. this is done using
-find_req_subnet(). this also has the benefit of stopping any queries
-from subnets that samba does not know about.
-
-if the query is a broadcast query, then the database of the local subnet
-is included in the search.
-
-the name is then searched for in the appropriate NetBIOS data structures.
-if it is found, then we need to check whether it is appropriate for us
-to reply to such a query.
-
-we will only reply if the query is a directed query, the name belongs to
-samba on that subnet, or the name is a domain master browser type,
-or we're doing replies on behalf of hosts on subnets not known to the
-host issuing the query. in the latter instance, it would be appropriate
-if samba is using a WINS server for it to forward the name query on to
-this WINS server.
-
-reply_name_query() then takes note of all the information that is
-needed to construct a reply to the caller. a negative reply (if the
-name is unknown to samba) or a positive reply (the name is known to
-samba) is then issued.
-
-
-/*************************************************************************
- reply_name_status()
- *************************************************************************/
-
-this function is responsible for constructing a reply to a NetBIOS
-name status query. this response contains all samba's NetBIOS names
-on the subnet that the query came in from.
-
-a reply will only be made if the NetBIOS name being queried exists.
-
-see rfc1001.txt and rfc1002.txt for details of the name status reply.
-
-
-/*************************************************************************
- reply_name_reg()
- *************************************************************************/
-
-this function is responsible for updating the NetBIOS name database
-from registration packets sent out by hosts wishing to register a
-name, and for informing them, if necessary, if this is acceptable
-or not.
-
-name registration can be done by broadcast or by point-to-point,
-i.e the registration is sent directly to samba in its capacity as
-a WINS server.
-
-if the name registration is done by broadcast (see rfc1001.txt 15.2.1),
-then samba's involvement in replying is limited to whether that name
-is owned by samba or not, on the relevant subnet.
-
-if the name registration is done point-to-point (see rfc1001.txt 15.2.2)
-then samba will first need to check its WINS name database records and
-proceed accordingly.
-
-samba looks for the appropriate subnet record that the registration
-should be added to / checked against, using find_req_subnet().
-
-next, the name is searched for in the local database or the WINS
-database as appropriate.
-
-if the name is not found, then it is added to the NetBIOS name database,
-using add_netbios_entry(), which may choose not to add the name (not
-that this affects the registration of the name on the network in any way).
-it will only add names to the WINS database, and even then it will only
-add non-special-browser type names.
-
-if the name is found, then samba must decide whether to accept the name
-or not. a group name is always added. for unique names, further checks
-need to be carried out.
-
-firstly, if the name in the database is one of samba's names, or if the
-name in the database is a group name, then it cannot be added as a unique
-name belonging to someone else. it is therefore rejected.
-
-secondly, if the ip address of the name being registered does not match
-against the ip in the database, then the unique name may belong to
-someone else. a check needs to be carried out with the owner in case
-they still wish to keep this name. a detailed discussion of what action
-to take is in rfc1001.txt 15.2.2.2 and 15.2.2.3.
-
-samba currently implements non-secured WINS, whereupon the responsibility
-for checking the name is passed on to the host doing the registration.
-rfc1001.txt refers to this as an END-NODE CHALLENGE REGISTRATION RESPONSE.
-(samba itself cannot yet cope with receiving such responses if it
-registers its names with another WINS server).
-
-having decided what kind of response to send (if any - acceptance of
-name registrations by broadcast is implicit), samba will send either a
-positive or negative NAME REGISTRATION RESPONSE, or an END-NODE CHALLENGE
-REGISTRATION RESPONSE to the host that initially sent the registration.
-
-whew.
-
-
-/*************************************************************************
- reply_name_release()
- *************************************************************************/
-
-this function is responsible for removing a NetBIOS name from the
-database when a server sends a release packet.
-
-samba looks for the appropriate subnet record that the release should
-be removed from, using find_req_subnet(). next, the name is searched
-for in the local database or the WINS database as appropriate.
-
-if the name is found, it is removed from the database and a
-positive reply is sent confirming this. if the name is not
-found, a negative reply is sent.
-
-a reply is _not_ sent if the release was done by broadcast: the
-release is implicit, and we should be grateful that they bothered
-to tell us. if the release was done by directed packet, then
-we deal with it as a WINS server and must reply (pos / neg).
-
-at present, the criteria for removing a name have yet to be
-developed / experimented with. at present, the only flags that
-are checked are the NetBIOS flags.
-
-
-/*************************************************************************
- send_name_response()
- *************************************************************************/
-
-this function is a wrap around reply_netbios_packet(). it sends
-a response to a name registration or release packet, minimising
-the function parameters needed to do this.
-
-if the function is called with the parameter 'success' set to
-True, then a positive response (to the registration or release)
-is made (see rfc1002.txt 4.2.5 and 4.2.10). if this parameter
-is False, then a negative response is issued (see rfc1002.txt
-4.2.6 and 4.2.11)
-
-if the function is called with a registration code, and the
-parameter 'recurse' is False, then an End-Node Challenge
-Registration response is issued (see rfc1002.txt 4.2.7)
-
-note: this function could also easily be used for name conflict
-demand (see rfc1002.txt 4.2.8).
-
-note: End-Node Challenge Registration response is only sent in
-non-secured NetBIOS Name Server implementations. samba now
-implements secured NetBIOS Name Server functionality (see
-rfc1001.txt 15.1.6).
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- Module name: nameservresp.c
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 05 jul 96: lkcl@pires.co.uk
- created module nameservresp containing NetBIOS response functions
-
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-extern pstring scope;
-extern fstring myworkgroup;
-extern struct in_addr ipzero;
-extern struct in_addr wins_ip;
-extern struct in_addr ipzero;
-
-
-#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
-
-
-/****************************************************************************
- response for a reg release received. samba has asked a WINS server if it
- could release a name.
- **************************************************************************/
-static void response_name_release(struct nmb_name *ans_name,
- struct subnet_record *d, struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *name = ans_name->name;
- int type = ans_name->name_type;
-
- DEBUG(4,("response name release received\n"));
-
- if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
- {
- /* IMPORTANT: see expire_netbios_response_entries() */
-
- struct in_addr found_ip;
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
- /* NOTE: we only release our own names at present */
- if (ismyip(found_ip))
- {
- name_unregister_work(d,name,type);
- }
- else
- {
- DEBUG(2,("name release for different ip! %s %s\n",
- inet_ntoa(found_ip), namestr(ans_name)));
- }
- }
- else
- {
- DEBUG(2,("name release for %s rejected!\n", namestr(ans_name)));
-
- /* XXXX PANIC! what to do if it's one of samba's own names? */
-
- /* 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. */
- }
-}
-
-
-/****************************************************************************
-response for a reg request received
-**************************************************************************/
-static void response_name_reg(struct nmb_name *ans_name,
- struct subnet_record *d, struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- BOOL bcast = nmb->header.nm_flags.bcast;
- char *name = ans_name->name;
- int type = ans_name->name_type;
-
- DEBUG(4,("response name registration received!\n"));
-
-#if 1
- /* This code is neccesitated due to bugs in earlier versions of
- Samba (up to 1.9.16p11). They respond to a broadcast
- name registration of WORKGROUP<1b> when they should
- not. Hence, until these versions are gone, we should
- treat such errors as success for this particular
- case only. jallison@whistle.com.
- */
- if ( ((d != wins_client_subnet) && (nmb->header.rcode == 6) && strequal(myworkgroup, name) &&
- (type == 0x1b)) ||
- (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata))
-#else
- if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
-#endif
- {
- /* IMPORTANT: see expire_netbios_response_entries() */
-
- int nb_flags = nmb->answers->rdata[0];
- int ttl = nmb->answers->ttl;
- struct in_addr found_ip;
-
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
- name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast);
- }
- else
- {
- DEBUG(2,("name registration for %s rejected by ip %s!\n",
- namestr(ans_name), inet_ntoa(p->ip)));
-
- /* oh dear. we have problems. possibly unbecome a master browser. */
- name_unregister_work(d,name,type);
- }
-}
-
-/****************************************************************************
- response from a name query server check. states of type NAME_QUERY_DOM_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, struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct in_addr send_ip;
- enum state_type cmd;
-
- /* This next fix was from Bernhard Laeser <nlaesb@ascom.ch>
- who noticed we were replying directly back to the server
- we sent to - rather than reading the response.
- */
-
- if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
- putip((char*)&send_ip,&nmb->answers->rdata[2]);
- else
- {
-
- DEBUG(2,("response_server_check: name query for %s failed\n",
- namestr(ans_name)));
- return;
- }
-
- /* issue another state: this time to do a name status check */
-
- cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
- NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK;
-
- /* initiate a name status check on address given in the reply
- record. In addition, the workgroup being checked has been stored
- in the response_record->my_name (see announce_master) we
- also propagate this into the same field. */
- queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd,
- ans_name->name, ans_name->name_type,
- 0,0,0,n->my_name,NULL,
- False,False,send_ip,n->reply_to_ip, 0);
-}
-
-
-/****************************************************************************
- 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.
-****************************************************************************/
-static BOOL interpret_node_status(struct subnet_record *d,
- char *p, struct nmb_name *name,int t,
- char *serv_name, struct in_addr ip, BOOL bcast)
-{
- int numnames = CVAL(p,0);
- BOOL found = False;
-
- DEBUG(4,("received %d names\n",numnames));
-
- p += 1;
-
- if (serv_name) *serv_name = 0;
-
- while (numnames--)
- {
- char qname[17];
- int type;
- fstring flags;
- int nb_flags;
-
- BOOL group = False;
- BOOL add = False;
-
- *flags = 0;
-
- StrnCpy(qname,p,15);
- type = CVAL(p,15);
- nb_flags = p[16];
- trim_string(qname,NULL," ");
-
- p += 18;
-
- if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;}
- if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); }
- if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); }
- if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
- if (NAME_HFLAG (nb_flags)) { strcat(flags,"H "); }
- if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
- if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); }
- if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
- if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
-
- /* we want the server name */
- if (serv_name && !*serv_name && !group && type == 0x20)
- {
- StrnCpy(serv_name,qname,15);
- serv_name[15] = 0;
- }
-
- /* looking for a name and type? */
- if (name && !found && (t == type))
- {
- /* take a guess at some of the name types we're going to ask for.
- evaluate whether they are group names or no... */
- if (((t == 0x1b || t == 0x1d || t == 0x20 ) && !group) ||
- ((t == 0x1c || t == 0x1e ) && group))
- {
- found = True;
- make_nmb_name(name,qname,type,scope);
- }
- }
-
- DEBUG(4,("\t%s(0x%x)\t%s\n",qname,type,flags));
- }
- DEBUG(4,("num_good_sends=%d num_good_receives=%d\n",
- IVAL(p,20),IVAL(p,24)));
- return found;
-}
-
-
-/****************************************************************************
- response from a name status check. states of type NAME_STATUS_DOM_SRV_CHK
- and NAME_STATUS_SRV_CHK dealt with here.
- ****************************************************************************/
-static void response_name_status_check(struct in_addr ip,
- struct nmb_packet *nmb, BOOL bcast,
- struct response_record *n, struct subnet_record *d)
-{
- /* NMB_STATUS arrives: contains workgroup name and server name required.
- amongst other things. */
-
- struct nmb_name name;
- fstring serv_name;
-
- if (nmb->answers &&
- interpret_node_status(d,nmb->answers->rdata,
- &name,0x20,serv_name,ip,bcast))
- {
- if (*serv_name)
- {
- /* response_record->my_name contains the
- workgroup name to sync with. See
- response_server_check() */
- sync_server(n->state,serv_name,
- n->my_name,name.name_type, d, n->send_ip);
- }
- }
- else
- {
- DEBUG(1,("No 0x20 name type in interpret_node_status()\n"));
- }
-}
-
-
-/****************************************************************************
- response from a name query for secured WINS registration. a state of
- NAME_REGISTER_CHALLENGE is dealt with here.
- ****************************************************************************/
-static void response_name_query_register(struct nmb_packet *nmb,
- struct nmb_name *ans_name,
- struct response_record *n, struct subnet_record *d)
-{
- struct in_addr register_ip;
- BOOL new_owner;
-
- DEBUG(4, ("Name query at %s ip %s - ",
- namestr(&n->name), inet_ntoa(n->send_ip)));
-
- if (!name_equal(&n->name, ans_name))
- {
- /* someone gave us the wrong name as a reply. oops. */
- /* XXXX should say to them 'oi! release that name!' */
-
- DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
- return;
- }
-
- if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
- {
- /* we had sent out a name query to the current owner
- of a name because someone else wanted it. now they
- have responded saying that they still want the name,
- so the other host can't have it.
- */
-
- /* first check all the details are correct */
-
- int nb_flags = nmb->answers->rdata[0];
- struct in_addr found_ip;
-
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
- if (nb_flags != n->nb_flags)
- {
- /* someone gave us the wrong nb_flags as a reply. oops. */
- /* XXXX should say to them 'oi! release that name!' */
-
- DEBUG(4,("expected nb_flags: %d\n", n->nb_flags));
- DEBUG(4,("unexpected nb_flags: %d\n", nb_flags));
- return;
- }
-
- if (!ip_equal(n->send_ip, found_ip))
- {
- /* someone gave us the wrong ip