This is it ! The mega-merge of the JRA_NMBD_REWRITE branch
authorJeremy Allison <jra@samba.org>
Sat, 13 Dec 1997 14:16:07 +0000 (14:16 +0000)
committerJeremy Allison <jra@samba.org>
Sat, 13 Dec 1997 14:16:07 +0000 (14:16 +0000)
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.

63 files changed:
source/client/clientutil.c
source/include/nameserv.h
source/include/proto.h
source/lib/interface.c
source/libsmb/namequery.c
source/libsmb/nmblib.c
source/nameannounce.c [deleted file]
source/nameannounce.doc [deleted file]
source/namebrowse.c [deleted file]
source/namebrowse.doc [deleted file]
source/namedbname.c [deleted file]
source/namedbname.doc [deleted file]
source/namedbresp.c [deleted file]
source/namedbresp.doc [deleted file]
source/namedbserver.c [deleted file]
source/namedbsubnet.c [deleted file]
source/namedbwork.c [deleted file]
source/nameelect.c [deleted file]
source/nameelect.doc [deleted file]
source/namelogon.c [deleted file]
source/namelogon.doc [deleted file]
source/namepacket.c [deleted file]
source/namepacket.doc [deleted file]
source/namequery.doc [deleted file]
source/nameresp.c [deleted file]
source/nameresp.doc [deleted file]
source/nameserv.c [deleted file]
source/nameserv.doc [deleted file]
source/nameservreply.c [deleted file]
source/nameservreply.doc [deleted file]
source/nameservresp.c [deleted file]
source/nameservresp.doc [deleted file]
source/namework.c [deleted file]
source/namework.doc [deleted file]
source/nmbd/asyncdns.c
source/nmbd/nmbd.c
source/nmbd/nmbd_become_dmb.c [new file with mode: 0644]
source/nmbd/nmbd_become_lmb.c [new file with mode: 0644]
source/nmbd/nmbd_browserdb.c [new file with mode: 0644]
source/nmbd/nmbd_browsesync.c [new file with mode: 0644]
source/nmbd/nmbd_elections.c [new file with mode: 0644]
source/nmbd/nmbd_incomingdgrams.c [new file with mode: 0644]
source/nmbd/nmbd_incomingrequests.c [new file with mode: 0644]
source/nmbd/nmbd_lmhosts.c [new file with mode: 0644]
source/nmbd/nmbd_logonnames.c [new file with mode: 0644]
source/nmbd/nmbd_mynames.c [new file with mode: 0644]
source/nmbd/nmbd_namelistdb.c [new file with mode: 0644]
source/nmbd/nmbd_namequery.c [new file with mode: 0644]
source/nmbd/nmbd_nameregister.c [new file with mode: 0644]
source/nmbd/nmbd_namerelease.c [new file with mode: 0644]
source/nmbd/nmbd_nodestatus.c [new file with mode: 0644]
source/nmbd/nmbd_packets.c [new file with mode: 0644]
source/nmbd/nmbd_processlogon.c [new file with mode: 0644]
source/nmbd/nmbd_responserecordsdb.c [new file with mode: 0644]
source/nmbd/nmbd_sendannounce.c [new file with mode: 0644]
source/nmbd/nmbd_serverlistdb.c [new file with mode: 0644]
source/nmbd/nmbd_subnetdb.c [new file with mode: 0644]
source/nmbd/nmbd_winsproxy.c [new file with mode: 0644]
source/nmbd/nmbd_winsserver.c [new file with mode: 0644]
source/nmbd/nmbd_workgroupdb.c [new file with mode: 0644]
source/nmbsync.c [deleted file]
source/param/loadparm.c
source/utils/nmblookup.c

index 4064dbecd789af94eebd5712259a8c99500a57aa..bf49c6b342be87272c4a6a95053135a6bfdd0393 100644 (file)
@@ -891,15 +891,18 @@ BOOL cli_open_sockets(int port )
       {
 #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);
        }
index 2a7bb290709eaad7d9ff6fcdfad33b7999d10967..4b7216fef6f7c4c8db31b12e6b107883fb8a7c96 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef _NAMESERV_H_
+#define _NAMESERV_H_
 /* 
    Unix SMB/Netbios implementation.
    Version 1.9.
@@ -20,7 +22,7 @@
    
 */
 
-#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;
 
@@ -255,37 +377,35 @@ struct response_record
   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;
@@ -294,7 +414,7 @@ struct subnet_record
   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;
@@ -304,7 +424,7 @@ struct res_rec {
   char rdata[MAX_DGRAM_SIZE];
 };
 
-/* define a nmb packet. */
+/* An nmb packet. */
 struct nmb_packet
 {
   struct {
@@ -337,7 +457,8 @@ struct nmb_packet
 };
 
 
-/* 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;
@@ -358,32 +479,35 @@ struct dgram_packet {
   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
@@ -396,42 +520,48 @@ struct packet_struct
 #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_ */
index e6a0b1efd74ac5923fd212a9f1a66dd90fae52b9..b249c9cb2031243691bbb0666dd28d28dd982917 100644 (file)
@@ -189,6 +189,8 @@ BOOL ismyip(struct in_addr ip);
 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);
@@ -276,6 +278,8 @@ BOOL lp_time_server(void);
 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);
@@ -451,225 +455,329 @@ int reply_sendstrt(char *inbuf,char *outbuf);
 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,
index 8af2696a446cac2ec6e6a737a44b69e25c8222a2..0008ad889dfc100676daccfaeae87f4d705d632e 100644 (file)
@@ -24,7 +24,7 @@
 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;
@@ -33,7 +33,7 @@ static BOOL got_ip=False;
 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;
 
@@ -262,7 +262,7 @@ static void interpret_interfaces(char *s, struct interface **interfaces,
   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)) {
@@ -424,6 +424,33 @@ int iface_count(void)
   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
   **************************************************************************/
@@ -453,7 +480,9 @@ static struct interface *iface_find(struct in_addr ip)
 }
 
 /* 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)
 {
index 15bf58bc559451baa561af1336abd3a70d6b42b3..9915ee92a850dbb06dbbccf9967e73f35000d57c 100644 (file)
@@ -189,21 +189,25 @@ BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
 
 /****************************************************************************
   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);
@@ -237,7 +241,7 @@ BOOL name_query(int fd,char *name,int name_type,
   GetTimeOfDay(&tval);
 
   if (!send_packet(&p)) 
-    return(False);
+    return NULL;
 
   retries--;
 
@@ -248,7 +252,7 @@ BOOL name_query(int fd,char *name,int name_type,
       if (TvalDiff(&tval,&tval2) > retry_time) {
        if (!retries) break;
        if (!found && !send_packet(&p))
-         return False;
+         return NULL;
        GetTimeOfDay(&tval);
        retries--;
       }
@@ -256,7 +260,7 @@ BOOL name_query(int fd,char *name,int name_type,
       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) {
@@ -279,11 +283,17 @@ BOOL name_query(int fd,char *name,int name_type,
            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);
@@ -291,5 +301,5 @@ BOOL name_query(int fd,char *name,int name_type,
        }
     }
 
-  return(found);
+  return ip_list;
 }
index 6a91b20ea87fe1cffae34e2e8c670ca268ac55be..0335f01833b338add761a955ba660eeab0bcb505 100644 (file)
@@ -34,11 +34,13 @@ static struct opcode_names {
        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 }
 };
 
@@ -205,7 +207,7 @@ static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *na
   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;
@@ -249,6 +251,7 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
     /* 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);
   }
@@ -292,9 +295,9 @@ char *namestr(struct nmb_name *n)
   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);
@@ -467,26 +470,146 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
   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);
 }
 
 /*******************************************************************
@@ -619,12 +742,22 @@ static int build_dgram(char *buf,struct packet_struct *p)
   ******************************************************************/
 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
diff --git a/source/nameannounce.c b/source/nameannounce.c
deleted file mode 100644 (file)
index 28ebe5d..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-/* 
-   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);
-    }
-  }
-}
diff --git a/source/nameannounce.doc b/source/nameannounce.doc
deleted file mode 100644 (file)
index e04a592..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/* 
-   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.
------------
-
diff --git a/source/namebrowse.c b/source/namebrowse.c
deleted file mode 100644 (file)
index 2f883d4..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/* 
-   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);
-}
-
diff --git a/source/namebrowse.doc b/source/namebrowse.doc
deleted file mode 100644 (file)
index 82713d8..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/* 
-   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.
-
-
-
-
diff --git a/source/namedbname.c b/source/namedbname.c
deleted file mode 100644 (file)
index 6ff20f4..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/* 
-   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);
-      }
-    }
-  }
-}
-
-
diff --git a/source/namedbname.doc b/source/namedbname.doc
deleted file mode 100644 (file)
index 34a791d..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/* 
-   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.
-
-
diff --git a/source/namedbresp.c b/source/namedbresp.c
deleted file mode 100644 (file)
index e9fe39c..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/* 
-   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;
-}
-
-
diff --git a/source/namedbresp.doc b/source/namedbresp.doc
deleted file mode 100644 (file)
index a54c070..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* 
-   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.
-----------------
diff --git a/source/namedbserver.c b/source/namedbserver.c
deleted file mode 100644 (file)
index c3f6076..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/* 
-   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);
-       }
-    }
-}
-
diff --git a/source/namedbsubnet.c b/source/namedbsubnet.c
deleted file mode 100644 (file)
index 816203e..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/* 
-   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));
-}
-
diff --git a/source/namedbwork.c b/source/namedbwork.c
deleted file mode 100644 (file)
index b01eb92..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/* 
-   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));
-                   }
-               }
-           }
-       }
-    }
-}
diff --git a/source/nameelect.c b/source/nameelect.c
deleted file mode 100644 (file)
index b977741..0000000
+++ /dev/null
@@ -1,845 +0,0 @@
-/* 
-   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;
-}
-
diff --git a/source/nameelect.doc b/source/nameelect.doc
deleted file mode 100644 (file)
index df025e2..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/* 
-   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)
-
-
diff --git a/source/namelogon.c b/source/namelogon.c
deleted file mode 100644 (file)
index 08e0f03..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/* 
-   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;
-               }
-       }
-
-}
diff --git a/source/namelogon.doc b/source/namelogon.doc
deleted file mode 100644 (file)
index c4a97d0..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 
-   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 :-).
diff --git a/source/namepacket.c b/source/namepacket.c
deleted file mode 100644 (file)
index be09934..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-/* 
-   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));
-}
diff --git a/source/namepacket.doc b/source/namepacket.doc
deleted file mode 100644 (file)
index 159a507..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* 
-   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.
-
-
diff --git a/source/namequery.doc b/source/namequery.doc
deleted file mode 100644 (file)
index 4337cfb..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* 
-   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().
-
diff --git a/source/nameresp.c b/source/nameresp.c
deleted file mode 100644 (file)
index de1f33c..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/* 
-   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;
-}
diff --git a/source/nameresp.doc b/source/nameresp.doc
deleted file mode 100644 (file)
index cfe6350..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/* 
-   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 :-)
-
-
diff --git a/source/nameserv.c b/source/nameserv.c
deleted file mode 100644 (file)
index a05db39..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-/* 
-   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;
-       }
-}
-
diff --git a/source/nameserv.doc b/source/nameserv.doc
deleted file mode 100644 (file)
index af4934a..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/* 
-   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.
-
diff --git a/source/nameservreply.c b/source/nameservreply.c
deleted file mode 100644 (file)
index 6c7bfde..0000000
+++ /dev/null
@@ -1,685 +0,0 @@
-/* 
-   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);
-}
diff --git a/source/nameservreply.doc b/source/nameservreply.doc
deleted file mode 100644 (file)
index a5acf8a..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/* 
-   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).
-
diff --git a/source/nameservresp.c b/source/nameservresp.c
deleted file mode 100644 (file)
index 3349610..0000000
+++ /dev/null
@@ -1,851 +0,0 @@
-/* 
-   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 as a reply. oops. */
-                       /* XXXX should say to them 'oi! release that name!' */
-
-                       DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
-                       DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
-                       return;
-               }
-
-               DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
-
-               /* fine: now tell the other host they can't have the name */
-               register_ip = n->send_ip;
-               new_owner = False;
-       }
-       else
-       {
-               DEBUG(4, (" NEGATIVE RESPONSE!\n"));
-
-               /* the owner didn't want the name: the other host can have it */
-               register_ip = n->reply_to_ip;
-               new_owner = True;
-       }
-
-       /* register the old or the new owners' ip */
-       add_name_respond(d, n->fd, d->myip, n->reply_id,&n->name,n->nb_flags,
-                                       GET_TTL(0), register_ip,
-                                       new_owner, n->reply_to_ip);
-
-       remove_response_record(d,n); /* remove the response record */
-}
-
-
-/****************************************************************************
-  response from a name query to sync browse lists or to update our netbios
-  entry. states of type NAME_QUERY_SYNC and NAME_QUERY_CONFIRM 
-  ****************************************************************************/
-static void response_name_query_sync(struct nmb_packet *nmb, 
-               struct nmb_name *ans_name, BOOL bcast,
-               struct response_record *n, struct subnet_record *d)
-{
-  DEBUG(4, ("Name query at %s ip %s - ",
-           namestr(&n->name), inet_ntoa(n->send_ip)));
-
-  if (!name_equal(&n->name, ans_name))
-    {
-      /* someone gave us the wrong name as a reply. oops. */
-      DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
-      return;
-    }
-
-  if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
-    {
-      int nb_flags = nmb->answers->rdata[0];
-      struct in_addr found_ip;
-      
-      putip((char*)&found_ip,&nmb->answers->rdata[2]);
-      
-      if (!ip_equal(n->send_ip, found_ip))
-       {
-         /* someone gave us the wrong ip as a reply. oops. */
-         DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
-         DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
-         return;
-       }
-
-      DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
-      
-      if (n->state == NAME_QUERY_SYNC_LOCAL ||
-         n->state == NAME_QUERY_SYNC_REMOTE)
-       {
-         struct work_record *work = NULL;
-         /* We cheat here as we know that the workgroup name has
-            been placed in the my_comment field of the 
-            response_record struct by the code in 
-            start_sync_browse_entry().
-         */
-         if ((work = find_workgroupstruct(d, n->my_comment, False)))
-           {
-             BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL;
-             
-             /* the server is there: sync quick before it (possibly) dies! */
-             sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
-                               found_ip, local_list_only);
-           }
-       }
-      else
-       {
-          struct subnet_record *add_rec = (!bcast) ? wins_client_subnet : d;
-
-         /* update our netbios name list (re-register it if necessary) */
-         add_netbios_entry(add_rec, ans_name->name, ans_name->name_type,
-                           nb_flags,GET_TTL(0),REGISTER,
-                           found_ip,False);
-       }
-    }
-  else
-    {
-      DEBUG(4, (" NEGATIVE RESPONSE!\n"));
-      
-      if (n->state == NAME_QUERY_CONFIRM)
-       {
-         /* XXXX remove_netbios_entry()? */
-         /* lots of things we ought to do, here. if we get here,
-            then we're in a mess: our name database doesn't match
-            reality. sort it out
-             */
-         remove_netbios_name(d,n->name.name, n->name.name_type, REGISTER);
-       }
-    }
-}
-
-/****************************************************************************
-  response from a name query for DOMAIN<1b>
-  NAME_QUERY_DOMAIN is dealt with here - we are trying to become a domain
-  master browser and WINS replied - check it's our address.
-  ****************************************************************************/
-static void response_name_query_domain(struct nmb_name *ans_name,
-                struct nmb_packet *nmb,
-                struct response_record *n, struct subnet_record *d)
-{
-  DEBUG(4, ("response_name_query_domain: Got %s response from %s for query \
-for %s\n", nmb->header.rcode == 0 ? "success" : "failure",
-           inet_ntoa(n->send_ip), namestr(ans_name)));
-
-  /* Check the name is correct and ip address returned is our own. If it is then we
-     just remove the response record.
-   */
-  if (name_equal(&n->name, ans_name) && (nmb->header.rcode == 0) && nmb->answers && (nmb->answers->rdata))
-  {
-    struct in_addr found_ip;
-
-    putip((char*)&found_ip,&nmb->answers->rdata[2]);
-    /* Samba 1.9.16p11 servers seem to return the broadcast address for this
-       query. */
-    if (ismyip(found_ip) || ip_equal(wins_ip, found_ip) || ip_equal(ipzero, found_ip))
-    {
-      DEBUG(4, ("response_name_query_domain: WINS server returned our ip \
-address. Pretending we never received response.\n"));
-      n->num_msgs = 0;
-      n->repeat_count = 0;
-      n->repeat_time = 0;
-    }
-    else
-    {
-      DEBUG(0,("response_name_query_domain: WINS server already has a \
-domain master browser registered %s at address %s\n", 
-           namestr(ans_name), inet_ntoa(found_ip)));
-    }
-  }
-  else
-  {
-    /* Negative/incorrect response. No domain master
-       browser was registered - pretend we didn't get this response.
-     */
-    n->num_msgs = 0;
-    n->repeat_count = 0;
-    n->repeat_time = 0;
-  }
-
-}
-
-/****************************************************************************
-  report the response record type
-  ****************************************************************************/
-static void debug_rr_type(int rr_type)
-{
-  switch (rr_type)
-    {
-    case NMB_STATUS: DEBUG(3,("Name status ")); break;
-    case NMB_QUERY : DEBUG(3,("Name query ")); break;
-    case NMB_REG   : DEBUG(3,("Name registration ")); break;
-    case NMB_REL   : DEBUG(3,("Name release ")); break;
-    default        : DEBUG(1,("wrong response packet type received")); break;
-    }
-}
-
-/****************************************************************************
-  report the response record nmbd state
-  ****************************************************************************/
-void debug_state_type(int state)
-{
-  /* report the state type to help debugging */
-  switch (state)
-    {
-    case NAME_QUERY_DOM_SRV_CHK  : DEBUG(4,("NAME_QUERY_DOM_SRV_CHK\n")); break;
-    case NAME_QUERY_SRV_CHK      : DEBUG(4,("NAME_QUERY_SRV_CHK\n")); break;
-    case NAME_QUERY_FIND_MST     : DEBUG(4,("NAME_QUERY_FIND_MST\n")); break;
-    case NAME_QUERY_MST_CHK      : DEBUG(4,("NAME_QUERY_MST_CHK\n")); break;
-    case NAME_QUERY_CONFIRM      : DEBUG(4,("NAME_QUERY_CONFIRM\n")); break;
-    case NAME_QUERY_SYNC_LOCAL   : DEBUG(4,("NAME_QUERY_SYNC_LOCAL\n")); break;
-    case NAME_QUERY_SYNC_REMOTE  : DEBUG(4,("NAME_QUERY_SYNC_REMOTE\n")); break;
-    case NAME_QUERY_DOMAIN       : DEBUG(4,("NAME_QUERY_DOMAIN\n")); break;
-      
-    case NAME_REGISTER           : DEBUG(4,("NAME_REGISTER\n")); break;
-    case NAME_REGISTER_CHALLENGE : DEBUG(4,("NAME_REGISTER_CHALLENGE\n"));break;
-      
-    case NAME_RELEASE            : DEBUG(4,("NAME_RELEASE\n")); break;
-      
-    case NAME_STATUS_DOM_SRV_CHK : DEBUG(4,("NAME_STATUS_DOM_SRV_CHK\n")); break;
-    case NAME_STATUS_SRV_CHK     : DEBUG(4,("NAME_STATUS_SRV_CHK\n")); break;
-      
-    default: break;
-    }
-}
-
-/****************************************************************************
-  report any problems with the fact that a response has been received.
-
-  (responses for certain types of operations are only expected from one host)
-  ****************************************************************************/
-static BOOL response_problem_check(struct response_record *n,
-                       struct nmb_packet *nmb, char *ans_name)
-{
-  switch (nmb->answers->rr_type)
-    {
-    case NMB_REL:
-      {
-        if (n->num_msgs > 1)
-         {
-            DEBUG(1,("more than one release name response received!\n"));
-            return True;
-         }
-        break;
-      }
-
-    case NMB_REG:
-      {
-        if (n->num_msgs > 1)
-         {
-            DEBUG(1,("more than one register name response received!\n"));
-            return True;
-         }
-        break;
-      }
-    
-    case NMB_QUERY:
-      { 
-       if (n->num_msgs > 1)
-         {
-           if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
-             {
-               int nb_flags = nmb->answers->rdata[0];
-               
-               if ((!NAME_GROUP(nb_flags)))
-                 {
-                   /* oh dear. more than one person responded to a 
-                      unique name.
-                      there is either a network problem, a 
-                      configuration problem
-                      or a server is mis-behaving */
-                   
-                   /* XXXX mark the name as in conflict, and then let the
-                      person who just responded know that they 
-                      must also mark it
-                      as in conflict, and therefore must NOT use it.
-                      see rfc1001.txt 15.1.3.5 */
-                   
-                   /* this may cause problems for some 
-                      early versions of nmbd */
-                   
-                   switch (n->state)
-                     {
-                     case NAME_QUERY_FIND_MST:
-                       {
-                         /* query for ^1^2__MSBROWSE__^2^1 expect
-                            lots of responses */
-                         return False;
-                       }
-                     case NAME_QUERY_DOM_SRV_CHK:
-                     case NAME_QUERY_SRV_CHK:
-                     case NAME_QUERY_MST_CHK:
-                       {
-                         if (!strequal(ans_name,n->name.name))
-                           {
-                             /* one subnet, one master browser 
-                                per workgroup */
-                             /* XXXX force an election? */
-                             
-                             DEBUG(3,("more than one master browser replied!\n"));
-                             return True;
-                           }
-                         break;
-                       }
-                     default: break;
-                     }
-                   DEBUG(3,("Unique Name conflict detected!\n"));
-                   return True;
-                 }
-             }
-           else
-             {
-               /* we have received a negative reply, 
-                  having already received
-                  at least one response (pos/neg). 
-                  something's really wrong! */
-               
-               DEBUG(3,("wierd name query problem detected!\n"));
-               return True;
-             }
-         }
-      }
-    }
-  return False;
-}
-
-#if 0
-/****************************************************************************
-  check that the response received is compatible with the response record
-  ****************************************************************************/
-static BOOL response_compatible(struct response_record *n,
-                       struct nmb_packet *nmb)
-{
-  switch (n->state)
-  {
-    case NAME_RELEASE:
-    {
-               if (nmb->answers->rr_type != 0x20)
-               {
-                       DEBUG(1,("Name release reply has wrong answer rr_type\n"));
-                       return False;
-               }
-        break;
-    }
-
-    case NAME_REGISTER:
-    {
-               if (nmb->answers->rr_type != 0x20)
-               {
-                       DEBUG(1,("Name register reply has wrong answer rr_type\n"));
-                       return False;
-               }
-        break;
-    }
-
-    case NAME_REGISTER_CHALLENGE: /* this is a query: we then do a register */
-    case NAME_QUERY_CONFIRM:
-    case NAME_QUERY_SYNC_LOCAL:
-    case NAME_QUERY_SYNC_REMOTE:
-    case NAME_QUERY_DOM_SRV_CHK:
-    case NAME_QUERY_SRV_CHK:
-    case NAME_QUERY_FIND_MST:
-    case NAME_QUERY_MST_CHK:
-    {
-               if (nmb->answers->rr_type != 0x20)
-               {
-                       DEBUG(1,("Name query reply has wrong answer rr_type\n"));
-                       return False;
-               }
-               break;
-    }
-      
-    case NAME_STATUS_DOM_SRV_CHK:
-    case NAME_STATUS_SRV_CHK:
-    {
-               if (nmb->answers->rr_type != 0x21)
-               {
-                       DEBUG(1,("Name status reply has wrong answer rr_type\n"));
-                       return False;
-               }
-               break;
-    }
-      
-    default:
-    {
-               DEBUG(1,("unknown state type received in response_netbios_packet\n"));
-               return False;
-    }
-  }
-  return True;
-}
-#endif
-
-
-/****************************************************************************
-  process the response packet received
-  ****************************************************************************/
-static void response_process(struct subnet_record *d, struct packet_struct *p,
-                            struct response_record *n, struct nmb_packet *nmb,
-                            BOOL bcast, struct nmb_name *ans_name)
-{
-  switch (n->state)
-    {
-    case NAME_RELEASE:
-      {
-        response_name_release(ans_name, d, p);
-        break;
-      }
-
-    case NAME_REGISTER:
-      {
-               response_name_reg(ans_name, d, p);
-        break;
-      }
-
-    case NAME_REGISTER_CHALLENGE:
-      {
-        response_name_query_register(nmb, ans_name, n, d);
-        break;
-      }
-
-    case NAME_QUERY_DOM_SRV_CHK:
-    case NAME_QUERY_SRV_CHK:
-    case NAME_QUERY_FIND_MST:
-      {
-       response_server_check(ans_name, n, d, p);
-       break;
-      }
-    
-    case NAME_STATUS_DOM_SRV_CHK:
-    case NAME_STATUS_SRV_CHK:
-      {
-       response_name_status_check(p->ip, nmb, bcast, n, d);
-       break;
-      }
-    
-    case NAME_QUERY_CONFIRM:
-    case NAME_QUERY_SYNC_LOCAL:
-    case NAME_QUERY_SYNC_REMOTE:
-      {
-       response_name_query_sync(nmb, ans_name, bcast, n, d);
-       break;
-      }
-    case NAME_QUERY_MST_CHK:
-      {
-       /* no action required here. it's when NO responses are received
-          that we need to do something. see expire_name_query_entries() */
-       
-       DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n",
-                 namestr(&n->name), inet_ntoa(n->send_ip)));
-       break;
-      }
-   
-    case NAME_QUERY_DOMAIN:
-      {
-        /* We were asking to be a domain master browser, and someone
-           replied. If it was the WINS server and the IP it is
-           returning is our own - then remove the record and pretend
-           we didn't get a response. Else we do nothing and let 
-           dead_netbios_entry deal with it. 
-           We can only become domain master browser
-           when no broadcast responses are received and WINS
-           either contains no entry for the DOMAIN<1b> name or
-           contains our IP address.
-         */
-        response_name_query_domain(ans_name, nmb, n, d);
-        break;
-      }
-    default:
-      {
-       DEBUG(1,("unknown state type received in response_netbios_packet\n"));
-       break;
-      }
-    }
-}
-
-
-/****************************************************************************
-  response from a netbios packet.
-  ****************************************************************************/
-void response_netbios_packet(struct packet_struct *p)
-{
-  struct nmb_packet *nmb = &p->packet.nmb;
-  struct nmb_name *ans_name = NULL;
-  BOOL bcast = nmb->header.nm_flags.bcast;
-  struct response_record *n;
-  struct subnet_record *d = NULL;
-
-  if (!(n = find_response_record(&d,nmb->header.name_trn_id))) {
-    DEBUG(2,("unknown netbios response id %d (received late or from nmblookup?)\n",
-           nmb->header.name_trn_id));
-    return;
-  }
-
-  if (!d)
-    {
-      DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
-      return;
-    }
-
-  /* args wrong way round: spotted by ccm@shentel.net */
-  if (!same_net(d->bcast_ip, p->ip, d->mask_ip)) /* copes with WINS 'subnet' */
-    {
-      DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
-      DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
-    }
-  
-  if (nmb->answers == NULL) {
-         /* if there is no name is the response then the name is the one
-            we queried on */
-         ans_name = &n->name;
-  } else {
-         ans_name = &nmb->answers->rr_name;
-         debug_rr_type(nmb->answers->rr_type);
-  }
-
-  DEBUG(3,("response for %s from %s(%d) (bcast=%s)\n",
-          namestr(ans_name), inet_ntoa(p->ip), p->port, BOOLSTR(bcast)));
-  
-  n->num_msgs++; /* count number of responses received */
-  n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
-  
-  debug_state_type(n->state);
-  
-  /* problem checking: multiple responses etc */
-  if (nmb->answers && response_problem_check(n, nmb, ans_name->name))
-    return;
-  
-  /* now deal with the current state */
-  response_process(d, p, n, nmb, bcast, ans_name);
-}
diff --git a/source/nameservresp.doc b/source/nameservresp.doc
deleted file mode 100644 (file)
index 635db45..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* 
-   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: nameservresp.doc
-
-   Revision History:
-
-   0.0 - 02jul96 : lkcl@pires.co.uk
-   created
-*/
-
-this module deals with the receipt of response packets. the
-response packets are expected to be received, and there is a
-record of this kept (see also: modules nameresp and namedbresp)
-
-point of interest to design purists: every function in this
-module is static except response_netbios_packet().
-
-/*************************************************************************
-  response_netbios_packet()
-  *************************************************************************/
-
-this function receives netbios response packets. the samba server
-(or a rogue tcp/ip system, or nmblookup) will have sent out a packet
-requesting a response. a client (or a rogue tcp/ip system) responds
-to that request.
-
-this function checks the validity of the packet it receives.
-the expected response records are searched for the transaction id,
-to see if it's a response expected by the samba server. if it isn't
-it's reported as such, and ignored.
-
-if the response is found, then the subnet it was expected from will
-also have been found. the subnet it actually came in on can be
-checked against the subnet it was expected from and reported,
-otherwise this function just carries on.
-
-the number of responses received is increased, and the number of
-retries left to be sent is set to zero.
-
-after debug information is reported, and validation of the netbios
-packet (e.g only one response from one machine is expected for some
-functions) has occurred, the packet is processed. when the initial
-request was sent out, the expected response record was flagged with,
-for lack of a better word, a samba 'state' type. whenever a
-response is received, the appropriate function is called to carry on
-where the program control flow was interrupted while awaiting exactly
-such a response.
-
-please note that _not_ receiving a response is dealt with in another
-area of code - expire_netbios_response_entries().
-
-
-/*************************************************************************
-  response_name_query_sync()
-  *************************************************************************/
-
-this function receives responses to samba 'states' NAME_QUERY_SYNC and
-NAME_QUERY_CONFIRM.
-
-NAME_QUERY_SYNC: name query a server before synchronising browse lists.
-NAME_QUERY_CONFIRM: name query a server to check that it's alive.
-
-a NAME_QUERY_SYNC will be carried out in order to check that a server
-is alive before syncing browse lists. we don't want to delay the SMB
-NetServerEnum api just because the server has gone down: we have too
-much else to do.
-
-a NAME_QUERY_CONFIRM is just a name query to see whether the server is
-alive.  these queries are sent out by samba's WINS server side, to verify
-its netbios name database of all machines that have registered with it.
-
-we don't normally expect a negative response from such a query, although
-we may do so if the query was sent to another WINS server. the registered
-entry should be removed if we receive a negative response.
-
-
-/*************************************************************************
-  response_name_status_check()
-  *************************************************************************/
-
-this function receives responses to samba 'states' NAME_STATUS_SRV_CHK
-and NAME_STATUS_DOM_SRV_CHK
-
-NAME_STATUS_DOM_SRV_CHK: name status a domain master browser
-                          confirm its domain and then initiate syncing
-                          its browse list.
-
-NAME_STATUS_SRV_CHK: same as NAME_STATUS_DOM_SRV_CHK except the
-                     name status is issued to a master browser.
-
-if we don't know what workgroup a server is responsible for, but we
-know that there is a master browser at a certain ip, we can issue a
-name status check. from the response received, there will be
-a master browser netbios entry. this will allow us to synchronise
-browse lists with that machine and then add the information to the
-correct part of samba's workgroup - server database.
-
-
-/*************************************************************************
-  response_server_check()
-  *************************************************************************/
-
-this function receives responses to samba 'states' NAME_QUERY_DOM_SRV_CHK,
-NAME_QUERY_SRV_CHK and NAME_QUERY_FIND_MST.
-
-NAME_QUERY_FIND_MST: issued as a broadcast when we wish to find out all
-                     master browsers (i.e all servers that have registered
-                     the NetBIOS name ^1^2__MSBROWSE__^2(0x1), and then
-                     issue a NAME_STATUS_MASTER_CHECK on any servers that
-                     respond, which will initiate a sync browse lists.
-
-NAME_QUERY_DOM_SRV_CHK: same as a NAME_QUERY_FIND_MST except this is sent
-                        to a domain master browser.
-
-NAME_QUERY_SRV_CHK: same as a NAME_QUERY_DOM_SRV_CHK except this is sent to
-                    a master browser.
-                        
-the purpose of each of these states is to do a broadcast name query, or
-a name query directed at a WINS server, then to all hosts that respond,
-we issue a name status check, which will confirm for us the workgroup
-or domain name, and then initiate issuing a sync browse list call with
-that server.
-
-a NAME_QUERY_SRV_CHK is sent when samba receives a list of backup
-browsers. it checks to see if that server is alive (by doing a
-name query on a server) and then syncs browse lists with it.
-
-
-/*************************************************************************
-  response_name_reg()
-  *************************************************************************/
-
-this function is responsible for dealing with samba's registration
-attempts, by broadcast to a local subnet, or point-to-point with 
-another WINS server.
-
-please note that it cannot cope with END-NODE CHALLENGE REGISTRATION
-RESPONSEs at present.
-
-when a response is received, samba determines if the response is a
-positive or a negative one. if it is a positive response, the name
-is added to samba's database.
-
-when a negative response is received, samba will remove the name
-from its database. if, however, the name is a browser type (0x1b is
-a domain master browser type name; or 0x1d, which is a local master
-browser type name) then it must also stop being a domain master
-browser or master browser respectively, depending on what kind
-of name was rejected.
-
-(when no response is received, then expire_netbios_response_entries()
-is expected to deal with this. the only case that is dealt with here
-at present is when the registration was done by broadcast. if there
-is no challenge to the broadcast registration, it is implicitly
-assumed that claiming the name is acceptable).
-
-
-/*************************************************************************
-  response_name_release()
-  *************************************************************************/
-
-this function is responsible for removing samba's NetBIOS name when
-samba contacts another WINS server with which it had registered the
-name.
-
-only positive name releases are expected and dealt with. exactly what
-to do if a negative name release (i.e someone says 'oi! you have to
-keep that name!') is received is uncertain.
-
-(when no response is received, then expire_netbios_response_entries()
-is expected to deal with this. if there is no challenge to the release
-of the name, the name is then removed from that subnet's NetBIOS
-name database).
-
diff --git a/source/namework.c b/source/namework.c
deleted file mode 100644 (file)
index 540aec5..0000000
+++ /dev/null
@@ -1,724 +0,0 @@
-/* 
-   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;
-
-#define TEST_CODE /* want to debug unknown browse packets */
-
-extern int DEBUGLEVEL;
-extern pstring scope;
-extern BOOL CanRecurse;
-
-extern pstring myname;
-extern fstring myworkgroup;
-
-extern int ClientNMB;
-extern int ClientDGRAM;
-
-extern struct in_addr ipzero;
-
-extern int workgroup_count; /* total number of workgroups we know about */
-
-/* this is our domain/workgroup/server database */
-extern struct subnet_record *subnetlist;
-
-extern int  updatecount;
-
-/* backup request types: which servers are to be included */
-#define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
-#define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL   )
-
-extern time_t StartupTime;
-
-extern BOOL updatedlists;
-
-/****************************************************************************
-tell a server to become a backup browser
-state - 0x01 become backup instead of master
-      - 0x02 remove all entries in browse list and become non-master
-      - 0x04 stop master browser service altogether. NT ignores this 
-**************************************************************************/
-void reset_server(char *name, int state, struct in_addr ip)
-{
-  char outbuf[20];
-  char *p;
-
-  bzero(outbuf,sizeof(outbuf));
-  p = outbuf;
-
-  CVAL(p,0) = ANN_ResetBrowserState;
-  CVAL(p,2) = state; 
-  p += 2;
-
-  DEBUG(2,("sending reset to %s %s of state %d\n",
-          name,inet_ntoa(ip),state));
-
-  send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
-              outbuf,PTR_DIFF(p,outbuf),
-                     myname,name,0x20,0x1d,ip,*iface_ip(ip));
-}
-
-
-/****************************************************************************
-tell a server to become a backup browser
-**************************************************************************/
-void tell_become_backup(void)
-{
-  /* XXXX note: this function is currently unsuitable for use, as it
-     does not properly check that a server is in a fit state to become
-     a backup browser before asking it to be one.
-   */
-
-  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;
-         int num_servers = 0;
-         int num_backups = 0;
-         
-         for (s = work->serverlist; s; s = s->next)
-           {
-             if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
-             
-             num_servers++;
-             
-             if (is_myname(s->serv.name)) continue;
-             
-             if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
-               num_backups++;
-               continue;
-             }
-             
-             if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
-             
-             if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
-             
-             DEBUG(3,("num servers: %d num backups: %d\n", 
-                      num_servers, num_backups));
-             
-             /* make first server a backup server. thereafter make every
-                tenth server a backup server */
-             if (num_backups != 0 && (num_servers+9) / num_backups > 10)
-               {
-                 continue;
-               }
-             
-             DEBUG(2,("sending become backup to %s %s for %s\n",
-                      s->serv.name, inet_ntoa(d->bcast_ip),
-                      work->work_group));
-             
-             /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
-             do_announce_request(s->serv.name, work->work_group,
-                                 ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
-           }
-       }
-    }
-}
-
-
-/*******************************************************************
-  same context: scope. should check name_type as well, and makes sure
-  we don't process messages from ourselves
-  ******************************************************************/
-BOOL same_context(struct dgram_packet *dgram)
-{
-  if (!strequal(dgram->dest_name  .scope,scope )) return(True);
-  if ( is_myname(dgram->source_name.name)) return(True);
-  
-  return(False);
-}
-
-
-/*******************************************************************
-  process a domain announcement frame
-
-  Announce frames come in 3 types. Servers send host announcements
-  (command=1) to let the master browswer know they are
-  available. Master browsers send local master announcements
-  (command=15) to let other masters and backups that they are the
-  master. They also send domain announcements (command=12) to register
-  the domain
-
-  The comment field of domain announcements contains the master
-  browser name. The servertype is used by NetServerEnum to select
-  resources. We just have to pass it to smbd (via browser.dat) and let
-  the client choose using bit masks.
-  ******************************************************************/
-static void process_localnet_announce(struct packet_struct *p,uint16 command,char *buf)
-{
-  struct dgram_packet *dgram = &p->packet.dgram;
-  struct subnet_record *d = find_subnet(p->ip);  /* Explicitly exclude WINS - local nets only */
-  int update_count = CVAL(buf,0);
-
-  int ttl = IVAL(buf,1)/1000;
-  char *name = buf+5;
-  int osmajor=CVAL(buf,21);
-  int osminor=CVAL(buf,22);
-  uint32 servertype = IVAL(buf,23);
-  uint32 browse_type= CVAL(buf,27);
-  uint32 browse_sig = CVAL(buf,29);
-  char *comment = buf+31;
-
-  struct work_record *work;
-  char *work_name;
-  char *serv_name = dgram->source_name.name;
-  BOOL add = False;
-
-  comment[43] = 0;
-  
-  DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
-  DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
-          namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
-          servertype,browse_type,browse_sig,comment));
-  
-  name[15] = 0;  
-  
-  if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
-    {
-      DEBUG(2,("Announce to nametype(0) not supported yet\n"));
-      return;
-    }
-
-  if (command == ANN_DomainAnnouncement && 
-      ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
-       dgram->dest_name.name_type != 0x1))
-    {
-      DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
-               command, inet_ntoa(p->ip), namestr(&dgram->dest_name)));
-      return;
-    }
-  
-  if (!strequal(dgram->dest_name.scope,scope )) return;
-  
-  if (command == ANN_DomainAnnouncement) { 
-    /* XXXX if we are a master browser for the workgroup work_name,
-       then there is a local subnet configuration problem. only
-       we should be sending out such domain announcements, because
-       as the master browser, that is our job.
-
-       stop being a master browser, and force an election. this will
-       sort out the network problem. hopefully.
-     */
-
-    work_name = name;
-    add = True;
-  } else {
-    work_name = dgram->dest_name.name;
-  }
-
-  /* we need some way of finding out about new workgroups
-     that appear to be sending packets to us. The name_type checks make
-     sure we don't add host names as workgroups */
-  if (command == ANN_HostAnnouncement &&
-      (dgram->dest_name.name_type == 0x1d ||
-       dgram->dest_name.name_type == 0x1e))
-    add = True;
-  
-  DEBUG(4,("search for workgroup: %s (add? %s)\n",
-            work_name, BOOLSTR(add)));
-
-  if (!(work = find_workgroupstruct(d, work_name,add)))
-    return;
-  
-  DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
-  
-  ttl = GET_TTL(ttl);
-  
-  /* add them to our browse list, and update the browse.dat file */
-  add_server_entry(d,work,name,servertype|SV_TYPE_LOCAL_LIST_ONLY,ttl,comment,True);
-  updatedlists = True;
-
-#if 0
-  /* the tell become backup code is broken, no great harm is done by
-     disabling it */
-  tell_become_backup();
-#endif
-}
-
-/*******************************************************************
-  process a master announcement frame
-  Domain master browsers recieve these from local masters. The Domain
-  master should then issue a sync with the local master, asking for
-  that machines local server list.
-  ******************************************************************/
-static void process_master_announce(struct packet_struct *p,char *buf)
-{
-  struct dgram_packet *dgram = &p->packet.dgram;
-  char *name = buf;
-  struct work_record *work;
-  name[15] = 0;
-  
-  DEBUG(3,("process_master_announce: Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
-  
-  if (same_context(dgram)) return;
-  
-  if (!wins_client_subnet) 
-    {
-      DEBUG(3,("process_master_announce: No wins subnet !\n"));
-      return;
-    }
-  
-  if (!lp_domain_master()) 
-    {
-      DEBUG(3,("process_master_announce: Not configured as domain master - ignoring master announce.\n"));
-      return;
-    }
-  
-  for (work = wins_client_subnet->workgrouplist; work; work = work->next)
-  {
-    if (AM_MASTER(work) || AM_DOMMST(work))
-    {
-         /* merge browse lists with them */
-         add_browser_entry(name,0x1d, work->work_group,30,wins_client_subnet,p->ip,True);
-    }
-  }
-}
-
-/*******************************************************************
-  process a receive backup list request
-  
-  we receive a list of servers, and we attempt to locate them all on
-  our local subnet, and sync browse lists with them on the workgroup
-  they are said to be in.
-
-  XXXX NOTE: this function is in overdrive. it should not really do
-  half of what it actually does (it should pick _one_ name from the
-  list received and sync with it at regular intervals, rather than
-  sync with them all only once!)
-
-  ******************************************************************/
-static void process_rcv_backup_list(struct packet_struct *p,char *buf)
-{
-  struct dgram_packet *dgram = &p->packet.dgram;
-  int count = CVAL(buf,0);
-  uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
-  char *buf1;
-  
-  DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
-          namestr(&dgram->dest_name), inet_ntoa(p->ip),
-          count, info));
-  
-  if (same_context(dgram)) return;
-  
-  if (count <= 0) return;
-  
-  /* go through the list of servers attempting to sync browse lists */
-  for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
-  {
-    struct in_addr back_ip;
-    /* struct subnet_record *d; */
-      
-    DEBUG(4,("Searching for backup browser %s at %s...\n",
-              buf1, inet_ntoa(p->ip)));
-      
-    /* XXXX assume name is a DNS name NOT a netbios name. a more complete
-          approach is to use reply_name_query functionality to find the name */
-
-    back_ip = *interpret_addr2(buf1);
-      
-    if (zero_ip(back_ip))
-       {
-         DEBUG(4,("Failed to find backup browser server using DNS\n"));
-         continue;
-       }
-      
-      DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
-      DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
-      
-#if 0
-      /* XXXX function needs work */
-      continue;
-
-    if ((d = find_subnet(back_ip)))
-       {
-         struct subnet_record *d1;
-         for (d1 = subnetlist; d1; d1 = d1->next)
-         {
-             struct work_record *work;
-             for (work = d1->workgrouplist; work; work = work->next)
-               {
-                 if (work->token == 0 /* token */)
-                 {
-                     queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
-                                          work->work_group,0x1d,
-                       0,0,0,NULL,NULL,
-                                          False,False,back_ip,back_ip,
-                                          0);
-                     return;
-                 }
-               }
-         }
-       }
-#endif
-  }
-}
-
-
-/****************************************************************************
-  send a backup list response.
-  **************************************************************************/
-static void send_backup_list(char *work_name, struct nmb_name *src_name,
-                            int token, uint32 info,
-                            int name_type, struct in_addr ip)
-{                     
-  char outbuf[1024];
-  char *p, *countptr, *nameptr;
-  int count = 0;
-  char *theirname = src_name->name;
-  
-  DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", 
-          work_name, inet_ntoa(ip),
-          myname,0x0,theirname,0x0));     
-  
-  if (name_type == 0x1d)
-    {
-      DEBUG(4,("master browsers: "));
-    }
-  else if (name_type == 0x1b)
-    {
-      DEBUG(4,("domain controllers: "));
-    }
-  else
-    {
-      DEBUG(0,("backup request for unknown type %0x\n", name_type));
-      return;
-    }
-  
-  bzero(outbuf,sizeof(outbuf));
-  p = outbuf;
-  
-  CVAL(p,0) = ANN_GetBackupListResp;    /* backup list response */
-  
-  p++;
-  countptr = p;
-
-  SIVAL(p,1,info); /* the sender's unique info */
-
-  p += 5;
-  
-  nameptr = p;
-
-#if 0
-
-  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;
-         
-         if (!strequal(work->work_group, work_name)) continue;
-         
-         for (s = work->serverlist; s; s = s->next)
-           { 
-             BOOL found = False;
-             char *n;
-             
-             if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
-             
-             for (n = nameptr; n < p; n = skip_string(n, 1))
-               {
-                 if (strequal(n, s->serv.name)) found = True;
-               }
-             
-             if (found) continue; /* exclude names already added */
-             
-             /* workgroup request: include all backup browsers in the list */
-             /* domain request: include all domain members in the list */
-
-             if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
-                     (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
-               {                          
-                 DEBUG(4, ("%s ", s->serv.name));
-                 
-                 count++;
-                 strcpy(p,s->serv.name);
-                 strupper(p);
-                 p = skip_string(p,1);
-               }
-        }
-       }
-  }
-
-#endif
-
-       count++;
-       strcpy(p,myname);
-       strupper(p);
-       p = skip_string(p,1);
-
-  if (count == 0)
-    {
-      DEBUG(4, ("none\n"));
-    }
-  else
-    {
-      DEBUG(4, (" - count %d\n", count));
-    }
-  
-  CVAL(countptr, 0) = count;
-
-  {
-    int len = PTR_DIFF(p, outbuf);
-    debug_browse_data(outbuf, len);
-  }
-  send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
-              outbuf,PTR_DIFF(p,outbuf),
-                     myname,theirname,0x0,0x0,ip,*iface_ip(ip));
-}
-
-
-/*******************************************************************
-  process a send backup list request
-
-  A client sends a backup list request to ask for a list of servers on
-  the net that maintain server lists for a domain. A server is then
-  chosen from this list to send NetServerEnum commands to to list
-  available servers.
-
-  Currently samba only sends back one name in the backup list, its
-  own. For larger nets we'll have to add backups and send "become
-  backup" requests occasionally.
-  ******************************************************************/
-static void process_send_backup_list(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;
-  struct work_record *work;
-
-  int    token = CVAL(buf,0); /* sender's key index for the workgroup */
-  uint32 info  = IVAL(buf,1); /* XXXX don't know: some sort of info */
-  int name_type = dgram->dest_name.name_type;
-
-  if (same_context(dgram)) return;
-  
-  if (name_type != 0x1b && name_type != 0x1d) {
-    DEBUG(0,("backup request to wrong type %d from %s\n",
-             name_type,inet_ntoa(ip)));
-    return;
-  }
-  
-  for (d = subnetlist; d; d = d->next)
-    {
-      for (work = d->workgrouplist; work; work = work->next)
-       {
-         if (strequal(work->work_group, dgram->dest_name.name))
-           {
-             DEBUG(2,("sending backup list to %s %s id=%x\n",
-                      namestr(&dgram->dest_name),inet_ntoa(ip),info));
-  
-             send_backup_list(work->work_group,&dgram->source_name,
-                              token,info,name_type,ip);
-             return;
-           }
-       } 
-    }
-}
-
-
-/*******************************************************************
-  process a reset browser state
-
-  diagnostic packet:
-  0x1 - stop being a master browser and become a backup browser.
-  0x2 - discard browse lists, stop being a master browser, try again.
-  0x4 - stop being a master browser forever. no way. ain't gonna.
-         
-  ******************************************************************/
-static void process_reset_browser(struct packet_struct *p,char *buf)
-{
-  struct dgram_packet *dgram = &p->packet.dgram;
-  int state = CVAL(buf,0);
-
-  DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
-          namestr(&dgram->dest_name), state));
-
-  /* stop being a master but still deal with being a backup browser */
-  if (state & 0x1)
-    {
-      struct subnet_record *d;
-      for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
-       {
-         struct work_record *work;
-         for (work = d->workgrouplist; work; work = work->next)
-           {
-             if (AM_MASTER(work))
-               {
-                 unbecome_local_master(d,work,SV_TYPE_MASTER_BROWSER);
-               }
-           }
-       }
-    }
-  
-  /* XXXX documentation inconsistency: the above description does not
-     exactly tally with what is implemented for state & 0x2
-   */
-
-  /* totally delete all servers and start afresh */
-  if (state & 0x2)
-    {
-      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=remove_workgroup(d,work,True));
-       }
-      add_my_subnets(myworkgroup);
-    }
-  
-  /* stop browsing altogether. i don't think this is a good idea! */
-  if (state & 0x4)
-    {
-      DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
-    }
-}
-
-/*******************************************************************
-  process a announcement request
-
-  clients send these when they want everyone to send an announcement
-  immediately. This can cause quite a storm of packets!
-  ******************************************************************/
-static void process_announce_request(struct packet_struct *p,char *buf)
-{
-  struct dgram_packet *dgram = &p->packet.dgram;
-  struct work_record *work;
-  struct in_addr ip = dgram->header.source_ip;
-  struct subnet_record *d = find_subnet(ip); /* Explicitly NO WINS */
-  int token = CVAL(buf,0);
-  char *name = buf+1;
-  
-  name[15] = 0;
-  
-  DEBUG(3,("process_announce_request: Announce request from %s to %s token=0x%X\n",
-          name,namestr(&dgram->dest_name), token));
-  
-  if (is_myname(dgram->source_name.name)) return;
-  
-  /* XXXX BUG or FEATURE?: need to ensure that we are a member of
-     this workgroup before announcing, particularly as we only
-     respond on local interfaces anyway.
-
-     if (strequal(dgram->dest_name, myworkgroup) return; ???
-   */
-
-  if (!d) 
-    {
-      DEBUG(3,("process_announce_request: No local interface to announce to %s\n",
-                name));
-      return;
-    }
-  for (work = d->workgrouplist; work; work = work->next)
-    {
-     /* XXXX BUG: the destination name type should also be checked,
-        not just the name. e.g if the name is WORKGROUP(0x1d) then
-        we should only respond if we own that name */
-    
-      if (strequal(dgram->dest_name.name,work->work_group)) 
-       {
-         work->needannounce = True;
-       }
-    }
-}
-
-
-
-/****************************************************************************
-process a browse frame
-****************************************************************************/
-void process_browse_packet(struct packet_struct *p,char *buf,int len)
-{
-  int command = CVAL(buf,0);
-  switch (command) 
-    {
-    case ANN_HostAnnouncement:
-    case ANN_DomainAnnouncement:
-    case ANN_LocalMasterAnnouncement:
-      {
-        debug_browse_data(buf, len);
-       process_localnet_announce(p,command,buf+1);
-       break;
-      }
-      
-    case ANN_AnnouncementRequest:
-      {
-       process_announce_request(p,buf+1);
-       break;
-      }
-      
-    case ANN_Election:
-      {
-       process_election(p,buf+1);
-       break;
-      }
-      
-    case ANN_GetBackupListReq:
-      {
-        debug_browse_data(buf, len);
-       process_send_backup_list(p,buf+1);
-       break;
-      }
-      
-    case ANN_GetBackupListResp:
-    {
-        debug_browse_data(buf, len);
-        process_rcv_backup_list(p, buf+1);
-        break;
-    }
-      
-    case ANN_ResetBrowserState:
-      {
-       process_reset_browser(p, buf+1);
-       break;
-      }
-      
-    case ANN_MasterAnnouncement:
-      {
-       process_master_announce(p,buf+1);
-       break;
-      }
-      
-    default:
-      {
-       struct dgram_packet *dgram = &p->packet.dgram;
-       DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
-                command, namestr(&dgram->source_name), 
-                inet_ntoa(p->ip), namestr(&dgram->dest_name)));
-      }
-    }
-}
-
-
diff --git a/source/namework.doc b/source/namework.doc
deleted file mode 100644 (file)
index 958a86c..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/* 
-   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: namework.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 namework.c deals with NetBIOS datagram packets, primarily.
-it deals with nmbd's workgroup browser side and the domain log in
-side. none of the functionality here has specification documents available.
-empirical observation of packet traces has been the order of the day,
-along with some guess-work.
-
-beware!
-
-the receipt of datagram packets for workgroup browsing are dealt with here.
-some of the functions listed here will call others outside of this
-module, or will activate functionality dealt with by other modules
-(namedb, nameannounce, nameelect, namelogon, and namebrowse).
-
-
-/*************************************************************************
-  process_browse_packet()
-  *************************************************************************/
-
-this function is responsible for further identifying which type of
-browser datagram packet has been received, and dealing with it
-accordingly. if the packet is not dealt with, then an error is
-logged along with the type of packet that has been received.
-
-if listening_type() was in use, then it would be used here.
-
-the types of packets received and dealt with are:
-
-- ANN_HostAnnouncement         
-- ANN_DomainAnnouncement      
-- ANN_LocalMasterAnnouncement 
-
-these are all identical in format and can all be processed by
-process_announce(). an announcement is received from a host
-(either a master browser telling us about itself, a server
-telling us about itself or a master browser telling us about
-a domain / workgroup)
-
-- ANN_AnnouncementRequest      
-
-these are sent by master browsers or by servers. it is a
-request to announce ourselves as appropriate by sending
-either a ANN_HostAnnouncement datagram or both an
-ANN_DomainAnnouncement and an ANN_LocalMasterAnnouncement
-if we are a master browser (but not both).
-
-- ANN_Election                 
-
-this is an election datagram. if samba has been configured
-as a domain master then it will also send out election
-datagrams. 
-
-- ANN_GetBackupListReq         
-
-this is a request from another server for us to send a
-backup list of all servers that we know about. we respond
-by sending a datagram ANN_GetBackupListResp. the protocol
-here is a little dicey.
-
-- ANN_GetBackupListResp       
-
-this is a response from another server that we have sent an
-ANN_GetBackupListReq to. the protocol is a little dicey.
-
-- ANN_BecomeBackup            
-
-this is a message sent by a master browser to a
-potential master browser, indicating that it should become
-a backup master browser for the workgroup it is a member
-of. samba does not respond at present to such datagrams,
-and it also sends out such datagrams for the wrong reasons
-(this code has now been disabled until this is fixed).
-
-- ANN_ResetBrowserState       
-
-this datagram is sent for trouble-shooting purposes.
-it asks a browser to clear out its server lists, or to
-stop becoming a master browser altogether. NT/AS and
-samba do not implement this latter option.
-
-- ANN_MasterAnnouncement      
-
-this datagram is sent by a master browser to a domain master
-browser. it is a way to ensure that master browsers are kept in sync
-with a domain master browser across a wide area network. on
-receipt of an ANN_MasterAnnouncement we should sync browse lists with
-the sender.
-
-(i never got the hang of this one when i was experimenting.
-i forget exactly what it's for, and i never fully worked
-out how to coax a server to send it. :-)
-
-NOTE FROM TRIDGE: The reason you didn't work out how to coax a server
-into sending it is that you can't (or shouldn't try!). Basically these
-"master announce" datagrams are the way that separate netbios subnets
-are linked together to form a complete browse net. The way it works is
-that the local master decides it is going to inform the domain master
-of its presence, then sends this master announce to the domain
-master. The domain master then syncs with the local master using a
-"local only" sync. The whole transaction is initiated by the local
-master, not the domain master, so the domain master should not do any
-of this if it does not first receive a "master announcement". The
-local domain masters need to be configured to know the IP address of
-the domain master.
-
-
-/*************************************************************************
-  listening_type()
-  *************************************************************************/
-
-
-a datagram packet is sent from one NetBIOS name of a specific type
-to another NetBIOS name of a specific type. certain types of
-datagrams are only expected from certain types of NetBIOS names.
-
-this function is intended to catch errors in the type of datagrams
-received from different NetBIOS names. it is currently incomplete
-due to lack of information on the types of names and the datagrams
-they send.
-
-
-/*************************************************************************
-  process_announce_request()
-  *************************************************************************/
-
-this function is responsible for dealing with announcement requests.
-if the type of name that the request is sent to matches our current
-status, then we should respond. otherwise, the datagram should be
-ignored.
-
-samba only responds on its local subnets.
-
-at present, just the name is checked to see if the packet is for us.
-what should be done is that if we own the name (e.g WORGROUP(0x1d)
-or WORKGROUP(0x1b) then we should respond, otherwise, ignore the
-datagram.
-
-if the name is for us, and we are a member of that workgroup, then
-samba should respond.
-note that samba does not respond immediately. this is to ensure that
-if the master browser for the workgroup that samba is a member of
-sends out a broadcast request announcement, that that master browser
-is not swamped with replies. it is therefore up to samba to reply
-at some random interval. hence, a flag is set indicating the need
-to announce later.
-
-
-/*************************************************************************
-  process_reset_browser()
-  *************************************************************************/
-
-this function is responsible for dealing with reset state datagrams.
-there are three kinds of diagnostic reset requests:
-
-- stop being a master browser
-- discard browse lists, stop being a master browser, and run for re-election
-- stop being a master browser forever.
-
-samba and windows nt do not implement the latter option.
-
-there appears to be a discrepancy between this description and the
-code actually implemented.
-
-
-/*************************************************************************
-  process_send_backup_list()
-  *************************************************************************/
-
-this function is part of samba's domain master browser functionality.
-
-it is responsible for giving master browsers a list of other browsers
-that maintain backup lists of servers for that master browser's workgroup.
-
-it is also responsible for giving master browsers a list of domain master
-browsers for that local master browser's domain.
-
-a correct way to think of this function is that it is a 'request to
-send out a backup list for the requested workgroup or domain'.
-
-i have some suspicions and intuitions about this function and how it
-is to actually be used. there is no documentation on this, so it is a
-matter of experimenting until it's right.
-
-
-/*************************************************************************
-  send_backup_list()
-  *************************************************************************/
-
-this function is responsible for compiling a list of either master
-browsers and backup master browsers or domain master browsers and
-backup domain master browsers. samba constructs this list from its 
-workgroup / server database.
-
-the list is then sent to the host that requested it by sending an
-ANN_GetBackupListResp datagram to this host.
-
-
-NOTE FROM TRIDGE: The "backup list" stuff is only relevant to 
-local subnets. It has nothing to do with PDCs or domain masters. Its
-function is twofold:
-
-1) spread the browsing load over multiple servers so one server
-doesn't get overloaded with browse requests
-2) make sure the database doesn't get lost completely if the master
-goes down
-
-To accomplish this a few things are supposed to be done:
-
-- the master browser maintains a list of "backup browsers".  
-
-- backup browsers are are machines that are just like ordinary servers
-but also maintain a browse list and respond to "NetServerEnum"
-requests
-
-- when a server initially announces itself to the master it may set
-its "maintain browse list" flag to auto. 
-
-- when a master browser sees a server announcement with "auto" set it
-may send a "become backup" to that server telling it to become a
-backup.
-
-- the master has a simple algorithm to determine how many backups it wants
-given the number of hosts on the net
-
-- when a client wishes to get a browse list it asks the master for a
-backup list. The master sends it the current list of backup browsers,
-including itself. The client caches this list. The client then sends
-the NetServerEnum to a random member of this list easch time it wants
-to browse. This spreads the load.
-
-
-
-/*************************************************************************
-  process_rcv_backup_list()
-  *************************************************************************/
-
-this function is implemented with a slightly over-kill algorithm.
-the correct functionality is to pick any three names at random from
-the list that is received from this datagram, and then at intervals
-contact _one_ of them for a list of browser, in order to update
-samba's browse list.
-
-samba contacts every single one of the backup browsers listed, through
-the use of a NAME_QUERY_SRV_CHK 'state'.
-
-
-/*************************************************************************
-  process_master_announce()
-  *************************************************************************/
-
-this function is responsible for synchronising browse lists with a
-master browser that contacts samba in its capacity as a domain master
-browser.
-
-the function add_browser_entry() is used to add the server that
-contacts us to our list of browser to sync browse lists with at
-some point in the near future.
-
-
-/*************************************************************************
-  process_announce()
-  *************************************************************************/
-
-this function is responsible for dealing with the three types of
-announcement type datagrams that samba recognises. some appropriate
-type-checking is done on the name that the datagram is sent to.
-
-samba does not at present deal with LanManager announcements.
-
-these announcements are for updating the browse entry records.
-each browse entry has a time-to-live associated with it. each server
-must refresh its entry with all other servers by broadcasting
-Announcements. if it does not do so, then other servers will not
-know about that machine, and the records on each server of that
-other machine will die.
-
-if an ANN_DomainAnnouncement is received, then this will be from
-a master browser. only one machine on any given broadcast area (e.g
-a subnet) should be broadcasting such announcements. the information
-it contains tells other servers that there is a master browser for
-this workgroup. if another server thinks that it is also a master
-browser for the same workgroup, then it should stop being a master
-browser and force an election.
-
-if an ANN_LocalMasterAnnouncement is received, then a master browser
-is telling us that it exists. i am uncertain that anything else
-actually needs to be done with this, other than to shout 'hooray' and
-'thank you for informing me of this fact'.
-
-
-/*************************************************************************
-  listening_name()
-  *************************************************************************/
-
-this function is an over-simplified way of identifying whether we
-should be responding to a datagram that has been received.
-
-
-/*************************************************************************
-  same_context()
-  *************************************************************************/
-
-this function helps us to identify whether we should be responding to
-a datagram that has been received.
-
-
-/*************************************************************************
-  tell_become_backup()
-  *************************************************************************/
-
-this function is part of samba's domain master browser capabilities.
-it is responsible for finding appropriate servers to tell to become a
-backup master browser for the domain that samba controls.
-
-other servers that contact samba asking for a list of backup browsers
-will then be given that server's name, and that server can expect to
-receive NetServerEnum requests for lists of servers and workgroups.
-
-this function must be updated before it is in a fit state to be used.
-it must properly check whether a server is prepared to become a backup
-browser before actually asking it to be one.
-
-
-/*************************************************************************
-  reset_server()
-  *************************************************************************/
-
-this function is responsible for issuing an ANN_ResetBrowserState to
-the specified server, asking it to reset its browser information.
-
-see process_reset_browser() for details on this function.
-
-
index 57d0eda9b36601f3050e09f2b3384d048cbd2323..1ee9dab065855f6ab7dbea3950a5a43118e2d3ba 100644 (file)
 
 extern int DEBUGLEVEL;
 
-
 /***************************************************************************
-  add a DNS result to the name cache
-  ****************************************************************************/
+  Add a DNS result to the name cache.
+****************************************************************************/
+
 static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
 {
   int name_type = question->name_type;
   char *qname = question->name;
-
+  
+  
   if (!addr.s_addr) {
     /* add the fail to WINS cache of names. give it 1 hour in the cache */
-    DEBUG(3,("Negative DNS answer for %s\n", qname));
-    add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,60*60,
-                      DNSFAIL,addr,True);
+    DEBUG(3,("add_dns_result: Negative DNS answer for %s\n", qname));
+    add_name_to_subnet(wins_server_subnet,qname,name_type,
+                       NB_ACTIVE, 60*60, DNSFAIL_NAME, 1, &addr);
     return NULL;
   }
 
   /* add it to our WINS cache of names. give it 2 hours in the cache */
-  DEBUG(3,("DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
+  DEBUG(3,("add_dns_result: DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
 
-  return add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,
-                           2*60*60,DNS,addr, True);
+  return add_name_to_subnet(wins_server_subnet,qname,name_type,
+                            NB_ACTIVE, 2*60*60, DNS_NAME, 1, &addr);
 }
 
 
@@ -101,6 +102,23 @@ static void asyncdns_process(void)
        _exit(0);
 }
 
+/**************************************************************************** **
+  catch a sigterm
+  We need a separate term handler here so we don't release any 
+  names that our parent is going to release, or overwrite a 
+  WINS db that our parent is going to write.
+ **************************************************************************** */
+
+static int sig_term()
+{
+  BlockSignals(True,SIGTERM);
+  DEBUG(0,("async dns child. Got SIGTERM: going down...\n"));
+
+  exit(0);
+  /* Keep compiler happy.. */
+  return 0;
+}
 
 /***************************************************************************
   create a child process to handle DNS lookups
@@ -131,6 +149,7 @@ void start_async_dns(void)
        signal(SIGUSR2, SIG_IGN);
        signal(SIGUSR1, SIG_IGN);
        signal(SIGHUP, SIG_IGN);
+        signal( SIGTERM, SIGNAL_CAST sig_term );
 
        asyncdns_process();
 }
@@ -142,7 +161,7 @@ check if a particular name is already being queried
 static BOOL query_current(struct query_record *r)
 {
        return dns_current &&
-               name_equal(&r->name, 
+               nmb_name_equal(&r->name, 
                           &dns_current->packet.nmb.question.question_name);
 }
 
@@ -166,6 +185,7 @@ void run_dns_queue(void)
 {
        struct query_record r;
        struct packet_struct *p, *p2;
+       struct name_record *namerec;
        int size;
 
        if (fd_in == -1)
@@ -184,13 +204,16 @@ void run_dns_queue(void)
                return;
        }
 
-       add_dns_result(&r.name, r.result);
+       namerec = add_dns_result(&r.name, r.result);
 
        if (dns_current) {
                if (query_current(&r)) {
-                       DEBUG(3,("DNS calling reply_name_query\n"));
+                       DEBUG(3,("DNS calling send_wins_name_query_response\n"));
                        in_dns = 1;
-                       reply_name_query(dns_current);
+                        if(namerec == NULL)
+                          send_wins_name_query_response(NAM_ERR, dns_current, NULL);
+                        else
+                         send_wins_name_query_response(0,dns_current,namerec);
                        in_dns = 0;
                }
 
@@ -205,10 +228,13 @@ void run_dns_queue(void)
                struct nmb_packet *nmb = &p->packet.nmb;
                struct nmb_name *question = &nmb->question.question_name;
 
-               if (name_equal(question, &r.name)) {
-                       DEBUG(3,("DNS calling reply_name_query\n"));
+               if (nmb_name_equal(question, &r.name)) {
+                       DEBUG(3,("DNS calling send_wins_name_query_response\n"));
                        in_dns = 1;
-                       reply_name_query(p);
+                        if(namerec == NULL)
+                         send_wins_name_query_response(NAM_ERR, p, NULL);
+                        else
+                          send_wins_name_query_response(0,p,namerec);
                        in_dns = 0;
                        p->locked = False;
 
@@ -286,6 +312,10 @@ BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
        dns_ip.s_addr = interpret_addr(qname);
 
        *n = add_dns_result(question, dns_ip);
+        if(*n == NULL)
+          send_wins_name_query_response(NAM_ERR, p, NULL);
+        else
+          send_wins_name_query_response(0, p, *n);
        return False;
 }
 #endif
index a34e2caf42baf0716ab5bb66ff79ddb5aeed55eb..11cd50cd76f8732f940847ba755f0ea3263f3b37 100644 (file)
@@ -34,8 +34,8 @@ pstring servicesf = CONFIGFILE;
 
 extern pstring scope;
 
-int ClientNMB            = -1;
-int ClientDGRAM          = -1;
+int ClientNMB       = -1;
+int ClientDGRAM     = -1;
 int global_nmb_port = -1;
 
 extern pstring myhostname;
@@ -49,47 +49,47 @@ static BOOL is_daemon = False;
 
 /* what server type are we currently */
 
-time_t StartupTime =0;
+time_t StartupTime = 0;
 
 extern struct in_addr ipzero;
 
- /****************************************************************************
+/**************************************************************************** **
   catch a sigterm
 ****************************************************************************/
**************************************************************************** */
 static int sig_term()
 {
   BlockSignals(True,SIGTERM);
   
   DEBUG(0,("Got SIGTERM: going down...\n"));
   
-  /* write out wins.dat file if samba is a WINS server */
-  dump_names();
+  /* Write out wins.dat file if samba is a WINS server */
+  wins_write_database();
   
-  /* remove all samba names, with wins server if necessary. */
-  remove_my_names();
+  /* Remove all SELF registered names. */
+  release_my_names();
   
-  /* announce all server entries as 0 time-to-live, 0 type */
-  /* XXXX don't care if we never receive a response back... yet */
+  /* Announce all server entries as 0 time-to-live, 0 type. */
   announce_my_servers_removed();
 
-  /* XXXX other things: if we are a master browser, force an election? */
-  
   exit(0);
   /* Keep compiler happy.. */
   return 0;
-}
+} /* sig_term */
 
 
-/****************************************************************************
-catch a sighup
-****************************************************************************/
+/**************************************************************************** **
+ catch a sighup
+ **************************************************************************** */
 static int sig_hup(void)
 {
-  BlockSignals(True,SIGHUP);
+  BlockSignals( True, SIGHUP );
+
+  DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) );
+
+  write_browse_list( 0, True );
 
-  DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
-  dump_names();
-  reload_services(True);
+  dump_all_namelists();
+  reload_services( True );
 
   set_samba_nb_type();
 
@@ -98,239 +98,294 @@ static int sig_hup(void)
   signal(SIGHUP,SIGNAL_CAST sig_hup);
 #endif
   return(0);
-}
+} /* sig_hup */
 
-/****************************************************************************
-catch a sigpipe
-****************************************************************************/
+/**************************************************************************** **
+ catch a sigpipe
+ **************************************************************************** */
 static int sig_pipe(void)
 {
-  BlockSignals(True,SIGPIPE);
+  BlockSignals( True, SIGPIPE );
 
-  DEBUG(0,("Got SIGPIPE\n"));
-  if (!is_daemon)
+  DEBUG( 0, ("Got SIGPIPE\n") );
+  if ( !is_daemon )
     exit(1);
-  BlockSignals(False,SIGPIPE);
+  BlockSignals( False, SIGPIPE );
   return(0);
-}
+} /* sig_pipe */
 
 #if DUMP_CORE
-/*******************************************************************
-prepare to dump a core file - carefully!
-********************************************************************/
+/**************************************************************************** **
+ prepare to dump a core file - carefully!
+ **************************************************************************** */
 static BOOL dump_core(void)
 {
   char *p;
   pstring dname;
-  pstrcpy(dname,debugf);
-  if ((p=strrchr(dname,'/'))) *p=0;
-  strcat(dname,"/corefiles");
-  mkdir(dname,0700);
-  sys_chown(dname,getuid(),getgid());
-  chmod(dname,0700);
-  if (chdir(dname)) return(False);
-  umask(~(0700));
+  pstrcpy( dname, debugf );
+  if ((p=strrchr(dname,'/')))
+    *p=0;
+  strcat( dname, "/corefiles" );
+  mkdir( dname, 0700 );
+  sys_chown( dname, getuid(), getgid() );
+  chmod( dname, 0700 );
+  if ( chdir(dname) )
+    return( False );
+  umask( ~(0700) );
 
 #ifndef NO_GETRLIMIT
 #ifdef RLIMIT_CORE
   {
     struct rlimit rlp;
-    getrlimit(RLIMIT_CORE, &rlp);
-    rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
-    setrlimit(RLIMIT_CORE, &rlp);
-    getrlimit(RLIMIT_CORE, &rlp);
-    DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
+    getrlimit( RLIMIT_CORE, &rlp );
+    rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
+    setrlimit( RLIMIT_CORE, &rlp );
+    getrlimit( RLIMIT_CORE, &rlp );
+    DEBUG( 3, ( "Core limits now %d %d\n", rlp.rlim_cur, rlp.rlim_max ) );
   }
 #endif
 #endif
 
 
-  DEBUG(0,("Dumping core in %s\n",dname));
-  return(True);
-}
+  DEBUG( 0, ( "Dumping core in %s\n",dname ) );
+  return( True );
+} /* dump_core */
 #endif
 
 
-/****************************************************************************
-possibly continue after a fault
-****************************************************************************/
+/**************************************************************************** **
+ possibly continue after a fault
+ **************************************************************************** */
 static void fault_continue(void)
 {
 #if DUMP_CORE
   dump_core();
 #endif
-}
+} /* fault_continue */
 
-/*******************************************************************
 expire old names from the namelist and server list
 ******************************************************************/
+/**************************************************************************** **
+ expire old names from the namelist and server list
**************************************************************************** */
 static void expire_names_and_servers(time_t t)
 {
   static time_t lastrun = 0;
   
-  if (!lastrun) lastrun = t;
-  if (t < lastrun + 5) return;
+  if ( !lastrun )
+    lastrun = t;
+  if ( t < (lastrun + 5) )
+    return;
   lastrun = t;
-  
+
+  /*
+   * Expire any timed out names on all the broadcast
+   * subnets and those registered with the WINS server.
+   * (nmbd_namelistdb.c)
+   */
   expire_names(t);
-  expire_servers(t);
-}
 
-/*****************************************************************************
+  /*
+   * Go through all the broadcast subnets and for each
+   * workgroup known on that subnet remove any expired
+   * server names. If a workgroup has an empty serverlist
+   * and has itself timed out then remove the workgroup.
+   * (nmbd_workgroupdb.c)
+   */
+  expire_workgroups_and_servers(t);
+} /* expire_names_and_servers */
+
+/**************************************************************************** **
   reload the services file
 **************************************************************************/
**************************************************************************** */
 BOOL reload_services(BOOL test)
 {
   BOOL ret;
   extern fstring remote_machine;
 
-  strcpy(remote_machine,"nmbd");
+  strcpy( remote_machine, "nmbd" );
 
-  if (lp_loaded())
+  if ( lp_loaded() )
+  {
+    pstring fname;
+    pstrcpy( fname,lp_configfile());
+    if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
     {
-      pstring fname;
-      pstrcpy(fname,lp_configfile());
-      if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
-       {
-         pstrcpy(servicesf,fname);
-         test = False;
-       }
+      pstrcpy(servicesf,fname);
+      test = False;
     }
+  }
 
-  if (test && !lp_file_list_changed())
+  if ( test && !lp_file_list_changed() )
     return(True);
 
-  ret = lp_load(servicesf,True);
+  ret = lp_load( servicesf, True );
 
   /* perhaps the config filename is now set */
-  if (!test) {
-    DEBUG(3,("services not loaded\n"));
-    reload_services(True);
+  if ( !test )
+  {
+    DEBUG( 3, ( "services not loaded\n" ) );
+    reload_services( True );
   }
 
   /* Do a sanity check for a misconfigured nmbd */
-  if(lp_wins_support() && *lp_wins_server()) {
+  if( lp_wins_support() && *lp_wins_server() )
+  {
     DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
 cannot be set in the smb.conf file. nmbd aborting.\n"));
     exit(10);
   }
 
   return(ret);
-}
-
-
-
-/****************************************************************************
-load a netbios hosts file
-****************************************************************************/
-static void load_hosts_file(char *fname)
-{
-  FILE *f = fopen(fname,"r");
-  pstring line;
-  if (!f) {
-    DEBUG(2,("Can't open lmhosts file %s\n",fname));
-    return;
-  }
-
-  while (!feof(f))
-    {
-      pstring ip,name,flags,extra;
-      struct subnet_record *d;
-      char *ptr;
-      int count = 0;
-      struct in_addr ipaddr;
-      enum name_source source = LMHOSTS;
-
-      if (!fgets_slash(line,sizeof(pstring),f)) continue;
-
-      if (*line == '#') continue;
-
-      strcpy(ip,"");
-      strcpy(name,"");
-      strcpy(flags,"");
-      
-      ptr = line;
-      
-      if (next_token(&ptr,ip   ,NULL)) ++count;
-      if (next_token(&ptr,name ,NULL)) ++count;
-      if (next_token(&ptr,flags,NULL)) ++count;
-      if (next_token(&ptr,extra,NULL)) ++count;
-      
-      if (count <= 0) continue;
-      
-      if (count > 0 && count < 2) {
-       DEBUG(0,("Ill formed hosts line [%s]\n",line));     
-       continue;
-      }
-      
-      if (count >= 4) {
-       DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
-       continue;
-      }
-      
-      DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
-      
-      if (strchr(flags,'G') || strchr(flags,'S')) {
-       DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
-       continue;
-      }
-      
-      if (strchr(flags,'M')) {
-       source = SELF;
-       pstrcpy(myname,name);
-      }
-      
-      ipaddr = *interpret_addr2(ip);
-      d = find_subnet_all(ipaddr);
-      if (d) {
-       add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True);
-       add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True);
-      } 
-    }
-  
-  fclose(f);
-}
+} /* reload_services */
 
-
-/****************************************************************************
-  The main select loop.
-  ***************************************************************************/
+/**************************************************************************** **
+ The main select loop.
+ **************************************************************************** */
 static void process(void)
 {
   BOOL run_election;
 
-  while (True)
-    {
-      time_t t = time(NULL);
-      run_election = check_elections();
-      if(listen_for_packets(run_election))
-        return;
-
-      run_packet_queue();
-      run_elections(t);
-
-      announce_host(t);
-      announce_master(t);
-      announce_remote(t);
-      browse_sync_remote(t);
-
-      query_refresh_names(t);
-
-      expire_names_and_servers(t);
-      expire_netbios_response_entries(t);
-      refresh_my_names(t);
-
-      write_browse_list(t);
-      do_browser_lists(t);
-      check_master_browser(t);
-      add_domain_names(t);
-    }
-}
+  while( True )
+  {
+    time_t t = time(NULL);
+
+    /*
+     * Check all broadcast subnets to see if
+     * we need to run an election on any of them.
+     * (nmbd_elections.c)
+     */
+    run_election = check_elections();
+
+    /*
+     * Read incoming UDP packets.
+     * (nmbd_packets.c)
+     */
+    if(listen_for_packets(run_election))
+      return;
+
+    /*
+     * Process all incoming packets
+     * read above. This calls the success and
+     * failure functions registered when response
+     * packets arrrive, and also deals with request
+     * packets from other sources.
+     * (nmbd_packets.c)
+     */
+    run_packet_queue();
+
+    /*
+     * Run any elections - initiate becoming
+     * a local master browser if we have won.
+     * (nmbd_elections.c)
+     */
+    run_elections(t);
+
+    /*
+     * Send out any broadcast announcements
+     * of our server names. This also announces
+     * the workgroup name if we are a local
+     * master browser.
+     * (nmbd_sendannounce.c)
+     */
+    announce_my_server_names(t);
+
+    /*
+     * If we are a local master browser, periodically
+     * announce ourselves to the domain master browser.
+     * This also deals with syncronising the domain master
+     * browser server lists with ourselves as a local
+     * master browser.
+     * (nmbd_sendannounce.c)
+     */
+    announce_myself_to_domain_master_browser(t);
+
+    /*
+     * Fullfill any remote announce requests.
+     * (nmbd_sendannounce.c)
+     */
+    announce_remote(t);
+
+    /*
+     * Fullfill any remote browse sync announce requests.
+     * (nmbd_sendannounce.c)
+     */
+    browse_sync_remote(t);
+
+    /*
+     * Scan the broadcast subnets, and WINS client
+     * namelists and refresh any that need refreshing.
+     * (nmbd_mynames.c)
+     */
+    refresh_my_names(t);
+
+    /*
+     * Scan the subnet namelists and server lists and
+     * expire thos that have timed out.
+     * (nmbd.c)
+     */
+    expire_names_and_servers(t);
+
+    /*
+     * Write out a snapshot of our current browse list into
+     * the browse.dat file. This is used by smbd to service
+     * incoming NetServerEnum calls - used to synchronise
+     * browse lists over subnets.
+     * (nmbd_serverlistdb.c)
+     */
+    write_browse_list(t, False);
+
+    /*
+     * If we are a domain master browser, we have a list of
+     * local master browsers we should synchronise browse
+     * lists with (these are added by an incoming local
+     * master browser announcement packet). Expire any of
+     * these that are no longer current, and pull the server
+     * lists from each of these known local master browsers.
+     * (nmbd_browsesync.c)
+     */
+    dmb_expire_and_sync_browser_lists(t);
+
+    /*
+     * Check that there is a local master browser for our
+     * workgroup for all our broadcast subnets. If one
+     * is not found, start an election (which we ourselves
+     * may or may not participate in, depending on the
+     * setting of the 'local master' parameter.
+     * (nmbd_elections.c)
+     */
+    check_master_browser_exists(t);
+
+    /*
+     * If we are configured as a logon server, attempt to
+     * register the special NetBIOS names to become such
+     * (WORKGROUP<1c> name) on all broadcast subnets and
+     * with the WINS server (if used). If we are configured
+     * to become a domain master browser, attempt to register
+     * the special NetBIOS name (WORKGROUP<1b> name) to
+     * become such.
+     * (nmbd_become_dmb.c)
+     */
+    add_domain_names(t);
+
+    /*
+     * If we are a WINS server, do any timer dependent
+     * processing required.
+     * (nmbd_winsserver.c)
+     */
+    initiate_wins_processing(t);
+
+    /*
+     * Go through the repsonse record queue and time out or re-transmit
+     * and expired entries.
+     * (nmbd_packets.c)
+     */
+    retransmit_or_expire_response_records(t);
+  }
+} /* process */
 
 
-/****************************************************************************
 open the socket communication
-****************************************************************************/
+/**************************************************************************** **
+ open the socket communication
+ **************************************************************************** */
 static BOOL open_sockets(BOOL isdaemon, int port)
 {
   /* The sockets opened here will be used to receive broadcast
@@ -340,29 +395,29 @@ static BOOL open_sockets(BOOL isdaemon, int port)
      now deprecated.
    */
 
-  if (isdaemon)
+  if ( isdaemon )
     ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0);
   else
     ClientNMB = 0;
   
   ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0);
 
-  if (ClientNMB == -1)
-    return(False);
+  if ( ClientNMB == -1 )
+    return( False );
 
-  signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+  signal( SIGPIPE, SIGNAL_CAST sig_pipe );
 
-  set_socket_options(ClientNMB,"SO_BROADCAST");
-  set_socket_options(ClientDGRAM,"SO_BROADCAST");
+  set_socket_options( ClientNMB,   "SO_BROADCAST" );
+  set_socket_options( ClientDGRAM, "SO_BROADCAST" );
 
-  DEBUG(3,("open_sockets: Broadcast sockets opened.\n"));
-  return True;
-}
+  DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) );
+  return( True );
+} /* open_sockets */
 
 
-/****************************************************************************
 initialise connect, service and file structs
-****************************************************************************/
+/**************************************************************************** **
+ initialise connect, service and file structs
+ **************************************************************************** */
 static BOOL init_structs()
 {
   extern fstring local_machine;
@@ -372,102 +427,108 @@ static BOOL init_structs()
   int nodup;
   pstring nbname;
 
-  if (! *myname) {
-    fstrcpy(myname,myhostname);
-    p = strchr(myname,'.');
-    if (p) *p = 0;
+  if (! *myname)
+  {
+    fstrcpy( myname, myhostname );
+    p = strchr( myname, '.' );
+    if (p)
+      *p = 0;
   }
-  strupper(myname);
+  strupper( myname );
 
   /* Add any NETBIOS name aliases. Ensure that the first entry
-     is equal to myname. */
+     is equal to myname.
+   */
   /* Work out the max number of netbios aliases that we have */
-  ptr=lp_netbios_aliases();
-  for (namecount=0; next_token(&ptr,nbname,NULL); namecount++)
+  ptr = lp_netbios_aliases();
+  for( namecount=0; next_token(&ptr,nbname,NULL); namecount++ )
     ;
-  if (*myname)
-      namecount++;
+  if ( *myname )
+    namecount++;
 
   /* Allocate space for the netbios aliases */
-  if((my_netbios_names=(char **)malloc(sizeof(char *)*(namecount+1))) == NULL)
+  my_netbios_names = (char **)malloc( sizeof(char *) * (namecount+1) );
+  if( NULL == my_netbios_names )
   {
-     DEBUG(0,("init_structs: malloc fail.\n"));
-     return False;
+     DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
+     return( False );
   }
  
   /* Use the myname string first */
   namecount=0;
-  if (*myname)
+  if ( *myname )
     my_netbios_names[namecount++] = myname;
   
-  ptr=lp_netbios_aliases();
-  while (next_token(&ptr,nbname,NULL)) {
-    strupper(nbname);
+  ptr = lp_netbios_aliases();
+  while ( next_token( &ptr, nbname, NULL ) )
+  {
+    strupper( nbname );
     /* Look for duplicates */
     nodup=1;
-    for(n=0; n<namecount; n++) {
-      if (strcmp(nbname, my_netbios_names[n])==0)
+    for( n=0; n<namecount; n++ )
+    {
+      if( 0 == strcmp( nbname, my_netbios_names[n] ) )
         nodup=0;
     }
     if (nodup)
-      my_netbios_names[namecount++]=strdup(nbname);
+      my_netbios_names[namecount++] = strdup( nbname );
   }
   
   /* Check the strdups succeeded. */
-  for(n = 0; n < namecount; n++)
-    if(my_netbios_names[n]==NULL)
+  for( n = 0; n < namecount; n++ )
+    if( NULL == my_netbios_names[n] )
     {
       DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
       return False;
     }
   
   /* Terminate name list */
-  my_netbios_names[namecount++]=NULL;
+  my_netbios_names[namecount++] = NULL;
   
-  fstrcpy(local_machine,myname);
-  trim_string(local_machine," "," ");
-  p = strchr(local_machine,' ');
-  if (p) 
+  fstrcpy( local_machine, myname );
+  trim_string( local_machine, " ", " " );
+  p = strchr( local_machine, ' ' );
+  if (p)
     *p = 0;
-  strlower(local_machine);
+  strlower( local_machine );
 
-  DEBUG(5, ("Netbios name list:-\n"));
-  for (n=0; my_netbios_names[n]; n++)
-    DEBUG(5, ("my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n]));
+  DEBUG( 5, ("Netbios name list:-\n") );
+  for( n=0; my_netbios_names[n]; n++ )
+    DEBUG( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n] ) );
 
-  return True;
-}
+  return( True );
+} /* init_structs */
 
-/****************************************************************************
-usage on the program
-****************************************************************************/
+/**************************************************************************** **
+ usage on the program
+ **************************************************************************** */
 static void usage(char *pname)
 {
   DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
 
-  printf("Usage: %s [-n name] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
-  printf("Version %s\n",VERSION);
-  printf("\t-D                    become a daemon\n");
-  printf("\t-p port               listen on the specified port\n");
-  printf("\t-d debuglevel         set the debuglevel\n");
-  printf("\t-l log basename.      Basename for log/debug files\n");
-  printf("\t-n netbiosname.       the netbios name to advertise for this host\n");
-  printf("\t-H hosts file        load a netbios hosts file\n");
-  printf("\n");
-}
-
-
-/****************************************************************************
-  main program
-  **************************************************************************/
- int main(int argc,char *argv[])
+  printf( "Usage: %s [-n name] [-D] [-p port] [-d debuglevel] ", pname );
+  printf( "[-l log basename]\n" );
+  printf( "Version %s\n", VERSION );
+  printf( "\t-D                    become a daemon\n" );
+  printf( "\t-p port               listen on the specified port\n" );
+  printf( "\t-d debuglevel         set the debuglevel\n" );
+  printf( "\t-l log basename.      Basename for log/debug files\n" );
+  printf( "\t-n netbiosname.       " );
+  printf( "the netbios name to advertise for this host\n");
+  printf( "\t-H hosts file         load a netbios hosts file\n" );
+  printf( "\n");
+} /* usage */
+
+
+/**************************************************************************** **
+ main program
+ **************************************************************************** */
+int main(int argc,char *argv[])
 {
   int opt;
   extern FILE *dbf;
   extern char *optarg;
-  char pidFile[100];
-
-  *pidFile = '\0';
+  char pidFile[100] = { 0 };
 
   global_nmb_port = NMB_PORT;
   *host_file = 0;
@@ -476,186 +537,208 @@ static void usage(char *pname)
 
   TimeInit();
 
-  strcpy(debugf,NMBLOGFILE);
+  strcpy( debugf, NMBLOGFILE );
 
-  setup_logging(argv[0],False);
+  setup_logging( argv[0], False );
 
   charset_initialise();
 
 #ifdef LMHOSTSFILE
-  strcpy(host_file,LMHOSTSFILE);
+  strcpy( host_file, LMHOSTSFILE );
 #endif
 
   /* this is for people who can't start the program correctly */
-  while (argc > 1 && (*argv[1] != '-')) {
+  while (argc > 1 && (*argv[1] != '-'))
+  {
     argv++;
     argc--;
   }
 
-  fault_setup(fault_continue);
+  fault_setup( fault_continue );
 
-  signal(SIGHUP ,SIGNAL_CAST sig_hup);
-  signal(SIGTERM,SIGNAL_CAST sig_term);
+  signal( SIGHUP,  SIGNAL_CAST sig_hup );
+  signal( SIGTERM, SIGNAL_CAST sig_term );
 
-  while ((opt = getopt(argc, argv, "as:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
+  while((opt = getopt(argc, argv, "as:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
     {
       switch (opt)
-       {
+        {
         case 'f':
           strncpy(pidFile, optarg, sizeof(pidFile));
           break;
-       case 's':
-         pstrcpy(servicesf,optarg);
-         break;          
-       case 'N':
-       case 'B':
-       case 'I':
-       case 'C':
-       case 'G':
-         DEBUG(0,("Obsolete option '%c' used\n",opt));
-         break;
-       case 'H':
-         pstrcpy(host_file,optarg);
-         break;
-       case 'n':
-         pstrcpy(myname,optarg);
-         strupper(myname);
-         break;
-       case 'l':
-         sprintf(debugf,"%s.nmb",optarg);
-         break;
-       case 'i':
-         pstrcpy(scope,optarg);
-         strupper(scope);
-         break;
-       case 'a':
-               {
-                       extern BOOL append_log;
-                       append_log = !append_log;
-               }
-               break;
-       case 'D':
-         is_daemon = True;
-         break;
-       case 'd':
-         DEBUGLEVEL = atoi(optarg);
-         break;
-       case 'p':
-         global_nmb_port = atoi(optarg);
-         break;
-       case 'h':
-         usage(argv[0]);
-         exit(0);
-         break;
-       default:
-         if (!is_a_socket(0)) {
-           usage(argv[0]);
-         }
-         break;
-       }
+        case 's':
+          pstrcpy(servicesf,optarg);
+          break;          
+        case 'N':
+        case 'B':
+        case 'I':
+        case 'C':
+        case 'G':
+          DEBUG(0,("Obsolete option '%c' used\n",opt));
+          break;
+        case 'H':
+          pstrcpy(host_file,optarg);
+          break;
+        case 'n':
+          pstrcpy(myname,optarg);
+          strupper(myname);
+          break;
+        case 'l':
+          sprintf(debugf,"%s.nmb",optarg);
+          break;
+        case 'i':
+          pstrcpy(scope,optarg);
+          strupper(scope);
+          break;
+        case 'a':
+          {
+          extern BOOL append_log;
+          append_log = !append_log;
+          }
+          break;
+        case 'D':
+          is_daemon = True;
+          break;
+        case 'd':
+          DEBUGLEVEL = atoi(optarg);
+          break;
+        case 'p':
+          global_nmb_port = atoi(optarg);
+          break;
+        case 'h':
+          usage(argv[0]);
+          exit(0);
+          break;
+        default:
+          if (!is_a_socket(0))
+          {
+            usage(argv[0]);
+          }
+          break;
+        }
     }
 
   DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
   DEBUG(1,("Copyright Andrew Tridgell 1994-1997\n"));
 
-  if(!get_myname(myhostname,NULL))
+  if( !get_myname( myhostname, NULL) )
   {
     DEBUG(0,("Unable to get my hostname - exiting.\n"));
     return -1;
   }
 
-#ifndef SYNC_DNS
-  start_async_dns();
-#endif
-
-  if (!reload_services(False))
-    return(-1);        
+  if ( !reload_services(False) )
+    return(-1);
 
   codepage_initialise(lp_client_code_page());
 
   if(!init_structs())
     return -1;
 
-  reload_services(True);
+  reload_services( True );
 
-  pstrcpy(myworkgroup, lp_workgroup());
+  fstrcpy( myworkgroup, lp_workgroup() );
 
-  if (strequal(myworkgroup,"*")) {
+  if (strequal(myworkgroup,"*"))
+  {
     DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
     exit(1);
   }
 
   set_samba_nb_type();
 
-  if (!is_daemon && !is_a_socket(0)) {
+  if (!is_daemon && !is_a_socket(0))
+  {
     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
     is_daemon = True;
   }
   
-  if (is_daemon) {
+  if (is_daemon)
+  {
     DEBUG(2,("%s becoming a daemon\n",timestring()));
     become_daemon();
   }
 
-  if (!directory_exist(lp_lockdir(), NULL)) {
-         mkdir(lp_lockdir(), 0755);
+  if (!directory_exist(lp_lockdir(), NULL))
+  {
+    mkdir(lp_lockdir(), 0755);
   }
 
   if (*pidFile)
-    {
-      int     fd;
-      char    buf[20];
+  {
+    int     fd;
+    char    buf[20];
 
-      if ((fd = open(pidFile,
 #ifdef O_NONBLOCK
-        O_NONBLOCK | 
+    fd = open( pidFile, O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644 );
+#else
+    fd = open( pidFile, O_CREAT | O_WRONLY | O_TRUNC, 0644 );
 #endif
-        O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
-        {
-          DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
-          exit(1);
-        }
-      if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
-        {
-          DEBUG(0,("ERROR: nmbd is already running\n"));
-          exit(1);
-        }
-      sprintf(buf, "%u\n", (unsigned int) getpid());
-      if (write(fd, buf, strlen(buf)) < 0)
-        {
-          DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
-          exit(1);
-        }
-      /* Leave pid file open & locked for the duration... */
+    if ( fd < 0 )
+    {
+      DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
+      exit(1);
     }
+    if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
+    {
+      DEBUG(0,("ERROR: nmbd is already running\n"));
+      exit(1);
+    }
+    sprintf(buf, "%u\n", (unsigned int) getpid());
+    if (write(fd, buf, strlen(buf)) < 0)
+    {
+      DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
+      exit(1);
+    }
+      /* Leave pid file open & locked for the duration... */
+  }
 
 
-  DEBUG(3,("Opening sockets %d\n", global_nmb_port));
+  DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
 
-  if (!open_sockets(is_daemon,global_nmb_port)) return 1;
+  if ( !open_sockets( is_daemon, global_nmb_port ) )
+    return 1;
 
+  /* Determine all the IP addresses we have. */
   load_interfaces();
-  add_my_subnets(myworkgroup);
-
-  add_my_names();
 
-  DEBUG(3,("Checked names\n"));
-  
-  load_netbios_names();
-
-  DEBUG(3,("Loaded names\n"));
+  /* Create an nmbd subnet record for each of the above. */
+  if( False == create_subnets() )
+  {
+    DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
+    exit(1);
+  }
 
-  if (*host_file) {
-    load_hosts_file(host_file);
+  /* Load in any static local names. */ 
+  if ( *host_file )
+  {
+    load_lmhosts_file(host_file);
     DEBUG(3,("Loaded hosts file\n"));
   }
 
-  write_browse_list(time(NULL));
+  /* If we are acting as a WINS server, initialise data structures. */
+  if( !initialise_wins() )
+  {
+    DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
+    exit(1);
+  }
 
-  DEBUG(3,("Dumped names\n"));
+  /* 
+   * Register nmbd primary workgroup and nmbd names on all
+   * the broadcast subnets, and on the WINS server (if specified).
+   * Also initiate the startup of our primary workgroup (start
+   * elections if we are setup as being able to be a local
+   * master browser.
+   */
+
+  if( False == register_my_workgroup_and_names() )
+  {
+    DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
+    exit(1);
+  }
 
   /* We can only take sigterm signals in the select. */
-  BlockSignals(True,SIGTERM);
+  BlockSignals( True, SIGTERM );
 
   process();
   close_sockets();
@@ -663,4 +746,6 @@ static void usage(char *pname)
   if (dbf)
     fclose(dbf);
   return(0);
-}
+} /* main */
+
+/* ========================================================================== */
diff --git a/source/nmbd/nmbd_become_dmb.c b/source/nmbd/nmbd_become_dmb.c
new file mode 100644 (file)
index 0000000..37fceb9
--- /dev/null
@@ -0,0 +1,471 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+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 allones_ip;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+static void become_domain_master_browser_bcast(char *);
+
+/*******************************************************************
+  Unbecome a domain master browser - name release success function.
+  ******************************************************************/
+
+static void unbecome_dmb_success(struct subnet_record *subrec,
+                                 struct userdata_struct *userdata,
+                                 struct nmb_name *released_name,
+                                 struct in_addr released_ip)
+{
+  struct work_record *work = find_workgroup_on_subnet(subrec, released_name->name);
+  struct server_record *servrec;
+
+  if(!work)
+  {
+    DEBUG(0,("unbecome_dmb_success: Cannot find workgroup %s on subnet %s\n",
+             released_name->name, subrec->subnet_name));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("unbecome_dmb_success: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, released_name->name, subrec->subnet_name));
+    return;
+  }
+
+  /* Set the state in the workgroup structure. */
+  work->dom_state = DOMAIN_NONE;
+
+  /* Update our server status. */
+  servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
+
+  /* Tell the namelist writer to write out a change. */
+  subrec->work_changed = True;
+
+  /* Remove any list of local master browsers we are syncing with. */
+  remove_workgroup_lmb_browsers(released_name->name);
+
+  /* Delete the known domain master browser name from the workgroup
+     struct. */
+  bzero((char *)&work->dmb_name, sizeof(work->dmb_name));
+  putip((char *)&work->dmb_addr, &ipzero);
+
+  DEBUG(0,("\n ***** Samba server %s has stopped being a domain master browser \
+for workgroup %s on subnet %s *****\n\n", myname, work->work_group, subrec->subnet_name));
+
+}
+
+/*******************************************************************
+  Unbecome a domain master browser - name release fail function.
+  ******************************************************************/
+
+static void unbecome_dmb_fail(struct subnet_record *subrec,
+                                 struct response_record *rrec,
+                                 struct nmb_name *released_name)
+{
+  DEBUG(0,("unbecome_dmb_fail: Failed to unbecome domain master browser for \
+workgroup %s on subnet %s.\n", released_name->name, subrec->subnet_name));
+}
+
+/*******************************************************************
+  Unbecome a domain master browser.
+  ******************************************************************/
+
+void unbecome_domain_master(char *workgroup_name)
+{   
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
+
+    if(work && (work->dom_state == DOMAIN_MST))
+    {
+      struct name_record *namerec;
+      struct nmb_name nmbname;
+      make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
+
+      /* We can only do this if we are a domain master already. */
+      DEBUG(2,("unbecome_domain_master: attempting to stop being a domain \
+master browser for workgroup %s on subnet %s\n",
+              work->work_group, subrec->subnet_name));
+   
+      /* Find the WORKGROUP<1b> name on the subnet namelist. */
+      if((namerec = find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME))==NULL)
+      {
+        DEBUG(0,("unbecome_domain_master: Cannot find name %s on subnet %s.\n",
+                namestr(&nmbname), subrec->subnet_name));
+        continue;
+      }
+      release_name(subrec, namerec, 
+                   unbecome_dmb_success,
+                   unbecome_dmb_fail,
+                   NULL);
+    }
+  }
+} 
+
+/****************************************************************************
+  Fail to become a Domain Master Browser on a subnet.
+  ****************************************************************************/
+
+static void become_domain_master_fail(struct subnet_record *subrec,
+                                      struct response_record *rrec,
+                                      struct nmb_name *fail_name)
+{
+  struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
+  struct server_record *servrec;
+
+  if(!work)
+  {
+    DEBUG(0,("become_domain_master_fail: Error - cannot find \
+workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
+    return;
+  }
+
+  /* Set the state back to DOMAIN_NONE. */
+  work->dom_state = DOMAIN_NONE;
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, work->work_group, subrec->subnet_name));
+    return;
+  }
+
+  /* Update our server status. */
+  servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
+
+  /* Tell the namelist writer to write out a change. */
+  subrec->work_changed = True;
+
+  DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+       work->work_group, subrec->subnet_name, namestr(fail_name)));
+}
+
+/****************************************************************************
+  Become a Domain Master Browser on a subnet.
+  ****************************************************************************/
+
+static void become_domain_master_stage2(struct subnet_record *subrec, 
+                                        struct userdata_struct *userdata,
+                                        struct nmb_name *registered_name,
+                                        uint16 nb_flags,
+                                        int ttl, struct in_addr registered_ip)
+{
+  struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
+  struct server_record *servrec;
+
+  if(!work)
+  {
+    DEBUG(0,("become_domain_master_stage2: Error - cannot find \
+workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
+in workgroup %s on subnet %s\n", 
+       myname, registered_name->name, subrec->subnet_name));
+    work->dom_state = DOMAIN_NONE;
+    return;
+  }
+
+  /* Set the state in the workgroup structure. */
+  work->dom_state = DOMAIN_MST; /* Become domain master. */
+
+  /* Update our server status. */
+  servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
+
+  /* Tell the namelist writer to write out a change. */
+  subrec->work_changed = True;
+
+  DEBUG(0,("\n ***** Samba server %s is now a domain master browser \
+for workgroup %s on subnet %s *****\n\n", myname, work->work_group, subrec->subnet_name));
+
+  if(subrec == unicast_subnet)
+  {
+    struct nmb_name nmbname;
+    struct in_addr my_first_ip;
+
+    /* Put our name and first IP address into the 
+       workgroup struct as domain master browser. This
+       will stop us syncing with ourself if we are also
+       a local master browser. */
+
+    make_nmb_name(&nmbname, myname, 0x20, scope);
+
+    work->dmb_name = nmbname;
+    /* Pick the first interface ip address as the domain master browser ip. */
+    my_first_ip = *iface_n_ip(0);
+
+    putip((char *)&work->dmb_addr, &my_first_ip);
+
+    /* 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 docs/DOMAIN.txt.
+
+     */
+    become_domain_master_browser_bcast(work->work_group);
+  }
+}
+
+/****************************************************************************
+  Start the name registration process when becoming a Domain Master Browser
+  on a subnet.
+  ****************************************************************************/
+
+static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name)
+{ 
+  struct work_record *work;
+
+  DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
+workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
+
+  /* First, find the workgroup on the subnet. */
+  if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL)
+  {
+    DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
+          wg_name, subrec->subnet_name));
+    return;
+  }
+
+  DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
+  work->dom_state = DOMAIN_WAIT;
+
+  /* WORKGROUP<1b> is the domain master browser name. */
+  register_name(subrec, work->work_group,0x1b,samba_nb_type,
+                become_domain_master_stage2,
+                become_domain_master_fail, NULL);
+}
+
+/****************************************************************************
+  Function called when a query for a WORKGROUP<1b> name succeeds.
+  This is normally a fail condition as it means there is already
+  a domain master browser for a workgroup and we were trying to
+  become one.
+****************************************************************************/
+
+static void become_domain_master_query_success(struct subnet_record *subrec,
+                        struct userdata_struct *userdata,
+                        struct nmb_name *nmbname, struct in_addr ip, 
+                        struct res_rec *rrec)
+{
+  /* If the given ip is not ours, then we can't become a domain
+     controler as the name is already registered.
+   */
+
+ /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
+    address or zero ip for this query. Pretend this is ok. */
+
+  if(ismyip(ip) || ip_equal(allones_ip, ip) || ip_equal(ipzero, ip))
+  {
+    DEBUG(3,("become_domain_master_query_success: Our address (%s) returned \
+in query for name %s (domain master browser name) on subnet %s. \
+Continuing with domain master code.\n", 
+           inet_ntoa(ip), namestr(nmbname), subrec->subnet_name));
+
+    become_domain_master_stage1(subrec, nmbname->name);
+  }
+  else
+  {
+    DEBUG(0,("become_domain_master_query_success: There is already a domain \
+master browser at IP %s for workgroup %s registered on subnet %s.\n",
+          inet_ntoa(ip), nmbname->name, subrec->subnet_name));
+  }
+}
+
+/****************************************************************************
+  Function called when a query for a WORKGROUP<1b> name fails.
+  This is normally a success condition as it then allows us to register
+  our own Domain Master Browser name.
+  ****************************************************************************/
+
+static void become_domain_master_query_fail(struct subnet_record *subrec,
+                                    struct response_record *rrec,
+                                    struct nmb_name *question_name, int fail_code)
+{
+  /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
+     then this is a failure. Otherwise, not finding the name is what we want. */
+  if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
+  {
+    DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
+querying WINS server for name %s.\n", 
+                  fail_code, namestr(question_name)));
+    return;
+  }
+
+  /* Otherwise - not having the name allows us to register it. */
+  become_domain_master_stage1(subrec, question_name->name);
+}
+
+/****************************************************************************
+  Attempt to become a domain master browser on all broadcast subnets.
+  ****************************************************************************/
+
+static void become_domain_master_browser_bcast(char *workgroup_name)
+{
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  { 
+    struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
+
+    if (work && (work->dom_state == DOMAIN_NONE))
+    {
+      struct nmb_name nmbname;
+      make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
+
+      /*
+       * Check for our name on the given broadcast subnet first, only initiate
+       * further processing if we cannot find it.
+       */
+
+      if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
+      {
+        DEBUG(0,("become_domain_master_browser_bcast: At time %s attempting to become domain \
+master browser on workgroup %s on subnet %s\n", timestring(), 
+                 workgroup_name, subrec->subnet_name));
+
+        /* Send out a query to establish whether there's a 
+           domain controller on the local subnet. If not,
+           we can become a domain controller. 
+         */
+
+        DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
+for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
+
+        query_name(subrec, nmbname.name, nmbname.name_type,
+                   become_domain_master_query_success, 
+                   become_domain_master_query_fail,
+                   NULL);
+      }
+    }
+  }
+}
+
+/****************************************************************************
+  Attempt to become a domain master browser by registering with WINS.
+  ****************************************************************************/
+
+static void become_domain_master_browser_wins(char *workgroup_name)
+{
+  struct work_record *work;
+
+  work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
+
+  if (work && (work->dom_state == DOMAIN_NONE))
+  {
+    struct nmb_name nmbname;
+
+    make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
+
+    /*
+     * Check for our name on the unicast subnet first, only initiate
+     * further processing if we cannot find it.
+     */
+
+    if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
+    {
+      DEBUG(0,("%s become_domain_master_browser_wins: attempting to become domain \
+master browser on workgroup %s, subnet %s.\n",
+      timestring(), workgroup_name, unicast_subnet->subnet_name));
+
+      /* Send out a query to establish whether there's a 
+         domain master broswer registered with WINS. If not,
+         we can become a domain master browser. 
+       */
+
+      DEBUG(0,("become_domain_master_browser_wins: querying WINS server at IP %s \
+for domain master browser name %s on workgroup %s\n",
+         inet_ntoa(unicast_subnet->myip), namestr(&nmbname), workgroup_name));
+
+      query_name(unicast_subnet, nmbname.name, nmbname.name_type,
+                   become_domain_master_query_success,
+                   become_domain_master_query_fail,
+                   NULL);
+    }
+  }
+}
+
+/****************************************************************************
+  Add the domain logon server and domain master browser names
+  if we are set up to do so.
+  **************************************************************************/
+
+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. */
+  if (lp_domain_logons())
+    add_logon_names();
+
+  /* Do the domain master names. */
+  if(lp_domain_master())
+  {
+    if(we_are_a_wins_client())
+    {
+      /* We register the WORKGROUP<1b> name with the WINS
+         server first, and call add_domain_master_bcast()
+         only if this is successful.
+
+         This results in domain logon services being gracefully provided,
+         as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
+         1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
+         cannot provide domain master / domain logon services.
+       */
+      become_domain_master_browser_wins(myworkgroup);
+    }
+    else
+      become_domain_master_browser_bcast(myworkgroup);
+  }
+}
diff --git a/source/nmbd/nmbd_become_lmb.c b/source/nmbd/nmbd_become_lmb.c
new file mode 100644 (file)
index 0000000..7f54471
--- /dev/null
@@ -0,0 +1,534 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+extern pstring myname;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
+
+/*******************************************************************
+ Utility function to add a name to the unicast subnet, or add in
+ our IP address if it already exists.
+******************************************************************/
+
+static void insert_permanent_name_into_unicast( struct subnet_record *subrec, 
+                                                struct nmb_name *nmbname, uint16 nb_type )
+{
+  struct name_record *namerec;
+
+  if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL)
+  {
+    /* The name needs to be created on the unicast subnet. */
+    add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type,
+                        nb_type, PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
+  }
+  else
+  {
+    /* The name already exists on the unicast subnet. Add our local
+       IP for the given broadcast subnet to the name. */
+    add_ip_to_name_record( namerec, subrec->myip);
+  }
+}
+
+/*******************************************************************
+ Utility function to remove a name from the unicast subnet.
+******************************************************************/
+
+static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
+                                                struct nmb_name *nmbname )
+{
+  struct name_record *namerec;
+
+  if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL)
+  {
+    /* Remove this broadcast subnet IP address from the name. */
+    remove_ip_from_name_record( namerec, subrec->myip);
+    if(namerec->num_ips == 0)
+      remove_name_from_namelist( unicast_subnet, namerec);
+  }
+}
+
+/*******************************************************************
+ Utility function always called to set our workgroup and server
+ state back to potential browser, or none.
+******************************************************************/
+
+static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name )
+{
+  struct work_record *work;
+  struct server_record *servrec;
+  struct nmb_name nmbname;
+
+  if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL)
+  {
+    DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
+subnet %s.\n", workgroup_name, subrec->subnet_name ));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, work->work_group, subrec->subnet_name));
+    work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+    return;
+  }
+
+  /* Update our server status - remove any master flag and replace
+   it with the potential browser flag. */
+  servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
+  servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
+
+  /* Tell the namelist writer to write out a change. */
+  subrec->work_changed = True;
+
+  /* Reset our election flags. */
+  work->ElectionCriterion &= ~0x4;
+
+  work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+
+  /* Forget who the local master browser was for
+     this workgroup. */
+
+  *work->local_master_browser_name = '\0';
+
+  /*
+   * Ensure the IP address of this subnet is not registered as one
+   * of the IP addresses of the WORKGROUP<1d> name on the unicast
+   * subnet. This undoes what we did below when we became a local
+   * master browser.
+   */
+
+  make_nmb_name(&nmbname, work->work_group, 0x1d, scope);
+
+  remove_permanent_name_from_unicast( subrec, &nmbname);
+
+}
+
+/*******************************************************************
+  Unbecome the local master browser name release success function.
+******************************************************************/
+
+void unbecome_local_master_success(struct subnet_record *subrec,
+                             struct userdata_struct *userdata,
+                             struct nmb_name *released_name,
+                             struct in_addr released_ip)
+{ 
+  DEBUG(3,("unbecome_local_master_success: released name %s.\n",
+             namestr(released_name)));
+
+  /* Now reset the workgroup and server state. */
+  reset_workgroup_state( subrec, released_name->name );
+
+  DEBUG(0,("\n*****   Samba name server %s has stopped being a local master browser for workgroup %s \
+on subnet %s *****\n\n", myname, released_name->name, subrec->subnet_name));
+
+}
+
+/*******************************************************************
+  Unbecome the local master browser name release fail function.
+******************************************************************/
+
+void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
+                       struct nmb_name *fail_name)
+{
+  struct name_record *namerec;
+
+  DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
+Removing from namelist anyway.\n", namestr(fail_name)));
+
+  /* Do it anyway. */
+  namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
+  if(namerec)
+    remove_name_from_namelist(subrec, namerec);
+
+  /* Now reset the workgroup and server state. */
+  reset_workgroup_state( subrec, fail_name->name );
+
+  DEBUG(0,("\n*****   Samba name server %s has stopped being a local master browser for workgroup %s \
+on subnet %s *****\n\n", myname, fail_name->name, subrec->subnet_name));
+
+}
+
+/*******************************************************************
+ Utility function to remove the WORKGROUP<1d> name called by both
+ success and fail of releasing the MSBROWSE name.
+******************************************************************/
+
+void release_1d_name( struct subnet_record *subrec, char *workgroup_name)
+{
+  struct nmb_name nmbname;
+  struct name_record *namerec;
+
+  make_nmb_name(&nmbname, workgroup_name, 0x1d, scope);
+  if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
+  {
+    release_name(subrec, namerec,
+                 unbecome_local_master_success,
+                 unbecome_local_master_fail,
+                 NULL);
+  }
+}
+
+/*******************************************************************
+ Unbecome the local master browser MSBROWSE name release success function.
+******************************************************************/
+
+static void release_msbrowse_name_success(struct subnet_record *subrec,
+                      struct userdata_struct *userdata,
+                      struct nmb_name *released_name,
+                      struct in_addr released_ip)
+{
+  DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
+           namestr(released_name), subrec->subnet_name ));
+
+  /* Remove the permanent MSBROWSE name added into the unicast subnet. */
+  remove_permanent_name_from_unicast( subrec, released_name);
+
+  release_1d_name( subrec, userdata->data );
+}
+
+/*******************************************************************
+ Unbecome the local master browser MSBROWSE name release fail function.
+******************************************************************/
+
+static void release_msbrowse_name_fail( struct subnet_record *subrec, 
+                       struct response_record *rrec,
+                       struct nmb_name *fail_name)
+{
+  struct userdata_struct *userdata = rrec->userdata;
+  struct name_record *namerec;
+
+  DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
+           namestr(fail_name), subrec->subnet_name ));
+
+  /* Release the name anyway. */
+  namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
+  if(namerec)
+    remove_name_from_namelist(subrec, namerec);
+
+  /* Remove the permanent MSBROWSE name added into the unicast subnet. */
+  remove_permanent_name_from_unicast( subrec, fail_name);
+
+  release_1d_name( subrec, userdata->data );
+}
+
+/*******************************************************************
+  Unbecome the local master browser.
+******************************************************************/
+
+void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work)
+{
+  struct server_record *servrec;
+  struct name_record *namerec;
+  struct nmb_name nmbname;
+  struct userdata_struct *userdata;
+  char ud[sizeof(struct userdata_struct) + sizeof(fstring)+1];
+
+  /* Sanity check. */
+
+  DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
+on subnet %s\n",work->work_group, subrec->subnet_name));
+  
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, work->work_group, subrec->subnet_name));
+    work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+    return;
+  }
+  
+  /* Set the state to unbecoming. */
+  work->mst_state = MST_UNBECOMING_MASTER;
+
+  /* Setup the userdata for the MSBROWSE name release. */
+  /* Setup the userdata_struct - this is copied so we can use
+     a stack variable for this. */
+  userdata = (struct userdata_struct *)ud;
+
+  userdata->copy_fn = NULL;
+  userdata->free_fn = NULL;
+  userdata->userdata_len = strlen(work->work_group)+1;
+  strcpy(userdata->data, work->work_group);
+
+  /* Deregister any browser names we may have. */
+  make_nmb_name(&nmbname, MSBROWSE, 0x1, scope);
+  if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
+  {
+    release_name(subrec, namerec,
+                 release_msbrowse_name_success,
+                 release_msbrowse_name_fail,
+                 userdata);
+  }
+}
+
+/****************************************************************************
+  Success in registering the WORKGROUP<1d> name.
+  We are now *really* a local master browser.
+  ****************************************************************************/
+
+static void become_local_master_stage2(struct subnet_record *subrec,
+                                        struct userdata_struct *userdata,
+                                        struct nmb_name *registered_name,
+                                        uint16 nb_flags,
+                                        int ttl, struct in_addr registered_ip)
+{
+  int i = 0;
+  struct server_record *sl;
+  struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
+  struct server_record *servrec;
+
+  if(!work)
+  {
+    DEBUG(0,("become_local_master_stage2: Error - cannot find \
+workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, registered_name->name, subrec->subnet_name));
+    work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+    return;
+  }
+  
+  DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
+on subnet %s\n", work->work_group, subrec->subnet_name));
+
+  work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
+
+  /* update our server status */
+  servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
+  servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
+
+  /* Tell the namelist writer to write out a change. */
+  subrec->work_changed = True;
+
+  /* Add this name to the workgroup as local master browser. */
+  StrnCpy(work->local_master_browser_name, myname,
+            sizeof(work->local_master_browser_name)-1);
+
+  /* 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. */
+    broadcast_announce_request(subrec, work);
+  }
+
+  /*
+   * Now we are a local master on a broadcast subnet, we need to add
+   * the WORKGROUP<1d> name to the unicast subnet so that we can answer
+   * unicast requests sent to this name. We can create this name directly on
+   * the unicast subnet as a WINS server always returns true when registering
+   * this name, and discards the registration. We use the number of IP
+   * addresses registered to this name as a reference count, as we
+   * remove this broadcast subnet IP address from it when we stop becoming a local
+   * master browser for this broadcast subnet.
+   */
+
+  insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
+
+  /* Reset the announce master browser timer so that we try and tell a domain
+     master browser as soon as possible that we are a local master browser. */
+  reset_announce_timer();
+
+  DEBUG(0,("\n*****   Samba name server %s is now a local master browser for workgroup %s \
+on subnet %s *****\n\n", myname, work->work_group, subrec->subnet_name));
+
+}
+
+/****************************************************************************
+  Failed to register the WORKGROUP<1d> name.
+  ****************************************************************************/
+static void become_local_master_fail2(struct subnet_record *subrec,
+                                      struct response_record *rrec,
+                                      struct nmb_name *fail_name)
+{
+  struct work_record *work = find_workgroup_on_subnet( subrec, fail_name->name);
+
+  DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
+Failed to become a local master browser.\n", namestr(fail_name), subrec->subnet_name));
+
+  if(!work)
+  {
+    DEBUG(0,("become_local_master_fail2: Error - cannot find \
+workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
+    return;
+  }
+
+  /* Roll back all the way by calling unbecome_local_master_browser(). */
+  unbecome_local_master_browser(subrec, work);
+}
+
+/****************************************************************************
+  Success in registering the MSBROWSE name.
+  ****************************************************************************/
+
+static void become_local_master_stage1(struct subnet_record *subrec,
+                                        struct userdata_struct *userdata,
+                                        struct nmb_name *registered_name,
+                                        uint16 nb_flags,
+                                        int ttl, struct in_addr registered_ip)
+{
+  char *work_name = userdata->data;
+  struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
+
+  if(!work)
+  {
+    DEBUG(0,("become_local_master_stage1: Error - cannot find \
+workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
+    return;
+  }
+
+  DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
+            work->work_group));
+
+  work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
+
+  /*
+   * We registered the MSBROWSE name on a broadcast subnet, now need to add
+   * the MSBROWSE name to the unicast subnet so that we can answer
+   * unicast requests sent to this name. We create this name directly on
+   * the unicast subnet.
+   */
+
+  insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
+
+  /* Attempt to register the WORKGROUP<1d> name. */
+  register_name(subrec, work->work_group,0x1d,samba_nb_type,
+                become_local_master_stage2,
+                become_local_master_fail2,
+                NULL);
+}
+
+/****************************************************************************
+  Failed to register the MSBROWSE name.
+  ****************************************************************************/
+
+static void become_local_master_fail1(struct subnet_record *subrec,
+                                      struct response_record *rrec,
+                                      struct nmb_name *fail_name)
+{
+  char *work_name = rrec->userdata->data;
+  struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
+  struct server_record *servrec;
+
+  if(!work)
+  {
+    DEBUG(0,("become_local_master_fail1: Error - cannot find \
+workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup(work, myname)) == NULL)
+  {
+    DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, work->work_group, subrec->subnet_name));
+    return;
+  }
+
+  reset_workgroup_state( subrec, work->work_group );
+
+  DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+       work->work_group, subrec->subnet_name, namestr(fail_name)));
+}
+
+/******************************************************************
+  Become the local master browser on a subnet.
+  This gets called if we win an election on this subnet.
+
+  Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
+  Stage 2: mst_state was MST_BACKUP  - go to MST_MSB  and register WORKGROUP<1d>.
+  Stage 3: mst_state was MST_MSB  - go to MST_BROWSER.
+******************************************************************/
+
+void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
+{
+  struct server_record *servrec;
+  struct userdata_struct *userdata;
+  char ud[sizeof(struct userdata_struct) + sizeof(fstring)+1];
+
+  /* Sanity check. */
+  if (!lp_local_master())
+  { 
+    DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
+    return;
+  }
+
+  if(!AM_POTENTIAL_MASTER_BROWSER(work))
+  {
+    DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
+              work->mst_state ));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, work->work_group, subrec->subnet_name));
+    return;
+  }
+
+  DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
+%s on subnet %s\n", work->work_group, subrec->subnet_name));
+  
+  DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
+  work->mst_state = MST_BACKUP; /* an election win was successful */
+
+  work->ElectionCriterion |= 0x5;
+
+  /* Tell the namelist writer to write out a change. */
+  subrec->work_changed = True;
+
+  /* Setup the userdata_struct - this is copied so we can use
+     a stack variable for this. */
+  userdata = (struct userdata_struct *)ud;
+
+  userdata->copy_fn = NULL;
+  userdata->free_fn = NULL;
+  userdata->userdata_len = strlen(work->work_group)+1;
+  strcpy(userdata->data, work->work_group);
+
+  /* Register the special browser group name. */
+  register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
+                become_local_master_stage1,
+                become_local_master_fail1,
+                userdata);
+}
diff --git a/source/nmbd/nmbd_browserdb.c b/source/nmbd/nmbd_browserdb.c
new file mode 100644 (file)
index 0000000..b2db744
--- /dev/null
@@ -0,0 +1,184 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int DEBUGLEVEL;
+
+/* This is our local master browser list database. */
+struct browse_cache_record *lmb_browserlist = NULL;
+
+/***************************************************************************
+Add a browser into the lmb list.
+**************************************************************************/
+
+static void add_to_lmb_browse_cache(struct browse_cache_record *browc)
+{
+  struct browse_cache_record *browc2;
+
+  if (lmb_browserlist == NULL)
+  {
+    lmb_browserlist = browc;
+    browc->prev = NULL;
+    browc->next = NULL;
+    return;
+  }
+  
+  for (browc2 = lmb_browserlist; browc2->next; browc2 = browc2->next)
+    ;
+  
+  browc2->next = browc;
+  browc->next = NULL;
+  browc->prev = browc2;
+}
+
+/*******************************************************************
+Remove a lmb browser entry.
+******************************************************************/
+
+void remove_lmb_browser_entry(struct browse_cache_record *browc)
+{
+  if (browc->prev)
+    browc->prev->next = browc->next;
+  if (browc->next)
+    browc->next->prev = browc->prev;
+
+  if (lmb_browserlist == browc)
+    lmb_browserlist = browc->next; 
+         
+  free((char *)browc);
+}
+
+/****************************************************************************
+Update a browser death time.
+****************************************************************************/
+
+void update_browser_death_time(struct browse_cache_record *browc)
+{
+  /* Allow the new lmb to miss an announce period before we remove it. */
+  browc->death_time = time(NULL) + (CHECK_TIME_MST_ANNOUNCE + 2)*60;
+}
+
+/****************************************************************************
+Create a browser entry.
+****************************************************************************/
+
+struct browse_cache_record *create_browser_in_lmb_cache(char *work_name, char *browser_name, 
+                                                        struct in_addr ip)
+{
+  struct browse_cache_record *browc;
+  time_t now = time(NULL);
+
+  browc = (struct browse_cache_record *)malloc(sizeof(*browc));
+     
+  if (browc == NULL)
+  {
+    DEBUG(0,("create_browser_in_lmb_cache: malloc fail !\n"));
+    return(NULL);
+  }
+
+  bzero((char *)browc,sizeof(*browc));
+  
+  /* For a new lmb entry we want to sync with it after one minute. This
+     will allow it time to send out a local announce and build its
+     browse list. */
+
+  browc->sync_time = now + 60;
+
+  /* Allow the new lmb to miss an announce period before we remove it. */
+  browc->death_time = now + (CHECK_TIME_MST_ANNOUNCE + 2)*60;
+
+  StrnCpy(browc->lmb_name, browser_name,sizeof(browc->lmb_name)-1);
+  StrnCpy(browc->work_group,work_name,sizeof(browc->work_group)-1);
+  strupper(browc->lmb_name);
+  strupper(browc->work_group);
+  
+  browc->ip = ip;
+  add_to_lmb_browse_cache(browc);
+      
+  DEBUG(3,("create_browser_in_lmb_cache: Added lmb cache entry for workgroup %s name %s IP %s ttl %d\n",
+            browc->work_group, browc->lmb_name, inet_ntoa(ip), browc->death_time));
+  
+  return(browc);
+}
+
+/****************************************************************************
+Find a browser entry.
+****************************************************************************/
+
+struct browse_cache_record *find_browser_in_lmb_cache( char *browser_name )
+{
+  struct browse_cache_record *browc = NULL;
+
+  for( browc = lmb_browserlist; browc; browc = browc->next)
+    if(strequal( browser_name, browc->lmb_name))
+      break;
+
+  return browc;
+}
+
+/*******************************************************************
+  Expire timed out browsers in the browserlist.
+******************************************************************/
+
+void expire_lmb_browsers(time_t t)
+{
+  struct browse_cache_record *browc;
+  struct browse_cache_record *nextbrowc;
+
+  for (browc = lmb_browserlist; browc; browc = nextbrowc)
+  {
+    nextbrowc = browc->next;
+
+    if (browc->death_time < t)
+    {
+      DEBUG(3,("expire_lmb_browsers: Removing timed out lmb entry %s\n",browc->lmb_name));
+      remove_lmb_browser_entry(browc);
+    }
+  }
+}
+
+/*******************************************************************
+  Remove browsers from a named workgroup in the browserlist.
+******************************************************************/
+
+void remove_workgroup_lmb_browsers(char *work_group)
+{
+  struct browse_cache_record *browc;
+  struct browse_cache_record *nextbrowc;
+
+  for (browc = lmb_browserlist; browc; browc = nextbrowc)
+  {
+    nextbrowc = browc->next;
+
+    if (strequal(work_group, browc->work_group))
+    {
+      DEBUG(3,("remove_workgroup_browsers: Removing lmb entry %s\n",browc->lmb_name));
+      remove_lmb_browser_entry(browc);
+    }
+  }
+}
+
diff --git a/source/nmbd/nmbd_browsesync.c b/source/nmbd/nmbd_browsesync.c
new file mode 100644 (file)
index 0000000..b899e2e
--- /dev/null
@@ -0,0 +1,458 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+extern struct in_addr ipzero;
+extern pstring myname;
+
+/* This is our local master browser list database. */
+extern struct browse_cache_record *lmb_browserlist;
+
+static struct work_record *call_work;
+static struct subnet_record *call_subrec;
+
+/*******************************************************************
+  This is the NetServerEnum callback.
+  ******************************************************************/
+
+static void callback(char *sname, uint32 stype, char *comment)
+{
+  struct work_record *work;
+
+  stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
+
+  if (stype & SV_TYPE_DOMAIN_ENUM) 
+  {
+    /* See if we can find the workgroup on this subnet. */
+    if(( work = find_workgroup_on_subnet( call_subrec, sname )) != NULL)
+    {
+      /* We already know about this workgroup - update the ttl. */
+      update_workgroup_ttl( work, lp_max_ttl() );
+    }
+    else
+    {
+      /* Create the workgroup on the subnet. */
+      create_workgroup_on_subnet( call_subrec, sname, lp_max_ttl() );
+    }
+  }
+  else
+  {
+    /* Server entry. */
+    struct server_record *servrec;
+
+    work = call_work;
+
+    if(( servrec = find_server_in_workgroup( work, sname )) != NULL)
+    {
+      /* Check that this is not a locally known server - if so ignore the
+         entry. */
+      if(!(servrec->serv.type & SV_TYPE_LOCAL_LIST_ONLY))
+      {
+        /* We already know about this server - update the ttl. */
+        update_server_ttl(servrec, lp_max_ttl() );
+        /* Update the type. */
+        servrec->serv.type = stype;
+      }
+    }
+    else
+    {
+      /* Create the server in the workgroup. */ 
+      create_server_on_workgroup(work, sname,stype,lp_max_ttl(),comment);
+    }
+  }
+}
+
+/*******************************************************************
+  Synchronise browse lists with another browse server.
+  Log in on the remote server's SMB port to their IPC$ service,
+  do a NetServerEnum and update our server and workgroup databases.
+******************************************************************/
+
+static void sync_browse_lists(struct subnet_record *subrec, struct work_record *work,
+                      char *name, int nm_type, struct in_addr ip, BOOL local)
+{
+  extern fstring local_machine;
+  static struct cli_state cli;
+  uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
+
+  DEBUG(2,("%s: sync_browse_lists: Sync browse lists with server %s<%02x> at IP %s for workgroup %s\n",
+     timestring(), name, nm_type, inet_ntoa(ip), work->work_group ));
+
+  /* Check we're not trying to sync with ourselves. This can happen if we are
+     a domain *and* a local master browser. */
+  if(ismyip(ip))
+  {
+    DEBUG(2,("sync_browse_lists: We are both a domain and a local master browser for workgroup %s. \
+Do not sync with ourselves.\n", work->work_group ));
+    return;
+  }
+
+  if (!cli_initialise(&cli) || !cli_connect(&cli, name, &ip))
+  {
+    DEBUG(0,("sync_browse_lists: Failed to start browse sync with %s\n", name));
+    return;
+  }
+
+  if (!cli_session_request(&cli, name, nm_type, local_machine))
+  {
+    DEBUG(0,("sync_browse_lists: %s rejected the browse sync session\n",name));
+    cli_shutdown(&cli);
+    return;
+  }
+
+  if (!cli_negprot(&cli))
+  {
+    DEBUG(0,("sync_browse_lists: %s rejected the negprot\n",name));
+    cli_shutdown(&cli);
+    return;
+  }
+
+  if (!cli_session_setup(&cli, "", "", 1, "", 0, work->work_group))
+  {
+    DEBUG(0,("sync_browse_lists: %s rejected the browse sync sessionsetup\n", 
+             name));
+    cli_shutdown(&cli);
+    return;
+  }
+
+  if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1))
+  {
+    DEBUG(0,("sync_browse_lists: %s refused browse sync IPC$ connect\n", name));
+    cli_shutdown(&cli);
+    return;
+  }
+
+  call_work = work;
+  call_subrec = subrec;
+
+  /* Fetch a workgroup list. */
+  cli_NetServerEnum(&cli, work->work_group, 
+                    local_type|SV_TYPE_DOMAIN_ENUM,
+                    callback);
+
+  /* Now fetch a server list. */
+  cli_NetServerEnum(&cli, work->work_group, 
+                    local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
+                    callback);
+
+  cli_shutdown(&cli);
+}
+
+/****************************************************************************
+As a domain master browser, do a sync with a local master browser.
+**************************************************************************/
+
+static void sync_with_lmb(struct browse_cache_record *browc)
+{                     
+  struct work_record *work;
+
+  if (!(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group))) {
+      DEBUG(0, ("sync_with_lmb: failed to get a \
+workgroup for a local master browser cache entry workgroup %s, server %s\n", 
+                browc->work_group, browc->lmb_name));
+      return;
+  }
+
+  /* We should only be doing this if we are a domain master browser for
+     the given workgroup. Ensure this is so. */
+
+  if(!AM_DOMAIN_MASTER_BROWSER(work))
+  {
+    DEBUG(0,("sync_with_lmb: We are trying to sync with a local master browser %s \
+for workgroup %s and we are not a domain master browser on this workgroup. Error !\n",
+        browc->lmb_name, browc->work_group));
+    return;
+  }
+
+  DEBUG(2, ("sync_with_lmb: Initiating sync with local master browser %s<0x20> at IP %s for \
+workgroup %s\n", browc->lmb_name, inet_ntoa(browc->ip), browc->work_group));
+
+  sync_browse_lists(unicast_subnet, work, browc->lmb_name, 0x20, browc->ip, True);
+
+  browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
+}
+
+/****************************************************************************
+Sync or expire any local master browsers.
+**************************************************************************/
+
+void dmb_expire_and_sync_browser_lists(time_t t)
+{
+  static time_t last_run = 0;
+  struct browse_cache_record *browc;
+
+  /* Only do this every 20 seconds. */  
+  if (t - last_run < 20) 
+   return;
+
+  last_run = t;
+
+  expire_lmb_browsers(t);
+
+  for (browc = lmb_browserlist; browc; browc = browc->next)
+  {
+    if (browc->sync_time < t)
+      sync_with_lmb(browc);
+  }
+}
+
+/****************************************************************************
+As a local master browser, send an announce packet to the domain master browser.
+**************************************************************************/
+
+static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
+{
+  pstring outbuf;
+  char *p;
+
+  if(ismyip(work->dmb_addr))
+  {
+    DEBUG(2,("announce_local_master_browser_to_domain_master_browser: We are both a domain \
+and a local master browser for workgroup %s. \
+Do not announce to ourselves.\n", work->work_group ));
+    return;
+  }
+
+  bzero(outbuf,sizeof(outbuf));
+  p = outbuf;
+  CVAL(p,0) = ANN_MasterAnnouncement;
+  p++;
+
+  StrnCpy(p,myname,15);
+  strupper(p);
+  p = skip_string(p,1);
+
+  DEBUG(4,("announce_local_master_browser_to_domain_master_browser: Sending local master announce \
+to %s for workgroup %s.\n", namestr(&work->dmb_name), work->work_group ));
+
+  send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+          myname, 0x0, work->dmb_name.name, 0x20, work->dmb_addr, FIRST_SUBNET->myip);
+
+}
+
+/****************************************************************************
+As a local master browser, do a sync with a domain master browser.
+**************************************************************************/
+
+static void sync_with_dmb(struct work_record *work)
+{
+  DEBUG(2, ("sync_with_dmb: Initiating sync with domain master browser %s at IP %s for \
+workgroup %s\n", namestr(&work->dmb_name), inet_ntoa(work->dmb_addr), work->work_group));
+
+  sync_browse_lists(unicast_subnet, work, work->dmb_name.name, work->dmb_name.name_type, 
+                    work->dmb_addr, False);
+}
+
+/****************************************************************************
+  Function called when a node status query to a domain master browser IP succeeds.
+****************************************************************************/
+
+static void domain_master_node_status_success(struct subnet_record *subrec,
+                                              struct userdata_struct *userdata,
+                                              struct res_rec *answers,
+                                              struct in_addr from_ip)
+{
+  struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
+
+  if(work == NULL)
+  {
+    DEBUG(0,("domain_master_node_status_success: Unable to find workgroup %s on subnet %s.\n",
+              userdata->data, subrec->subnet_name));
+    return;
+  }
+
+  DEBUG(3,("domain_master_node_status_success: Success in node status for workgroup %s from ip %s\n",
+            work->work_group, inet_ntoa(from_ip) ));
+
+  /* Go through the list of names found at answers->rdata and look for
+     the first SERVER<0x20> name. */
+
+  if(answers->rdata != NULL)
+  {
+    char *p = answers->rdata;
+    int numnames = CVAL(p, 0);
+
+    p += 1;
+
+    while (numnames--)
+    {
+      char qname[17];
+      uint16 nb_flags;
+      int name_type;
+
+      StrnCpy(qname,p,15);
+      name_type = CVAL(p,15);
+      nb_flags = get_nb_flags(&p[16]);
+      trim_string(qname,NULL," ");
+
+      p += 18;
+
+      if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
+      {
+        struct nmb_name nmbname;
+
+        make_nmb_name(&nmbname, qname, name_type, scope);
+
+        /* Copy the dmb name and IP address
+           into the workgroup struct. */
+
+        work->dmb_name = nmbname;
+        putip((char *)&work->dmb_addr, &from_ip);
+
+        /* Do the local master browser announcement to the domain
+           master browser name and IP. */
+        announce_local_master_browser_to_domain_master_browser( work );
+
+        /* Now synchronise lists with the domain master browser. */
+        sync_with_dmb(work);
+        break;
+      }
+    }
+  }
+  else
+    DEBUG(0,("domain_master_node_status_success: Failed to find a SERVER<0x20> \
+name in reply from IP %s.\n", inet_ntoa(from_ip) ));
+}
+
+/****************************************************************************
+  Function called when a node status query to a domain master browser IP fails.
+****************************************************************************/
+
+static void domain_master_node_status_fail(struct subnet_record *subrec,
+                       struct response_record *rrec)
+{
+  struct userdata_struct *userdata = rrec->userdata;
+
+  DEBUG(0,("domain_master_node_status_fail: Doing a node status request to \
+the domain master browser for workgroup %s at IP %s failed. Cannot sync browser \
+lists.\n", userdata->data, inet_ntoa(rrec->packet->ip) ));
+
+}
+
+/****************************************************************************
+  Function called when a query for a WORKGROUP<1b> name succeeds.
+****************************************************************************/
+
+static void find_domain_master_name_query_success(struct subnet_record *subrec,
+                        struct userdata_struct *userdata_in,
+                        struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
+{
+  /* 
+   * Unfortunately, finding the IP address of the Domain Master Browser,
+   * as we have here, is not enough. We need to now do a sync to the
+   * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
+   * respond to the SMBSERVER name. To get this name from IP
+   * address we do a Node status request, and look for the first
+   * NAME<0x20> in the response, and take that as the server name.
+   * We also keep a cache of the Domain Master Browser name for this
+   * workgroup in the Workgroup struct, so that if the same IP addess
+   * is returned every time, we don't need to do the node status
+   * request.
+   */
+
+  struct work_record *work;
+  struct nmb_name nmbname;
+  struct userdata_struct *userdata;
+  char ud[sizeof(struct userdata_struct) + sizeof(fstring)+1];
+
+  if (!(work = find_workgroup_on_subnet(subrec, q_name->name))) {
+      DEBUG(0, ("find_domain_master_name_query_success: failed to find \
+workgroup %s\n", q_name->name ));
+    return;
+  }
+
+  /* First check if we already have a dmb for this workgroup. */
+
+  if(!ip_equal(work->dmb_addr, ipzero) && ip_equal(work->dmb_addr, answer_ip))
+  {
+    /* Do the local master browser announcement to the domain
+       master browser name and IP. */
+    announce_local_master_browser_to_domain_master_browser( work );
+
+    /* Now synchronise lists with the domain master browser. */
+    sync_with_dmb(work);
+    return;
+  }
+  else
+    putip((char *)&work->dmb_addr, &ipzero);
+
+  /* Now initiate the node status request. */
+  bzero((char *)&nmbname, sizeof(nmbname));
+  nmbname.name[0] = '*';
+
+  /* Put the workgroup name into the userdata so we know
+     what workgroup we're talking to when the reply comes
+     back. */
+
+  /* Setup the userdata_struct - this is copied so we can use
+     a stack variable for this. */
+  userdata = (struct userdata_struct *)ud;
+
+  userdata->copy_fn = NULL;
+  userdata->free_fn = NULL;
+  userdata->userdata_len = strlen(work->work_group)+1;
+  strcpy(userdata->data, work->work_group);
+
+  node_status( subrec, &nmbname, answer_ip, 
+               domain_master_node_status_success,
+               domain_master_node_status_fail,
+               userdata);
+}
+
+/****************************************************************************
+  Function called when a query for a WORKGROUP<1b> name fails.
+  ****************************************************************************/
+static void find_domain_master_name_query_fail(struct subnet_record *subrec,
+                                    struct response_record *rrec,
+                                    struct nmb_name *question_name, int fail_code)
+{
+  DEBUG(0,("find_domain_master_name_query_fail: Unable to find the Domain Master \
+Browser name %s for the workgroup %s. Unable to sync browse lists in this workgroup.\n",
+        namestr(question_name), question_name->name ));
+}
+
+/****************************************************************************
+As a local master browser for a workgroup find the domain master browser
+name, announce ourselves as local master browser to it and then pull the
+full domain browse lists from it onto the given subnet.
+**************************************************************************/
+
+void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
+                                                   struct work_record *work)
+{
+  struct nmb_name nmbname;
+
+  make_nmb_name(&nmbname,work->work_group,0x1b,scope);
+
+  /* First, query for the WORKGROUP<1b> name from the WINS server. */
+  query_name(unicast_subnet, nmbname.name, nmbname.name_type,
+             find_domain_master_name_query_success,
+             find_domain_master_name_query_fail,
+             NULL);
+
+}
diff --git a/source/nmbd/nmbd_elections.c b/source/nmbd/nmbd_elections.c
new file mode 100644 (file)
index 0000000..5c3c4c7
--- /dev/null
@@ -0,0 +1,348 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+extern fstring myworkgroup;
+
+/* Election parameters. */
+extern time_t StartupTime;
+
+/****************************************************************************
+  Send an election datagram packet.
+**************************************************************************/
+static void send_election_dgram(struct subnet_record *subrec, char *workgroup_name,
+                                uint32 criterion, int timeup,char *server_name)
+{
+  pstring outbuf;
+  char *p;
+
+  DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n",
+       workgroup_name, subrec->subnet_name ));
+
+  bzero(outbuf,sizeof(outbuf));
+  p = outbuf;
+  CVAL(p,0) = ANN_Election; /* Election opcode. */
+  p++;
+
+  CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
+  SIVAL(p,1,criterion);
+  SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */
+  p += 13;
+  pstrcpy(p,server_name);
+  strupper(p);
+  p = skip_string(p,1);
+  
+  send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
+                server_name, 0,
+                workgroup_name, 0x1e,
+                subrec->bcast_ip, subrec->myip);
+}
+
+/*******************************************************************
+ We found a current master browser on one of our broadcast interfaces.
+******************************************************************/
+
+static void check_for_master_browser_success(struct subnet_record *subrec,
+                                 struct userdata_struct *userdata,
+                                 struct nmb_name *answer_name,
+                                 struct in_addr answer_ip, struct res_rec *rrec)
+{
+  DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \
+IP %s (just checking).\n", answer_name->name, inet_ntoa(answer_ip) ));
+}
+
+/*******************************************************************
+ We failed to find a current master browser on one of our broadcast interfaces.
+******************************************************************/
+
+static void check_for_master_browser_fail( struct subnet_record *subrec,
+                                           struct response_record *rrec,
+                                           struct nmb_name *question_name,
+                                           int fail_code)
+{
+  char *workgroup_name = question_name->name;
+  struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
+
+  if(work == NULL)
+  {
+    DEBUG(0,("check_for_master_browser_fail: Unable to find workgroup %s on subnet %s.=\n",
+          workgroup_name, subrec->subnet_name ));
+    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 that we will participate in.
+       */
+      DEBUG(2,("check_for_master_browser_fail: Forcing election on workgroup %s subnet %s\n",
+               work->work_group, subrec->subnet_name ));
+
+      /* Setting this means we will participate when the
+         election is run in run_elections(). */
+      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.
+       */
+      send_election_dgram(subrec, work->work_group, 0, 0, myname);
+    }
+  }
+}
+
+/*******************************************************************
+  Ensure there is a local master browser for a workgroup on our
+  broadcast interfaces.
+******************************************************************/
+
+void check_master_browser_exists(time_t t)
+{
+  static time_t lastrun=0;
+  struct subnet_record *subrec;
+  char *workgroup_name = myworkgroup;
+
+  if (!lastrun)
+    lastrun = t;
+
+  if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60)))
+    return;
+
+  lastrun = t;
+
+  dump_workgroups();
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work;
+
+    for (work = subrec->workgrouplist; work; work = work->next)
+    {
+      if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work))
+      {
+        /* Do a name query for the local master browser on this net. */
+        query_name( subrec, work->work_group, 0x1d,
+                    check_for_master_browser_success,
+                    check_for_master_browser_fail,
+                    NULL);
+      }
+    }
+  }
+}
+
+/*******************************************************************
+  Run an election.
+******************************************************************/
+
+void run_elections(time_t t)
+{
+  static time_t lastime = 0;
+  
+  struct subnet_record *subrec;
+  
+  /* Send election packets once a second - note */
+  if (lastime && (t - lastime <= 0))
+    return;
+  
+  lastime = t;
+  
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work;
+
+    for (work = subrec->workgrouplist; work; work = work->next)
+    {
+      if (work->RunningElection)
+      {
+        send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
+                      t - StartupTime, myname);
+             
+        if (work->ElectionCount++ >= 4)
+        {
+          /* Won election (4 packets were sent out uncontested. */
+          DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n",
+                    work->work_group, subrec->subnet_name ));
+
+          work->RunningElection = False;
+
+          become_local_master_browser(subrec, work);
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************
+  Determine if I win an election.
+******************************************************************/
+
+static BOOL win_election(struct work_record *work, int version,
+                         uint32 criterion, int timeup, char *server_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,("win_election: election comparison: %x:%x %x:%x %d:%d %s:%s\n",
+        version, ELECTION_VERSION,
+        criterion, mycriterion,
+        timeup, mytimeup,
+        server_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, server_name) > 0)
+    return(False);
+  
+  return(True);
+}
+
+/*******************************************************************
+  Process an incoming election datagram packet.
+******************************************************************/
+
+void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  int version = CVAL(buf,0);
+  uint32 criterion = IVAL(buf,1);
+  int timeup = IVAL(buf,5)/1000;
+  char *server_name = buf+13;
+  struct work_record *work;
+  char *workgroup_name = dgram->dest_name.name;
+
+  server_name[15] = 0;  
+
+  DEBUG(3,("process_election: Election request from %s at IP %s on subnet %s for workgroup %s.\n",
+      server_name,inet_ntoa(p->ip), subrec->subnet_name, workgroup_name ));
+
+  DEBUG(5,("process_election: vers=%d criterion=%08x timeup=%d\n", version,criterion,timeup));
+
+  if(( work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
+  {
+    DEBUG(0,("process_election: Cannot find workgroup %s on subnet %s.\n",
+          workgroup_name, subrec->subnet_name ));
+    return;
+  }
+
+  if (!strequal(work->work_group, myworkgroup))
+  {
+    DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \
+is not my workgroup.\n", work->work_group, subrec->subnet_name ));
+    return;
+  }
+
+  if (win_election(work, version,criterion,timeup,server_name))
+  {
+    /* We take precedence over the requesting server. */
+    if (!work->RunningElection)
+    {
+      /* We weren't running an election - start running one. */
+
+      work->needelection = True;
+      work->ElectionCount=0;
+    }
+
+    /* Note that if we were running an election for this workgroup on this
+       subnet already, we just ignore the server we take precedence over. */
+  }
+  else
+  {
+    /* We lost. Stop participating. */
+    work->needelection = False;
+
+    if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work))
+    {
+      work->RunningElection = False;
+      DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
+            work->work_group, subrec->subnet_name ));
+      if (AM_LOCAL_MASTER_BROWSER(work))
+        unbecome_local_master_browser(subrec, work);
+    }
+  }
+}
+
+/****************************************************************************
+  This function looks over all the workgroups known on all the broadcast
+  subnets and decides if a browser election is to be run on that workgroup.
+  It returns True if any election packets need to be sent (this will then
+  be done by run_elections().
+***************************************************************************/
+
+BOOL check_elections(void)
+{
+  struct subnet_record *subrec;
+  BOOL run_any_election = False;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work;
+    for (work = subrec->workgrouplist; work; work = work->next)
+    {
+      run_any_election |= work->RunningElection;
+
+      /* Only start an election if we are in the potential browser state. */
+      if (work->needelection && !work->RunningElection && AM_POTENTIAL_MASTER_BROWSER(work))
+      {
+        DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
+              work->work_group, subrec->subnet_name ));
+
+        work->ElectionCount = 0;
+        work->RunningElection = True;
+        work->needelection = False;
+      }
+    }
+  }
+  return run_any_election;
+}
diff --git a/source/nmbd/nmbd_incomingdgrams.c b/source/nmbd/nmbd_incomingdgrams.c
new file mode 100644 (file)
index 0000000..24b4f33
--- /dev/null
@@ -0,0 +1,625 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+extern fstring myworkgroup;
+
+#if 0
+
+/* XXXX note: This function is currently unsuitable for use, as it
+   does not properly check that a server is in a fit state to become
+   a backup browser before asking it to be one.
+   The code is left here to be worked on at a later date.
+*/
+
+/****************************************************************************
+Tell a server to become a backup browser
+**************************************************************************/
+
+void tell_become_backup(void)
+{
+  struct subnet_record *subrec;
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work;
+    for (work = subrec->workgrouplist; work; work = work->next)
+    {
+      struct server_record *servrec;
+      int num_servers = 0;
+      int num_backups = 0;
+         
+      for (servrec = work->serverlist; servrec; servrec = servrec->next)
+      {
+        num_servers++;
+             
+        if (is_myname(servrec->serv.name))
+          continue;
+             
+        if (servrec->serv.type & SV_TYPE_BACKUP_BROWSER) 
+        {
+          num_backups++;
+          continue;
+        }
+             
+        if (servrec->serv.type & SV_TYPE_MASTER_BROWSER)
+          continue;
+             
+        if (!(servrec->serv.type & SV_TYPE_POTENTIAL_BROWSER))
+          continue;
+             
+        DEBUG(3,("num servers: %d num backups: %d\n", 
+              num_servers, num_backups));
+             
+        /* make first server a backup server. thereafter make every
+           tenth server a backup server */
+        if (num_backups != 0 && (num_servers+9) / num_backups > 10)
+          continue;
+             
+        DEBUG(2,("sending become backup to %s %s for %s\n",
+             servrec->serv.name, inet_ntoa(subrec->bcast_ip),
+             work->work_group));
+             
+        /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
+        do_announce_request(servrec->serv.name, work->work_group,
+              ANN_BecomeBackup, 0x20, 0x1e, subrec->bcast_ip);
+      }
+    }
+  }
+}
+#endif
+
+/*******************************************************************
+  Process an incoming host announcement packet.
+*******************************************************************/
+
+void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  int ttl = IVAL(buf,1)/1000;
+  char *announce_name = buf+5;
+  uint32 servertype = IVAL(buf,23);
+  char *comment = buf+31;
+  struct work_record *work;
+  struct server_record *servrec;
+  char *work_name;
+  char *source_name = dgram->source_name.name;
+
+  comment[43] = 0;
+  
+  DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \
+%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+              namestr(&dgram->dest_name),announce_name));
+
+  DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n",
+          ttl, servertype,comment));
+
+  /* Filter servertype to remove impossible bits. */
+  servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+  /* A host announcement must be sent to the name WORKGROUP<1d>. */
+  if(dgram->dest_name.name_type != 0x1d)
+  {
+    DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x1d. Allowing packet anyway.\n",
+              inet_ntoa(p->ip), dgram->dest_name.name_type));
+    /* Change it so it was. */
+    dgram->dest_name.name_type = 0x1d;
+  }
+
+  /* For a host announce the workgroup name is the destination name. */
+  work_name = dgram->dest_name.name;
+
+  /*
+   * We are being very agressive here in adding a workgroup
+   * name on the basis of a host announcing itself as being
+   * in that workgroup. Maybe we should wait for the workgroup
+   * announce instead ? JRA.
+   */
+
+  if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL)
+  {
+    /* We have no record of this workgroup. Add it. */
+    if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+      return;
+  }
+  
+  if((servrec = find_server_in_workgroup( work, announce_name))==NULL)
+  {
+    /* If this server is not already in the workgroup, add it. */
+    create_server_on_workgroup(work, announce_name, 
+                               servertype|SV_TYPE_LOCAL_LIST_ONLY, 
+                               ttl, comment);
+  }
+  else
+  {
+    /* Update the record. */
+    servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+    update_server_ttl( servrec, ttl);
+    StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
+  }
+
+  subrec->work_changed = True;
+}
+
+/*******************************************************************
+  Process an incoming WORKGROUP announcement packet.
+*******************************************************************/
+
+void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  int ttl = IVAL(buf,1)/1000;
+  char *workgroup_announce_name = buf+5;
+  uint32 servertype = IVAL(buf,23);
+  char *master_name = buf+31;
+  struct work_record *work;
+  char *source_name = dgram->source_name.name;
+
+  master_name[43] = 0;
+
+  DEBUG(3,("process_workgroup_announce: from %s<%02x> IP %s to \
+%s for workgroup %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+              namestr(&dgram->dest_name),workgroup_announce_name));
+
+  DEBUG(5,("process_workgroup_announce: ttl=%d server type=%08x master browser=%s\n",
+           ttl, servertype, master_name));
+
+  /* Workgroup announcements must only go to the MSBROWSE name. */
+  if (!strequal(dgram->dest_name.name, MSBROWSE) || (dgram->dest_name.name_type != 0x1))
+  {
+    DEBUG(0,("process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s\n",
+              inet_ntoa(p->ip), namestr(&dgram->dest_name)));
+    return;
+  }
+
+  if ((work = find_workgroup_on_subnet(subrec, workgroup_announce_name))==NULL)
+  {
+    /* We have no record of this workgroup. Add it. */
+    if((work = create_workgroup_on_subnet(subrec, workgroup_announce_name, ttl))==NULL)
+      return;
+  }
+  else
+  {
+    /* Update the workgroup death_time. */
+    update_workgroup_ttl(work, ttl);
+  }
+
+  if(*work->local_master_browser_name == '\0')
+  {
+    /* Set the master browser name. */
+    StrnCpy(work->local_master_browser_name, master_name,
+            sizeof(work->local_master_browser_name)-1);
+
+  }
+
+  subrec->work_changed = True;
+}
+
+/*******************************************************************
+  Process an incoming local master browser announcement packet.
+*******************************************************************/
+
+void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  int ttl = IVAL(buf,1)/1000;
+  char *server_name = buf+5;
+  uint32 servertype = IVAL(buf,23);
+  char *comment = buf+31;
+  char *work_name;
+  struct work_record *work;
+  struct server_record *servrec;
+  char *source_name = dgram->source_name.name;
+
+  comment[43] = 0;
+
+  DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \
+%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+              namestr(&dgram->dest_name),server_name));
+
+  DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n",
+           ttl, servertype, comment));
+
+  /* A local master announcement must be sent to the name WORKGROUP<1e>. */
+  if(dgram->dest_name.name_type != 0x1e)
+  {
+    DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x1e. Ignoring packet.\n",
+              inet_ntoa(p->ip), dgram->dest_name.name_type));
+    return;
+  }
+
+  /* Filter servertype to remove impossible bits. */
+  servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+  /* For a local master announce the workgroup name is the destination name. */
+  work_name = dgram->dest_name.name;
+
+  if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL)
+  {
+    /* We have no record of this workgroup. Add it. */
+    if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+      return;
+  }
+
+  /* If we think we're the local master browser for this workgroup,
+     we should never have got this packet. We don't see our own
+     packets.
+   */
+  if(AM_LOCAL_MASTER_BROWSER(work))
+  {
+    DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \
+a local master browser for workgroup %s and we think we are master. Forcing election.\n",
+      server_name, inet_ntoa(p->ip), work_name));
+
+    /* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
+       they have become a local master browser once, they will never
+       stop sending local master announcements. To fix this we send
+       them a reset browser packet, with level 0x2 on the __SAMBA__
+       name that only they should be listening to. */
+   
+    send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip);
+
+    /* We should demote ourself and force an election. */
+
+    unbecome_local_master_browser( subrec, work);
+
+    /* The actual election requests are handled in
+       nmbd_election.c */
+
+    work->needelection = True;
+    return;
+  }  
+
+  /* Find the server record on this workgroup. If it doesn't exist, add it. */
+
+  if((servrec = find_server_in_workgroup( work, server_name))==NULL)
+  {
+    /* If this server is not already in the workgroup, add it. */
+    create_server_on_workgroup(work, server_name, 
+                               servertype|SV_TYPE_LOCAL_LIST_ONLY, 
+                               ttl, comment);
+  }
+  else
+  {
+    /* Update the record. */
+    servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+    update_server_ttl(servrec, ttl);
+    StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
+  }
+
+  /* Set the master browser name. */
+  StrnCpy(work->local_master_browser_name, server_name,
+            sizeof(work->local_master_browser_name)-1);
+
+  subrec->work_changed = True;
+}
+
+/*******************************************************************
+  Process a domain master announcement frame.
+  Domain master browsers receive these from local masters. The Domain
+  master should then issue a sync with the local master, asking for
+  that machines local server list.
+******************************************************************/
+
+void process_master_browser_announce(struct subnet_record *subrec, 
+                                     struct packet_struct *p,char *buf)
+{
+  char *local_master_name = buf;
+  struct work_record *work;
+  struct browse_cache_record *browrec;
+
+  local_master_name[15] = 0;
+  
+  DEBUG(3,("process_master_browser_announce: Local master announce from %s IP %s.\n",
+           local_master_name, inet_ntoa(p->ip)));
+  
+  if (!lp_domain_master()) 
+  {
+    DEBUG(0,("process_master_browser_announce: Not configured as domain \
+master - ignoring master announce.\n"));
+    return;
+  }
+  
+  if((work = find_workgroup_on_subnet(subrec, myworkgroup)) == NULL)
+  {
+    DEBUG(0,("process_master_browser_announce: Cannot find workgroup %s on subnet %s\n",
+           myworkgroup, subrec->subnet_name));
+    return;
+  }
+
+  if(!AM_DOMAIN_MASTER_BROWSER(work))
+  {
+    DEBUG(0,("process_master_browser_announce: Local master announce made to us from \
+%s IP %s and we are not a domain master browser.\n", local_master_name, inet_ntoa(p->ip)));
+    return;
+  }
+
+  /* Add this host as a local master browser entry on the browse lists.
+     This causes a sync request to be made to it at a later date.
+   */
+
+  if((browrec = find_browser_in_lmb_cache( local_master_name )) == NULL)
+  {
+    /* Add it. */
+    create_browser_in_lmb_cache( work->work_group, local_master_name, p->ip);
+  }
+  else
+    update_browser_death_time(browrec);
+}
+
+/****************************************************************************
+  Send a backup list response.
+*****************************************************************************/
+
+static void send_backup_list_response(struct subnet_record *subrec, 
+                             struct work_record *work,
+                             struct nmb_name *send_to_name,
+                             unsigned char max_number_requested,
+                            uint32 token, struct in_addr sendto_ip)
+{                     
+  char outbuf[1024];
+  char *p, *countptr, *nameptr;
+  int count = 0;
+  int len;
+  struct server_record *servrec;
+
+  bzero(outbuf,sizeof(outbuf));
+
+  DEBUG(3,("send_backup_list_response: sending backup list for workgroup %s to %s IP %s\n",
+          work->work_group, namestr(send_to_name), inet_ntoa(sendto_ip)));
+  
+  p = outbuf;
+  
+  SCVAL(p,0,ANN_GetBackupListResp); /* Backup list response opcode. */
+  p++;
+
+  countptr = p;
+  p++;
+
+  SIVAL(p,0,token); /* The sender's unique info. */
+  p += 4;
+  
+  nameptr = p;
+
+  /* We always return at least one name - our own. */
+  count = 1;
+  StrnCpy(p,myname,15);
+  strupper(p);
+  p = skip_string(p,1);
+
+  /* Look for backup browsers in this workgroup. */
+  for (servrec = work->serverlist; servrec; servrec = servrec->next)
+  { 
+    len = PTR_DIFF(p, outbuf);
+    if((sizeof(outbuf) - len) < 16)
+      break;
+
+    if(count >= max_number_requested)
+      break;
+
+    if(strnequal(servrec->serv.name, myname,15))
+      continue;
+
+    if(!(servrec->serv.type & SV_TYPE_BACKUP_BROWSER))
+      continue;
+
+    StrnCpy(p, servrec->serv.name, 15);
+    strupper(p);
+    count++;
+
+    DEBUG(5,("send_backup_list_response: Adding server %s number %d\n",
+              p, count));
+
+    p = skip_string(p,1);
+  }
+
+  SCVAL(countptr, 0, count);
+
+  len = PTR_DIFF(p, outbuf);
+
+  DEBUG(4,("send_backup_list_response: sending response to %s<00> IP %s with %d servers.\n",
+          send_to_name->name, inet_ntoa(sendto_ip), count));
+
+  send_mailslot(True, BROWSE_MAILSLOT,
+                outbuf,PTR_DIFF(p,outbuf),
+                myname, 0, 
+                send_to_name->name,0,
+                sendto_ip, subrec->myip);
+}
+
+/*******************************************************************
+  Process a send backup list request packet.
+
+  A client sends a backup list request to ask for a list of servers on
+  the net that maintain server lists for a domain. A server is then
+  chosen from this list to send NetServerEnum commands to to list
+  available servers.
+
+********************************************************************/
+
+void process_get_backup_list_request(struct subnet_record *subrec,
+                                     struct packet_struct *p,char *buf)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  struct work_record *work;
+  unsigned char max_number_requested = CVAL(buf,0);
+  uint32 token = IVAL(buf,1); /* Sender's key index for the workgroup. */
+  int name_type = dgram->dest_name.name_type;
+  char *workgroup_name = dgram->dest_name.name;
+
+  DEBUG(3,("process_get_backup_list_request: request from %s IP %s to %s.\n",
+           namestr(&dgram->source_name), inet_ntoa(p->ip),
+           namestr(&dgram->dest_name)));
+  
+  /* We have to be a master browser, or a domain master browser
+     for the requested workgroup. That means it must be our
+     workgroup. */
+
+  if(strequal(workgroup_name, myworkgroup) == False)
+  {
+    DEBUG(7,("process_get_backup_list_request: Ignoring announce request for workgroup %s.\n",
+           workgroup_name));
+    return;
+  }
+
+  if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
+  {
+    DEBUG(0,("process_get_backup_list_request: Cannot find workgroup %s on \
+subnet %s.\n", workgroup_name, subrec->subnet_name));
+    return;
+  }
+
+  if(name_type == 0x1b)
+  {
+    /* We must be a domain master browser in order to
+       process this packet. */
+
+    if(!AM_DOMAIN_MASTER_BROWSER(work))
+    {
+      DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
+and I am not a domain master browser.\n", workgroup_name));
+      return;
+    }
+  }
+  else if (name_type == 0x1d)
+  {
+    /* We must be a local master browser in order to
+       process this packet. */
+
+    if(!AM_LOCAL_MASTER_BROWSER(work))
+    {
+      DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
+and I am not a local master browser.\n", workgroup_name));
+      return;
+    }
+  }
+  else
+  {
+    DEBUG(0,("process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d.\n",
+            name_type));
+    return;
+  }
+
+  send_backup_list_response(subrec, work, &dgram->source_name, 
+                            max_number_requested, token, p->ip);
+}
+
+/*******************************************************************
+  Process a reset browser state packet.
+
+  Diagnostic packet:
+  0x1 - Stop being a master browser and become a backup browser.
+  0x2 - Discard browse lists, stop being a master browser, try again.
+  0x4 - Stop being a master browser forever.
+         
+******************************************************************/
+
+void process_reset_browser(struct subnet_record *subrec,
+                                  struct packet_struct *p,char *buf)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  int state = CVAL(buf,0);
+  struct subnet_record *sr;
+
+  DEBUG(1,("process_reset_browser: received diagnostic browser reset \
+request from %s IP %s state=0x%X\n",
+             namestr(&dgram->source_name), inet_ntoa(p->ip), state));
+
+  /* Stop being a local master browser on all our broadcast subnets. */
+  if (state & 0x1)
+  {
+    for (sr = FIRST_SUBNET; sr; sr = NEXT_SUBNET_EXCLUDING_UNICAST(sr))
+    {
+      struct work_record *work;
+      for (work = sr->workgrouplist; work; work = work->next)
+      {
+        if (AM_LOCAL_MASTER_BROWSER(work))
+        {
+          unbecome_local_master_browser(sr, work);
+          work->needelection = True;
+        }
+      }
+    }
+  }
+  
+  /* Discard our browse lists. */
+  if (state & 0x2)
+  {
+    /*
+     * Calling expire_workgroups_and_servers with a -1
+     * time causes all servers not marked with a PERMANENT_TTL
+     * on the workgroup lists to be discarded, and all 
+     * workgroups with empty server lists to be discarded.
+     * This means we keep our own server names and workgroup
+     * as these have a PERMANENT_TTL.
+     */
+
+    expire_workgroups_and_servers(-1);
+  }
+  
+  /* Request to stop browsing altogether. */
+  if (state & 0x4)
+    DEBUG(1,("process_reset_browser: ignoring request to stop being a browser.\n"));
+}
+
+/*******************************************************************
+  Process a announcement request packet.
+  We don't respond immediately, we just check it's a request for
+  out workgroup and then set the flag telling the announce code
+  in nmbd_sendannounce.c:announce_my_server_names that an 
+  announcement is needed soon.
+  ******************************************************************/
+
+void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  struct work_record *work;
+  char *workgroup_name = dgram->dest_name.name;
+  DEBUG(3,("process_announce_request: Announce request from %s IP %s to %s.\n",
+           namestr(&dgram->source_name), inet_ntoa(p->ip),
+           namestr(&dgram->dest_name)));
+  
+  /* We only send announcement requests on our workgroup. */
+  if(strequal(workgroup_name, myworkgroup) == False)
+  {
+    DEBUG(7,("process_announce_request: Ignoring announce request for workgroup %s.\n",
+           workgroup_name));
+    return;
+  }
+
+  if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
+  {
+    DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
+            workgroup_name));
+    return;
+  }
+
+  work->needannounce = True;
+}
diff --git a/source/nmbd/nmbd_incomingrequests.c b/source/nmbd/nmbd_incomingrequests.c
new file mode 100644 (file)
index 0000000..ff4bb07
--- /dev/null
@@ -0,0 +1,556 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+   This file contains all the code to process NetBIOS requests coming
+   in on port 137. It does not deal with the code needed to service
+   WINS server requests, but only broadcast and unicast requests.
+
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+Send a name release response.
+**************************************************************************/
+
+static void send_name_release_response(int rcode, struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  char rdata[6];
+
+  memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+  
+  reply_netbios_packet(p,                            /* Packet to reply to. */
+                       rcode,                        /* Result code. */
+                       NMB_REL,                      /* nmbd type code. */
+                       NMB_NAME_RELEASE_OPCODE,      /* opcode. */
+                       0,                            /* ttl. */
+                       rdata,                        /* data to send. */
+                       6);                           /* data length. */
+}
+
+/****************************************************************************
+Process a name release packet on a broadcast subnet.
+Ignore it if it's not one of our names.
+****************************************************************************/
+
+void process_name_release_request(struct subnet_record *subrec, 
+                                  struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct in_addr owner_ip;
+  struct nmb_name *question = &nmb->question.question_name;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+  BOOL group = (nb_flags & NB_GROUP) ? True : False;
+  struct name_record *namerec;
+  int rcode = 0;
+  
+  putip((char *)&owner_ip,&nmb->additional->rdata[2]);  
+  
+  if(!bcast)
+  {
+    /* We should only get broadcast name release packets here.
+       Anyone trying to release unicast should be going to a WINS
+       server. If the code gets here, then either we are not a wins
+       server and they sent it anyway, or we are a WINS server and
+       the request was malformed. Either way, log an error here.
+       and send an error reply back.
+     */
+    DEBUG(0,("process_name_release_request: unicast name release request \
+received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
+          namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));      
+
+    send_name_release_response(FMT_ERR, p);
+    return;
+  }
+
+  DEBUG(3,("process_name_release_request: Name release on name %s, \
+subnet %s from owner IP %s\n",
+           namestr(&nmb->question.question_name),
+           subrec->subnet_name, inet_ntoa(owner_ip)));
+  
+  /* If someone is releasing a broadcast group name, just ignore it. */
+  if( group && !ismyip(owner_ip) )
+    return;
+
+  namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_ANY_NAME);
+
+  /* We only care about someone trying to release one of our names. */
+  if (namerec && ((namerec->source == SELF_NAME) || (namerec->source == PERMANENT_NAME)))
+  {
+    rcode = ACT_ERR;
+    DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
+on subnet %s being rejected as it is one of our names.\n", 
+          namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
+  }
+
+  if(rcode == 0)
+    return;
+
+  /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
+  send_name_release_response(rcode, p);
+}
+
+/****************************************************************************
+Send a name registration response.
+**************************************************************************/
+
+static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  char rdata[6];
+
+  memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+  
+  reply_netbios_packet(p,                             /* Packet to reply to. */
+                       rcode,                         /* Result code. */
+                       NMB_REG,                       /* nmbd type code. */
+                       NMB_NAME_REG_OPCODE,           /* opcode. */
+                       ttl,                           /* ttl. */
+                       rdata,                         /* data to send. */
+                       6);                            /* data length. */
+}
+
+/****************************************************************************
+Process a name refresh request on a broadcast subnet.
+**************************************************************************/
+     
+void process_name_refresh_request(struct subnet_record *subrec,
+                                  struct packet_struct *p)
+{    
+     
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question = &nmb->question.question_name;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  struct in_addr from_ip;
+  
+  putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+  if(!bcast)
+  { 
+    /* We should only get broadcast name refresh packets here.
+       Anyone trying to refresh unicast should be going to a WINS
+       server. If the code gets here, then either we are not a wins
+       server and they sent it anyway, or we are a WINS server and
+       the request was malformed. Either way, log an error here.
+       and send an error reply back.
+     */
+    DEBUG(0,("process_name_refresh_request: unicast name registration request \
+received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
+          namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+    
+    send_name_registration_response(FMT_ERR, 0, p);
+    return;
+  } 
+
+  /* Just log a message. We really don't care about broadcast name
+     refreshes. */
+     
+  DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
+IP %s on subnet %s\n", namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+     
+}
+    
+/****************************************************************************
+Process a name registration request on a broadcast subnet.
+**************************************************************************/
+
+void process_name_registration_request(struct subnet_record *subrec, 
+                                       struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question = &nmb->question.question_name;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+  BOOL group = (nb_flags & NB_GROUP) ? True : False;
+  struct name_record *namerec = NULL;
+  int ttl = nmb->additional->ttl;
+  struct in_addr from_ip;
+  
+  putip((char *)&from_ip,&nmb->additional->rdata[2]);
+  
+  if(!bcast)
+  {
+    /* We should only get broadcast name registration packets here.
+       Anyone trying to register unicast should be going to a WINS
+       server. If the code gets here, then either we are not a wins
+       server and they sent it anyway, or we are a WINS server and
+       the request was malformed. Either way, log an error here.
+       and send an error reply back.
+     */
+    DEBUG(0,("process_name_registration_request: unicast name registration request \
+received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
+          namestr(question), inet_ntoa(from_ip), subrec->subnet_name));      
+
+    send_name_registration_response(FMT_ERR, 0, p);
+    return;
+  }
+
+  DEBUG(3,("process_name_registration_request: Name registration for name %s \
+IP %s on subnet %s\n", namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+  
+  /* See if the name already exists. */
+  namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+  
+  if (!group)
+  {
+    /* Unique name. */
+
+    if ((namerec != NULL) && 
+        ((namerec->source == SELF_NAME) || (namerec->source == PERMANENT_NAME) ||
+          NAME_GROUP(namerec))
+       )
+    {
+      /* No-one can register one of Samba's names, nor can they
+         register a name that's a group name as a unique name */
+
+      send_name_registration_response(ACT_ERR, 0, p);
+      return;
+    }
+    else if(namerec != NULL)
+    {
+      /* Update the namelist record with the new information. */
+      namerec->ip[0] = from_ip;
+      update_name_ttl(namerec, ttl);
+
+      DEBUG(3,("process_name_registration_request: Updated name record %s \
+with IP %s on subnet %s\n",namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
+      return;
+    }
+  }
+  else
+  {
+    /* Group name. */
+
+    if((namerec != NULL) && !NAME_GROUP(namerec) &&
+        ((namerec->source == SELF_NAME) || (namerec->source == PERMANENT_NAME))
+      )
+    {
+      /* Disallow group names when we have a unique name. */
+      send_name_registration_response(ACT_ERR, 0, p);  
+      return;  
+    }  
+  }
+}
+
+/****************************************************************************
+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;
+
+  /* It's 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);
+}
+
+
+/****************************************************************************
+  Process a node status query
+  ****************************************************************************/
+
+void process_node_status_request(struct subnet_record *subrec, 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 *namerec;
+
+  DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
+subnet %s.\n", namestr(&nmb->question.question_name), inet_ntoa(p->ip),
+          subrec->subnet_name));
+
+  if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name,
+                                    FIND_SELF_NAME)) == 0)
+  {
+    DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
+subnet %s - name not found.\n", namestr(&nmb->question.question_name),
+          inet_ntoa(p->ip), subrec->subnet_name));
+
+    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;
+
+  namerec = subrec->namelist;
+
+  while (buf < bufend) 
+  {
+    if ((namerec->source == SELF_NAME) || (namerec->source == PERMANENT_NAME))
+    {
+      int name_type = namerec->name.name_type;
+      
+      if (!strequal(namerec->name.name,"*") &&
+          !strequal(namerec->name.name,"__SAMBA__") &&
+          (name_type < 0x1b || name_type >= 0x20 || 
+           ques_type < 0x1b || ques_type >= 0x20 ||
+           strequal(qname, namerec->name.name)))
+      {
+        /* Start with the name. */
+        bzero(buf,18);
+        sprintf(buf,"%-15.15s",namerec->name.name);
+        strupper(buf);
+        
+        /* Put the name type and netbios flags in the buffer. */
+        buf[15] = name_type;
+        set_nb_flags(&buf[16],namerec->nb_flags);
+        buf[16] |= NB_ACTIVE; /* all our names are active */
+
+        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;
+
+    namerec = namerec->next;
+
+    if (!namerec)
+    {
+      /* End of the subnet specific name list. Now 
+         add the names on the unicast subnet . */
+      struct subnet_record *uni_subrec = unicast_subnet;
+
+      if (uni_subrec != subrec)
+      {
+        subrec = uni_subrec;
+        namerec = subrec->namelist;
+      }
+    }
+    if (!namerec)
+      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 NODE STATUS RESPONSE */
+  reply_netbios_packet(p,                            /* Packet to reply to. */
+                       0,                            /* Result code. */
+                       NMB_STATUS,                   /* nmbd type code. */
+                       NMB_NAME_QUERY_OPCODE,        /* opcode. */
+                      0,                            /* ttl. */
+                       rdata,                        /* data to send. */
+                       PTR_DIFF(buf,rdata));         /* data length. */
+}
+
+
+/***************************************************************************
+Process a name query.
+
+For broadcast name queries:
+
+  - Only reply if the query is for one of YOUR names.
+  - NEVER send a negative response to a broadcast query.
+
+****************************************************************************/
+
+void process_name_query_request(struct subnet_record *subrec, 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;
+  int ttl=0;
+  int rcode = 0;
+  char *prdata = NULL;
+  char rdata[6];
+  BOOL success = False;
+  struct name_record *namerec = NULL;
+  int reply_data_len = 0;
+  int i;
+  DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n", 
+            inet_ntoa(p->ip), subrec->subnet_name, namestr(question)));
+  
+  /* Look up the name in the cache - if the request is a broadcast request that
+     came from a subnet we don't know about then search all the broadcast subnets
+     for a match (as we don't know what interface the request came in on). */
+
+  if(subrec == remote_broadcast_subnet)
+    namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
+  else
+    namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+
+  /* Check if it is a name that expired */
+  if (namerec && ((namerec->death_time != PERMANENT_TTL) && (namerec->death_time < p->timestamp)))
+  {
+    DEBUG(5,("process_name_query_request: expired name %s\n", namestr(&namerec->name)));
+    namerec = NULL;
+  }
+
+  if (namerec)
+  {
+
+    /* 
+     * Always respond to unicast queries.
+     * Don't respond to broadcast queries unless the query is for
+     * a name we own, a Primary Domain Controller name, or a WINS_PROXY 
+     * name with type 0 or 0x20. WINS_PROXY names are only ever added
+     * into the namelist if we were configured as a WINS proxy.
+     */
+
+    if (!bcast || 
+        (bcast && ((name_type == 0x1b) || (namerec->source == SELF_NAME) || 
+        (namerec->source == PERMANENT_NAME) || 
+        ((namerec->source == WINS_PROXY_NAME) && ((name_type == 0) || (name_type == 0x20)))))
+       )
+    {
+      
+      /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY, 
+         or it's a Domain Master type. */
+
+      ttl = (namerec->death_time != PERMANENT_TTL) ?
+                     namerec->death_time - p->timestamp : lp_max_ttl();
+
+      /* Copy all known ip addresses into the return data. */
+      /* Optimise for the common case of one IP address so 
+         we don't need a malloc. */
+
+      if(namerec->num_ips == 1 )
+        prdata = rdata;
+      else
+      {
+        if((prdata = (char *)malloc( namerec->num_ips * 6 )) == NULL)
+        {
+          DEBUG(0,("process_name_query_request: malloc fail !\n"));
+          return;
+        }
+      }
+
+      for( i = 0; i < namerec->num_ips; i++)
+      {
+        set_nb_flags(&prdata[i*6],namerec->nb_flags);
+        putip((char *)&prdata[2+(i*6)], &namerec->ip[i]);
+      }
+      reply_data_len = namerec->num_ips * 6;
+      success = True;
+    }
+  }
+
+  /*
+   * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
+   * set we should initiate a WINS query here. On success we add the resolved name 
+   * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
+   */
+
+  if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() && 
+     bcast && (subrec != remote_broadcast_subnet))
+  {
+    make_wins_proxy_name_query_request( subrec, p, question );
+    return;
+  }
+
+  if (!success && bcast)
+  {
+    if((prdata != rdata) && (prdata != NULL))
+      free(rdata);
+    return; /* Never reply with a negative response to broadcasts. */
+  }
+
+  /* 
+   * Final check. From observation, if a unicast packet is sent
+   * to a non-WINS server with the recursion desired bit set
+   * then never send a negative response.
+   */
+
+  if(!success && !bcast && nmb->header.nm_flags.recursion_desired)
+  {
+    if((prdata != rdata) && (prdata != NULL))
+      free(rdata);
+    return;
+  }
+
+  if (success)
+  {
+      rcode = 0;
+      DEBUG(3,("OK\n"));
+  }
+  else
+  {
+      rcode = NAM_ERR;
+      DEBUG(3,("UNKNOWN\n"));      
+  }
+
+  /* See rfc1002.txt 4.2.13. */
+
+  reply_netbios_packet(p,                              /* Packet to reply to. */
+                       rcode,                          /* Result code. */
+                       NMB_QUERY,                      /* nmbd type code. */
+                       NMB_NAME_QUERY_OPCODE,          /* opcode. */
+                       ttl,                            /* ttl. */
+                       prdata,                         /* data to send. */
+                       reply_data_len);                /* data length. */
+
+  if((prdata != rdata) && (prdata != NULL))
+    free(prdata);
+}
diff --git a/source/nmbd/nmbd_lmhosts.c b/source/nmbd/nmbd_lmhosts.c
new file mode 100644 (file)
index 0000000..2dd1db8
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Jeremy Allison 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:
+
+   Handle lmhosts file reading.
+
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+Load a lmhosts file.
+****************************************************************************/
+void load_lmhosts_file(char *fname)
+{  
+  FILE *fp = fopen(fname,"r");
+  pstring line;
+  if (!fp) {
+    DEBUG(2,("load_lmhosts_file: Can't open lmhosts file %s. Error was %s\n",
+             fname, strerror(errno)));
+    return;
+  }
+   
+  while (!feof(fp))
+  {
+    pstring ip,name,flags,extra;
+    struct subnet_record *subrec = NULL;
+    char *ptr;
+    int count = 0;  
+    struct in_addr ipaddr;
+    enum name_source source = LMHOSTS_NAME;
+    int name_type = -1;
+
+    if (!fgets_slash(line,sizeof(pstring),fp))
+      continue;
+
+    if (*line == '#')
+      continue;
+
+    strcpy(ip,"");     
+    strcpy(name,"");
+    strcpy(flags,"");
+     
+    ptr = line;
+     
+    if (next_token(&ptr,ip   ,NULL))
+      ++count;
+    if (next_token(&ptr,name ,NULL))
+      ++count;
+    if (next_token(&ptr,flags,NULL))
+      ++count;
+    if (next_token(&ptr,extra,NULL))
+      ++count;
+   
+    if (count <= 0)
+      continue;
+     
+    if (count > 0 && count < 2)
+    {
+      DEBUG(0,("load_lmhosts_file: Ill formed hosts line [%s]\n",line));
+      continue;
+    }
+      
+    if (count >= 4)
+    {
+      DEBUG(0,("load_lmhosts_file: too many columns in lmhosts file %s (obsolete syntax)\n",
+             fname));
+      continue;
+    }
+      
+    DEBUG(4, ("load_lmhosts_file: lmhost entry: %s %s %s\n", ip, name, flags));
+    
+    if (strchr(flags,'G') || strchr(flags,'S'))
+    {
+      DEBUG(0,("load_lmhosts_file: group flag in %s ignored (obsolete)\n",fname));
+      continue;
+    }
+
+    ipaddr = *interpret_addr2(ip);
+
+    /* Extra feature. If the name ends in '#XX', where XX is a hex number,
+       then only add that name type. */
+    if((ptr = strchr(name, '#')) != NULL)
+    {
+      char *endptr;
+
+      ptr++;
+      name_type = (int)strtol(ptr, &endptr,0);
+
+      if(!*ptr || (endptr == ptr))
+      {
+        DEBUG(0,("load_lmhosts_file: invalid name %s containing '#'.\n", name));
+        continue;
+      }
+
+      *(--ptr) = '\0'; /* Truncate at the '#' */
+    }
+
+    /* We find a relevent subnet to put this entry on, then add it. */
+    /* Go through all the broadcast subnets and see if the mask matches. */
+    for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+    {
+      if(same_net(ipaddr, subrec->bcast_ip, subrec->mask_ip))
+        break;
+    }
+  
+    /* If none match add the name to the remote_broadcast_subnet. */
+    if(subrec == NULL)
+      subrec = remote_broadcast_subnet;
+
+    if(name_type == -1)
+    {
+      /* Add the (0) and (0x20) names directly into the namelist for this subnet. */
+      add_name_to_subnet(subrec,name,0x00,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
+      add_name_to_subnet(subrec,name,0x20,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
+    }
+    else
+    {
+      /* Add the given name type to the subnet namelist. */
+      add_name_to_subnet(subrec,name,name_type,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
+    }
+  }
+   
+  fclose(fp);
+}
+
+/****************************************************************************
+  Find a name read from the lmhosts file. We secretly check the names on
+  the remote_broadcast_subnet as if the name was added to a regular broadcast
+  subnet it will be found by normal name query processing.
+****************************************************************************/
+
+BOOL find_name_in_lmhosts(struct nmb_name *nmbname, struct name_record **namerecp)
+{
+  struct name_record *namerec;
+
+  *namerecp = NULL;
+
+  if((namerec = find_name_on_subnet(remote_broadcast_subnet, nmbname, 
+                                 FIND_ANY_NAME))==NULL)
+    return False;
+
+  if(!NAME_IS_ACTIVE(namerec) || (namerec->source != LMHOSTS_NAME))
+    return False;
+
+  *namerecp = namerec;
+  return True;
+}
diff --git a/source/nmbd/nmbd_logonnames.c b/source/nmbd/nmbd_logonnames.c
new file mode 100644 (file)
index 0000000..b2431ec
--- /dev/null
@@ -0,0 +1,166 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+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 allones_ip;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+/****************************************************************************
+  Fail to become a Logon server on a subnet.
+  ****************************************************************************/
+static void become_logon_server_fail(struct subnet_record *subrec,
+                                      struct response_record *rrec,
+                                      struct nmb_name *fail_name)
+{
+  struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
+  struct server_record *servrec;
+
+  if(!work)
+  {
+    DEBUG(0,("become_logon_server_fail: Error - cannot find \
+workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("become_logon_server_fail: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, fail_name->name, subrec->subnet_name));
+    work->log_state = LOGON_NONE;
+    return;
+  }
+
+  /* Set the state back to LOGON_NONE. */
+  work->log_state = LOGON_NONE;
+
+  servrec->serv.type &= ~SV_TYPE_DOMAIN_CTRL;
+
+  DEBUG(0,("become_logon_server_fail: Failed to become a domain master for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+       work->work_group, subrec->subnet_name, namestr(fail_name)));
+
+}
+
+/****************************************************************************
+  Become a Logon server on a subnet.
+  ****************************************************************************/
+
+static void become_logon_server_success(struct subnet_record *subrec,
+                                        struct userdata_struct *userdata,
+                                        struct nmb_name *registered_name,
+                                        uint16 nb_flags,
+                                        int ttl, struct in_addr registered_ip)
+{
+  struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
+  struct server_record *servrec;
+
+  if(!work)
+  {
+    DEBUG(0,("become_logon_server_success: Error - cannot find \
+workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
+    return;
+  }
+
+  if((servrec = find_server_in_workgroup( work, myname)) == NULL)
+  {
+    DEBUG(0,("become_logon_server_success: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+       myname, registered_name->name, subrec->subnet_name));
+    work->log_state = LOGON_NONE;
+    return;
+  }
+
+  /* Set the state in the workgroup structure. */
+  work->log_state = LOGON_SRV; /* Become domain master. */
+
+  /* Update our server status. */
+  servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER);
+  /* To allow Win95 policies to load we need to set type domain
+     controller.
+   */
+  servrec->serv.type |= SV_TYPE_DOMAIN_CTRL;
+
+  /* Tell the namelist writer to write out a change. */
+  subrec->work_changed = True;
+
+  DEBUG(0,("become_logon_server_success: Samba is now a logon server\
+for workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
+}
+
+/*******************************************************************
+  Become a logon server by attempting to register the WORKGROUP<1c>
+  group name.
+******************************************************************/
+
+static void become_logon_server(struct subnet_record *subrec,
+                                struct work_record *work)
+{
+  DEBUG(2,("become_logon_server: Atempting to become logon server for workgroup %s \
+on subnet %s\n", work->work_group,subrec->subnet_name));
+
+  DEBUG(3,("become_logon_server: go to first stage: register %s<1c> name\n",
+          work->work_group));
+  work->log_state = LOGON_WAIT;
+
+  register_name(subrec, work->work_group,0x1c,samba_nb_type|NB_GROUP,
+                become_logon_server_success,
+                become_logon_server_fail, NULL);
+}
+
+/*****************************************************************************
+  Add the internet group <1c> logon names by unicast and broadcast.
+  ****************************************************************************/
+void add_logon_names(void)
+{
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work = find_workgroup_on_subnet(subrec, myworkgroup);
+
+    if (work && (work->log_state == LOGON_NONE))
+    {
+      struct nmb_name nmbname;
+      make_nmb_name(&nmbname,myworkgroup,0x1c,scope);
+
+      if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
+      {
+        DEBUG(0,("add_domain_logon_names: At time %s attempting to become \
+logon server for workgroup %s on subnet %s\n", timestring(), myworkgroup, 
+                  subrec->subnet_name));
+        become_logon_server(subrec, work);
+      }
+    }
+  }
+}
diff --git a/source/nmbd/nmbd_mynames.c b/source/nmbd/nmbd_mynames.c
new file mode 100644 (file)
index 0000000..660b545
--- /dev/null
@@ -0,0 +1,165 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern char **my_netbios_names;
+extern pstring myname;
+extern fstring myworkgroup;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+/****************************************************************************
+ Fail funtion when registering my netbios names.
+  **************************************************************************/
+
+static void my_name_register_failed(struct subnet_record *subrec,
+                              struct response_record *rrec, struct nmb_name *nmbname)
+{
+  DEBUG(0,("my_name_register_failed: Failed to register my name %s on subnet %s.\n",
+            namestr(nmbname), subrec->subnet_name));
+}
+
+/****************************************************************************
+  Add my workgroup and my given names to the subnet lists.
+  Also add the magic Samba names.
+  **************************************************************************/
+
+BOOL register_my_workgroup_and_names()
+{
+  struct subnet_record *subrec;
+  struct work_record *work;
+  int i;
+
+  for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    /* Create the workgroup on the subnet. */
+    if((work = create_workgroup_on_subnet(subrec, myworkgroup, PERMANENT_TTL)) == NULL)
+    {
+      DEBUG(0,("register_my_workgroup_and_names: Failed to create my workgroup %s on subnet %s. \
+Exiting.\n", myworkgroup, subrec->subnet_name));
+      return False;
+    }
+
+    /* Each subnet entry, except for the remote_announce_broadcast subnet
+       and the wins_server_subnet has the magic Samba names. */
+    add_samba_names_to_subnet(subrec);
+
+    /* Register all our names including aliases. */
+    for (i=0; my_netbios_names[i]; i++) 
+    {
+      register_name(subrec, my_netbios_names[i],0x20,samba_nb_type,
+                    NULL,
+                    my_name_register_failed, NULL);
+      register_name(subrec, my_netbios_names[i],0x03,samba_nb_type,
+                    NULL,
+                    my_name_register_failed, NULL);
+      register_name(subrec, my_netbios_names[i],0x00,samba_nb_type,
+                    NULL,
+                    my_name_register_failed, NULL);
+    }
+
+    /* Initiate election processing, register the workgroup names etc. */
+    initiate_myworkgroup_startup(subrec, work);
+  }
+
+  /* If we are not a WINS client, we still need to add the magic Samba
+     names and the netbios names to the unicast subnet directly. This is
+     to allow unicast node status requests and queries to still work
+     in a broadcast only environment. */
+
+  if(we_are_a_wins_client() == False)
+  {
+    add_samba_names_to_subnet(unicast_subnet);
+
+    for (i=0; my_netbios_names[i]; i++)
+    {
+      add_name_to_subnet(unicast_subnet, my_netbios_names[i],0x20,samba_nb_type, PERMANENT_TTL,
+                     SELF_NAME, 1, &FIRST_SUBNET->myip);
+
+      add_name_to_subnet(unicast_subnet, my_netbios_names[i],0x3,samba_nb_type, PERMANENT_TTL,
+                     SELF_NAME, 1, &FIRST_SUBNET->myip);
+
+      add_name_to_subnet(unicast_subnet, my_netbios_names[i],0x0,samba_nb_type, PERMANENT_TTL,
+                     SELF_NAME, 1, &FIRST_SUBNET->myip);
+    }
+  }
+
+  return True;
+}
+
+/****************************************************************************
+  Remove all the names we registered.
+**************************************************************************/
+
+void release_my_names()
+{
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    struct name_record *namerec, *nextnamerec;
+
+    for (namerec = subrec->namelist; namerec; namerec = nextnamerec)
+    {
+      nextnamerec = namerec->next;
+      if ((namerec->source == SELF_NAME) && !NAME_IS_DEREGISTERING(namerec))
+        release_name(subrec, namerec, standard_success_release,
+                     NULL, NULL);
+    }
+  }
+}
+
+/*******************************************************************
+  Refresh our registered names.
+  ******************************************************************/
+
+void refresh_my_names(time_t t)
+{
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    struct name_record *namerec;
+         
+    for (namerec = subrec->namelist; namerec; namerec = namerec->next)
+    {
+      /* Each SELF name has an individual time to be refreshed. */
+      if ((namerec->source == SELF_NAME) && (namerec->refresh_time < t) && 
+          (namerec->death_time != PERMANENT_TTL))
+      {
+        /* We cheat here and pretend the refresh is going to be
+           successful & update the refresh times. This stops
+           multiple refresh calls being done. We actually
+           deal with refresh failure in the fail_fn.
+         */
+        refresh_name(subrec, namerec, NULL, NULL, NULL);
+       namerec->death_time += lp_max_ttl();
+       namerec->refresh_time += lp_max_ttl();
+      }
+    }
+  }
+}
diff --git a/source/nmbd/nmbd_namelistdb.c b/source/nmbd/nmbd_namelistdb.c
new file mode 100644 (file)
index 0000000..dfd8a80
--- /dev/null
@@ -0,0 +1,586 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern char **my_netbios_names;
+
+uint16 samba_nb_type = 0; /* samba's NetBIOS name type */
+
+
+/****************************************************************************
+  Set Samba's NetBIOS name type.
+  ****************************************************************************/
+
+void set_samba_nb_type(void)
+{
+  if (lp_wins_support() || (*lp_wins_server()))
+    samba_nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */
+  else
+    samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type */
+}
+
+/****************************************************************************
+  Returns 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 a namelist.
+  **************************************************************************/
+
+static void add_name_to_namelist(struct subnet_record *subrec, 
+                                 struct name_record *namerec)
+{
+  struct name_record *namerec2;
+
+  if (!subrec->namelist)
+  {
+    subrec->namelist = namerec;
+    namerec->prev = NULL;
+    namerec->next = NULL;
+    return;
+  }
+
+  for (namerec2 = subrec->namelist; namerec2->next; namerec2 = namerec2->next) 
+    ;
+
+  namerec2->next = namerec;
+  namerec->next = NULL;
+  namerec->prev = namerec2;
+  namerec->subnet = subrec;
+
+  subrec->namelist_changed = True;
+}
+
+/****************************************************************************
+  Remove a name from the namelist.
+  **************************************************************************/
+
+void remove_name_from_namelist(struct subnet_record *subrec, 
+                               struct name_record *namerec)
+{
+  if (namerec->next)
+    namerec->next->prev = namerec->prev;
+  if (namerec->prev)
+    namerec->prev->next = namerec->next;
+
+  if(namerec == subrec->namelist)
+    subrec->namelist = namerec->next;
+
+  if(namerec->ip != NULL)
+    free((char *)namerec->ip);
+  free((char *)namerec);
+
+  subrec->namelist_changed = True;
+}
+
+
+/****************************************************************************
+  Find a name in a subnet.
+  **************************************************************************/
+
+struct name_record *find_name_on_subnet(struct subnet_record *subrec,
+                                      struct nmb_name *nmbname, BOOL self_only)
+{
+  struct name_record *namerec = subrec->namelist;
+  struct name_record *name_ret;
+  
+  for (name_ret = namerec; name_ret; name_ret = name_ret->next)
+  {
+    if (nmb_name_equal(&name_ret->name, nmbname))
+    {
+      /* Self names only - these include permanent names. */
+      if (self_only && (name_ret->source != SELF_NAME) && 
+              (name_ret->source != PERMANENT_NAME) )
+      {
+        continue;
+      }
+      DEBUG(9,("find_name_on_subnet: on subnet %s - found name %s source=%d\n", 
+                subrec->subnet_name, namestr(nmbname), name_ret->source));
+      return name_ret;
+    }
+  }
+  DEBUG(9,("find_name_on_subnet: on subnet %s - name %s NOT FOUND\n", 
+            subrec->subnet_name, namestr(nmbname)));
+  return NULL;
+}
+
+/****************************************************************************
+  Find a name over all known broadcast subnets.
+**************************************************************************/
+
+struct name_record *find_name_for_remote_broadcast_subnet( struct nmb_name *nmbname, 
+                                                           BOOL self_only)
+{
+  struct subnet_record *subrec;
+  struct name_record *namerec = NULL;
+
+  for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    if((namerec = find_name_on_subnet(subrec, nmbname, self_only))!= NULL)
+      break;
+  }
+
+  return namerec;
+}    
+  
+/****************************************************************************
+  Update the ttl of an entry in a subnet name list.
+  ****************************************************************************/
+
+void update_name_ttl(struct name_record *namerec, int ttl)
+{
+  time_t time_now = time(NULL);
+
+  if(namerec->death_time != PERMANENT_TTL)
+    namerec->death_time = time_now + ttl;
+
+  namerec->refresh_time = time_now + (ttl/2);
+
+  namerec->subnet->namelist_changed = True;
+} 
+
+/****************************************************************************
+  Add an entry to a subnet name list.
+  ****************************************************************************/
+
+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)
+{
+  struct name_record *namerec;
+  time_t time_now = time(NULL);
+
+  if((namerec = (struct name_record *)malloc(sizeof(*namerec))) == NULL)
+  {
+    DEBUG(0,("add_name_to_subnet: malloc fail.\n"));
+    return NULL;
+  }
+
+  bzero((char *)namerec,sizeof(*namerec));
+
+  namerec->subnet = subrec;
+
+  namerec->num_ips = num_ips;
+  namerec->ip = (struct in_addr *)malloc(sizeof(struct in_addr) * namerec->num_ips);
+  if (!namerec->ip)
+  {
+     DEBUG(0,("add_name_to_subnet: malloc fail when creating ip_flgs.\n"));
+     free((char *)namerec);
+     return NULL;
+  }
+
+  bzero((char *)namerec->ip, sizeof(struct in_addr) * namerec->num_ips);
+
+  memcpy(&namerec->ip[0], iplist, num_ips * sizeof(struct in_addr));
+
+  make_nmb_name(&namerec->name,name,type,scope);
+
+  /* Setup the death_time and refresh_time. */
+  if(ttl == PERMANENT_TTL)
+    namerec->death_time = PERMANENT_TTL;
+  else
+    namerec->death_time = time_now + ttl;
+
+  namerec->refresh_time = time_now + (ttl/2);
+
+  /* Enter the name as active. */
+  namerec->nb_flags = nb_flags | NB_ACTIVE;
+
+  /* If it's our primary name, flag it as so. */
+  if(strequal(my_netbios_names[0],name))
+    namerec->nb_flags |= NB_PERM;
+
+  namerec->source = source;
+  
+  add_name_to_namelist(subrec,namerec);
+
+  DEBUG(3,("add_name_to_subnet: Added netbios name %s with first IP %s ttl=%d nb_flags=%2x to subnet %s\n",
+          namestr(&namerec->name),inet_ntoa(*iplist),ttl,(unsigned int)nb_flags,
+          subrec->subnet_name));
+
+  subrec->namelist_changed = True;
+
+  return(namerec);
+}
+
+/*******************************************************************
+ Utility function automatically called when a name refresh or register 
+ succeeds. By definition this is a SELF_NAME (or we wouldn't be registering
+ it).
+ ******************************************************************/
+
+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)
+{
+  struct name_record *namerec = find_name_on_subnet(subrec, nmbname, FIND_SELF_NAME);
+
+  if(namerec == NULL)
+    add_name_to_subnet(subrec, nmbname->name, nmbname->name_type,
+                     nb_flags, ttl, SELF_NAME, 1, &registered_ip);
+  else
+    update_name_ttl(namerec, ttl);
+}
+
+/*******************************************************************
+ Utility function automatically called when a name refresh or register 
+ fails.
+ ******************************************************************/
+
+void standard_fail_register(struct subnet_record *subrec, 
+                             struct response_record *rrec, struct nmb_name *nmbname)
+{
+  struct name_record *namerec = find_name_on_subnet(subrec, nmbname, FIND_SELF_NAME);
+
+  DEBUG(0,("standard_fail_register: Failed to register/refresh name %s on subnet %s\n",
+           namestr(nmbname), subrec->subnet_name));
+
+  /* Remove the name from the subnet. */
+  if(namerec)
+    remove_name_from_namelist(subrec, namerec);
+}
+
+/*******************************************************************
+ Utility function to remove an IP address from a name record.
+ ******************************************************************/
+
+static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
+{
+  if(ind != namerec->num_ips)
+    memmove( (char *)(&namerec->ip[ind]), (char *)(&namerec->ip[ind+1]), 
+              ( namerec->num_ips - ind - 1) * sizeof(struct in_addr));
+
+  namerec->num_ips--;
+  namerec->subnet->namelist_changed = True;
+}
+
+/*******************************************************************
+ Utility function to check if an IP address exists in a name record.
+ ******************************************************************/
+
+BOOL find_ip_in_name_record(struct name_record *namerec, struct in_addr ip)
+{
+  int i;
+
+  for(i = 0; i < namerec->num_ips; i++)
+    if(ip_equal( namerec->ip[i], ip))
+      return True;
+
+  return False;
+}
+
+/*******************************************************************
+ Utility function to add an IP address to a name record.
+ ******************************************************************/
+
+void add_ip_to_name_record(struct name_record *namerec, struct in_addr new_ip)
+{
+  struct in_addr *new_list;
+
+  /* Don't add one we already have. */
+  if(find_ip_in_name_record( namerec, new_ip))
+    return;
+  
+  if((new_list = (struct in_addr *)malloc( (namerec->num_ips + 1)*sizeof(struct in_addr)) )== NULL)
+  {
+    DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
+    return;
+  }
+
+  memcpy((char *)new_list, (char *)namerec->ip, namerec->num_ips *sizeof(struct in_addr));
+  new_list[namerec->num_ips] = new_ip;
+
+  free((char *)namerec->ip);
+  namerec->ip = new_list;
+  namerec->num_ips += 1;
+
+  namerec->subnet->namelist_changed = True;
+}
+
+/*******************************************************************
+ Utility function to remove an IP address from a name record.
+ ******************************************************************/
+
+void remove_ip_from_name_record( struct name_record *namerec, struct in_addr remove_ip)
+{
+  /* Try and find the requested ip address - remove it. */
+  int i;
+  int orig_num = namerec->num_ips;
+
+  for(i = 0; i < orig_num; i++)
+    if( ip_equal( remove_ip, namerec->ip[i]) )
+    {
+      remove_nth_ip_in_record( namerec, i);
+      break;
+    }
+}
+
+/*******************************************************************
+ Utility function that release_name callers can plug into as the
+ success function when a name release is successful. Used to save
+ duplication of success_function code.
+ ******************************************************************/
+
+void standard_success_release(struct subnet_record *subrec, 
+                             struct userdata_struct *userdata,
+                             struct nmb_name *nmbname, struct in_addr released_ip)
+{
+  struct name_record *namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME);
+
+  if(namerec == NULL)
+  {
+    DEBUG(0,("standard_success_release: Name release for name %s IP %s on subnet %s. Name \
+was not found on subnet.\n", namestr(nmbname), inet_ntoa(released_ip), subrec->subnet_name));
+    return;
+  }
+  else
+  {
+    int orig_num = namerec->num_ips;
+
+    remove_ip_from_name_record( namerec, released_ip);
+
+    if(namerec->num_ips == orig_num)
+      DEBUG(0,("standard_success_release: Name release for name %s IP %s on subnet %s. This ip \
+is not known for this name.\n", namestr(nmbname), inet_ntoa(released_ip), subrec->subnet_name ));
+  }
+
+  if (namerec->num_ips == 0)
+    remove_name_from_namelist(subrec, namerec);
+}
+
+/*******************************************************************
+  Expires old names in a subnet namelist.
+  ******************************************************************/
+
+void expire_names_on_subnet(struct subnet_record *subrec, time_t t)
+{
+  struct name_record *namerec;
+  struct name_record *next_namerec;
+
+  for (namerec = subrec->namelist; namerec; namerec = next_namerec)
+  {
+    next_namerec = namerec->next;
+    if ((namerec->death_time != PERMANENT_TTL) && (namerec->death_time < t))
+    {
+      if (namerec->source == SELF_NAME)
+      {
+        DEBUG(3,("expire_names_on_subnet: Subnet %s not expiring SELF name %s\n", 
+             subrec->subnet_name, namestr(&namerec->name)));
+        namerec->death_time += 300;
+        namerec->subnet->namelist_changed = True;
+        continue;
+      }
+      DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n", 
+                 subrec->subnet_name, namestr(&namerec->name)));
+  
+      remove_name_from_namelist(subrec, namerec);
+    }
+  }
+}
+
+/*******************************************************************
+  Expires old names in all subnet namelists.
+  ******************************************************************/
+
+void expire_names(time_t t)
+{
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    expire_names_on_subnet(subrec, t);
+  }
+}
+
+/****************************************************************************
+  Add the magic samba names, useful for finding samba servers.
+  These go directly into the name list for a particular subnet,
+  without going through the normal registration process.
+  When adding them to the unicast subnet, add them as a list of
+  all broadcast subnet IP addresses.
+**************************************************************************/
+
+void add_samba_names_to_subnet(struct subnet_record *subrec)
+{
+  struct in_addr *iplist = &subrec->myip;
+  int num_ips = 1;
+
+  /* These names are added permanently (ttl of zero) and will NOT be
+     refreshed.  */
+
+  if((subrec == unicast_subnet) || (subrec == wins_server_subnet))
+  {
+    struct subnet_record *bcast_subrecs;
+    int i;
+    /* Create an IP list containing all our known subnets. */
+
+    num_ips = iface_count();
+    if((iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) )) == NULL)
+    {
+      DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
+      return;
+    }
+
+    for(bcast_subrecs = FIRST_SUBNET, i = 0; bcast_subrecs; 
+                 bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++)
+      iplist[i] = bcast_subrecs->myip;
+
+  }
+
+  add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
+                     PERMANENT_NAME, num_ips, iplist);
+  add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
+                     PERMANENT_NAME, num_ips, iplist);
+  add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
+                   PERMANENT_NAME, num_ips, iplist);
+  add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
+                   PERMANENT_NAME, num_ips, iplist);
+
+  if(iplist != &subrec->myip)
+    free((char *)iplist);
+}
+
+/****************************************************************************
+ Dump the contents of the namelists on all the subnets (including unicast)
+ into a file. Initiated by SIGHUP - used to debug the state of the namelists.
+**************************************************************************/
+
+static void dump_subnet_namelist( struct subnet_record *subrec, FILE *fp)
+{
+  struct name_record *namerec;
+  char *src_type;
+  struct tm *tm;
+  int i;
+
+  fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
+  for (namerec = subrec->namelist; namerec; namerec = namerec->next)
+  {
+    fprintf(fp,"\tName = %s\t", namestr(&namerec->name));
+    switch(namerec->source)
+    {
+      case LMHOSTS_NAME:
+        src_type = "LMHOSTS_NAME";
+        break;
+      case WINS_PROXY_NAME:
+        src_type = "WINS_PROXY_NAME";
+        break;
+      case REGISTER_NAME:
+        src_type = "REGISTER_NAME";
+        break;
+      case SELF_NAME:
+        src_type = "SELF_NAME";
+        break;
+      case DNS_NAME:
+        src_type = "DNS_NAME";
+        break;
+      case DNSFAIL_NAME:
+        src_type = "DNSFAIL_NAME";
+        break;
+      case PERMANENT_NAME:
+        src_type = "PERMANENT_NAME";
+        break;
+      default:
+        src_type = "unknown!";
+        break;
+    }
+    fprintf(fp, "Source = %s\nb_flags = %x\t", src_type, namerec->nb_flags);
+
+    if(namerec->death_time != PERMANENT_TTL)
+    {
+      tm = LocalTime(&namerec->death_time);
+      fprintf(fp, "death_time = %s\t", asctime(tm));
+    }
+    else
+      fprintf(fp, "death_time = PERMANENT\t");
+
+    if(namerec->refresh_time != PERMANENT_TTL)
+    {
+      tm = LocalTime(&namerec->refresh_time);
+      fprintf(fp, "refresh_time = %s\n", asctime(tm));
+    }
+    else
+      fprintf(fp, "refresh_time = PERMANENT\n");
+
+    fprintf(fp, "\t\tnumber of IPS = %d", namerec->num_ips);
+    for(i = 0; i < namerec->num_ips; i++)
+      fprintf(fp, "\t%s", inet_ntoa(namerec->ip[i]));
+
+    fprintf(fp, "\n\n");
+  }
+}
+
+/****************************************************************************
+ Dump the contents of the namelists on all the subnets (including unicast)
+ into a file. Initiated by SIGHUP - used to debug the state of the namelists.
+**************************************************************************/
+
+void dump_all_namelists()
+{
+  fstring fname;
+  FILE *fp; 
+  struct subnet_record *subrec;
+
+  pstrcpy(fname,lp_lockdir());
+  trim_string(fname,NULL,"/");
+  strcat(fname,"/"); 
+  strcat(fname,"namelist.debug");
+
+  fp = fopen(fname,"w");
+     
+  if (!fp)
+  { 
+    DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
+              fname,strerror(errno)));
+    return;
+  }
+      
+  for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+    dump_subnet_namelist( subrec, fp);
+
+  if(!we_are_a_wins_client())
+    dump_subnet_namelist(unicast_subnet, fp);
+
+  if(remote_broadcast_subnet->namelist != NULL)
+    dump_subnet_namelist(remote_broadcast_subnet, fp);
+
+  if(wins_server_subnet != NULL)
+    dump_subnet_namelist( wins_server_subnet, fp);
+  fclose(fp);
+}
diff --git a/source/nmbd/nmbd_namequery.c b/source/nmbd/nmbd_namequery.c
new file mode 100644 (file)
index 0000000..5d98935
--- /dev/null
@@ -0,0 +1,234 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+
+/****************************************************************************
+ Deal with a response packet when querying a name.
+****************************************************************************/
+
+static void query_name_response(struct subnet_record *subrec,
+                       struct response_record *rrec, struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  BOOL success = False;
+  struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+  struct in_addr answer_ip;
+
+  /* Ensure we don't retry the query but leave the response record cleanup
+     to the timeout code. We may get more answer responses in which case
+     we should mark the name in conflict.. */
+  rrec->repeat_count = 0;
+
+  if(rrec->num_msgs == 1)
+  {
+    /* This is the first response. */
+
+    if(nmb->header.opcode == NMB_WACK_OPCODE)
+    {
+      /* WINS server is telling us to wait. Pretend we didn't get
+         the response but don't send out any more query requests. */
+  
+      DEBUG(5,("query_name_response: WACK from WINS server %s in querying \
+name %s on subnet %s.\n", inet_ntoa(p->ip), namestr(question_name), subrec->subnet_name));
+  
+      rrec->repeat_count = 0;
+      /* How long we should wait for. */
+      rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+      rrec->num_msgs--;
+      return;
+    }
+    else if(nmb->header.rcode != 0)
+    {
+      success = False;
+
+      DEBUG(5,("query_name_response: On subnet %s - negative response \
+from IP %s for name %s. Error code was %d.\n", subrec->subnet_name, inet_ntoa(p->ip), 
+                      namestr(question_name), nmb->header.rcode));
+    }
+    else
+    {
+      success = True;
+
+      putip((char *)&answer_ip,&nmb->answers->rdata[2]);
+      DEBUG(5,("query_name_response: On subnet %s - positive response from IP %s\
+for name %s. IP of that name is %s\n", subrec->subnet_name, inet_ntoa(p->ip),
+                    namestr(question_name), inet_ntoa(answer_ip)));
+
+      /* Interestingly, we could add these names to our namelists, and
+         change nmbd to a model that checked its own name cache first,
+         before sending out a query. This is a task for another day, though.
+       */
+    }
+  }
+  else if( rrec->num_msgs > 1)
+  {
+    DEBUG(0,("query_name_response: Multiple (%d) responses received for a query on \
+subnet %s for name %s. This response was from IP %s\n", 
+        rrec->num_msgs, subrec->subnet_name, namestr(question_name), 
+        inet_ntoa(rrec->packet->ip) ));
+
+    /* We have already called the success or fail function, so we
+       don't call again here. Leave the response record around in
+       case we get more responses. */
+
+    return; 
+  }
+  
+  if(success && rrec->success_fn)
+    (*rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
+  else if( rrec->fail_fn)
+    (*rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
+
+}
+
+/****************************************************************************
+ Deal with a timeout when querying a name.
+****************************************************************************/
+
+static void query_name_timeout_response(struct subnet_record *subrec,
+                       struct response_record *rrec)
+{
+  struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+  /* We can only fail here, never succeed. */
+  BOOL failed = True;
+  struct nmb_name *question_name = &sent_nmb->question.question_name;
+
+  if(rrec->num_msgs != 0)
+  {
+    /* We got at least one response, and have called the success/fail
+       function already. */
+
+    failed = False; 
+  }
+
+  if(failed)
+  {
+    DEBUG(5,("query_name_timeout_response: No response to querying name %s on subnet %s.\n",
+        namestr(question_name), subrec->subnet_name));
+
+    if(rrec->fail_fn)
+      (*rrec->fail_fn)(subrec, rrec, question_name, 0);
+  }
+
+  remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Lookup a name on our local namelists. We check the lmhosts file first. If the
+ name is not there we look for the name on the given subnet.
+****************************************************************************/
+
+static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
+                                  struct name_record **namerecp) 
+{
+  struct name_record *namerec;
+
+  *namerecp = NULL;
+
+  if(find_name_in_lmhosts(nmbname, namerecp))
+    return True;
+  
+  if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
+    return False;
+
+  if(NAME_IS_ACTIVE(namerec) && ((namerec->source == SELF_NAME) || 
+                              (namerec->source == LMHOSTS_NAME)) )
+  {
+    *namerecp = namerec;
+    return True;
+  } 
+  return False;
+}
+
+/****************************************************************************
+ Try and query for a name.
+****************************************************************************/
+
+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)
+{
+  struct nmb_name nmbname;
+  struct name_record *namerec;
+
+  make_nmb_name(&nmbname, name, type, scope);
+
+  /*
+   * We need to check our local namelists first.
+   * It may be an magic name, lmhosts name or just
+   * a name we have registered.
+   */
+
+  if(query_local_namelists(subrec, &nmbname, &namerec) == True)
+  {
+    struct res_rec rrec;
+    int i;
+
+    bzero((char *)&rrec, sizeof(struct res_rec));
+
+    /* Fake up the needed res_rec just in case it's used. */
+    rrec.rr_name = nmbname;
+    rrec.rr_type = RR_TYPE_NB;
+    rrec.rr_class = RR_CLASS_IN;
+    rrec.ttl = PERMANENT_TTL;
+    rrec.rdlength = namerec->num_ips * 6;
+    if(rrec.rdlength > MAX_DGRAM_SIZE)
+    {
+      DEBUG(0,("query_name: nmbd internal error - there are %d ip addresses for name %s.\n",
+               namerec->num_ips, namestr(&nmbname) ));
+      return False;
+    }
+
+    for( i = 0; i < namerec->num_ips; i++)
+    {
+      set_nb_flags( &rrec.rdata[i*6], namerec->nb_flags );
+      putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->ip[i]);
+    }
+
+    /* Call the success function directly. */
+    if(success_fn)
+      (*success_fn)(subrec, userdata, &nmbname, namerec->ip[0], &rrec);
+    return False;
+  }
+
+  if(queue_query_name( subrec,
+        query_name_response,
+        query_name_timeout_response,
+        success_fn,
+        fail_fn,
+        userdata,
+        &nmbname) == NULL)
+  {
+    DEBUG(0,("query_name: Failed to send packet trying to query name %s\n",
+          namestr(&nmbname)));
+    return True;
+  }
+  return False;
+}
diff --git a/source/nmbd/nmbd_nameregister.c b/source/nmbd/nmbd_nameregister.c
new file mode 100644 (file)
index 0000000..603daaa
--- /dev/null
@@ -0,0 +1,390 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern fstring myworkgroup;
+
+/****************************************************************************
+ Deal with a response packet when registering one of our names.
+****************************************************************************/
+
+static void register_name_response(struct subnet_record *subrec,
+                       struct response_record *rrec, struct packet_struct *p)
+{
+  /* 
+   * If we are registering broadcast, then getting a response is an
+   * error - we do not have the name. If we are registering unicast,
+   * then we expect to get a response.
+   */
+
+  struct nmb_packet *nmb = &p->packet.nmb;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  BOOL success = True;
+  struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+  struct nmb_name *answer_name = &nmb->answers->rr_name;
+  int ttl;
+  uint16 nb_flags;
+  struct in_addr registered_ip;
+
+  /* Sanity check. Ensure that the answer name in the incoming packet is the
+     same as the requested name in the outgoing packet. */
+
+  if(!nmb_name_equal(question_name, answer_name))
+  {
+    DEBUG(0,("register_name_response: Answer name %s differs from question \
+name %s.\n", namestr(answer_name), namestr(question_name)));
+    return;
+  }
+
+  if(bcast)
+  {
+    /*
+     * Special hack to cope with old Samba nmbd's.
+     * Earlier versions of Samba (up to 1.9.16p11) 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 1 /* OLD_SAMBA_SERVER_HACK */
+    if((nmb->header.rcode == ACT_ERR) && strequal(myworkgroup, answer_name->name) &&
+         (answer_name->name_type == 0x1b))
+    {
+      /* Pretend we did not get this. */
+      rrec->num_msgs--;
+
+      DEBUG(5,("register_name_response: Ignoring broadcast response to \
+registration of name %s due to old Samba server bug.\n", namestr(answer_name)));
+      return;
+    }
+#endif /* OLD_SAMBA_SERVER_HACK */
+
+    /* Someone else has the name. Log the problem. */
+    DEBUG(1,("register_name_response: Failed to register \
+name %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n", 
+              namestr(answer_name), 
+              subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip)));
+    success = False;
+  }
+  else
+  {
+    /* Unicast - check to see if the response allows us to have the name. */
+    if(nmb->header.rcode != 0)
+    {
+      /* Error code - we didn't get the name. */
+      success = False;
+
+      DEBUG(0,("register_name_response: server at IP %s rejected our \
+name registration of %s with error code %d.\n", inet_ntoa(p->ip), 
+                  namestr(answer_name), nmb->header.rcode));
+
+    }
+    else if(nmb->header.opcode == NMB_WACK_OPCODE)
+    {
+      /* WINS server is telling us to wait. Pretend we didn't get
+         the response but don't send out any more register requests. */
+
+      DEBUG(5,("register_name_response: WACK from WINS server %s in registering \
+name %s on subnet %s.\n", inet_ntoa(p->ip), namestr(answer_name), subrec->subnet_name));
+
+      rrec->repeat_count = 0;
+      /* How long we should wait for. */
+      rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+      rrec->num_msgs--;
+      return;
+    }
+    else
+    {
+      success = True;
+      /* Get the data we need to pass to the success function. */
+      nb_flags = get_nb_flags(nmb->answers->rdata);
+      putip((char*)&registered_ip,&nmb->answers->rdata[2]);
+      ttl = nmb->answers->ttl;
+    }
+  } 
+
+  DEBUG(5,("register_name_response: %s in registering name %s on subnet %s.\n",
+        success ? "success" : "failure", namestr(answer_name), subrec->subnet_name));
+
+  if(success)
+  {
+    /* Enter the registered name into the subnet name database before calling
+       the success function. */
+    standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
+    if( rrec->success_fn)
+      (*rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
+  }
+  else
+  {
+    if( rrec->fail_fn)
+      (*rrec->fail_fn)(subrec, rrec, question_name);
+    /* Remove the name. */
+    standard_fail_register( subrec, rrec, question_name);
+  }
+
+  /* Ensure we don't retry. */
+  remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when registering one of our names.
+****************************************************************************/
+
+static void register_name_timeout_response(struct subnet_record *subrec,
+                       struct response_record *rrec)
+{
+  /*
+   * If we are registering unicast, then NOT getting a response is an
+   * error - we do not have the name. If we are registering broadcast,
+   * then we don't expect to get a response.
+   */
+
+  struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+  BOOL bcast = sent_nmb->header.nm_flags.bcast;
+  BOOL success = False;
+  struct nmb_name *question_name = &sent_nmb->question.question_name;
+  uint16 nb_flags;
+  int ttl;
+  struct in_addr registered_ip;
+
+  if(bcast)
+  {
+    if(rrec->num_msgs == 0)
+    {
+      /* Not receiving a message is success for broadcast registration. */
+      success = True; 
+
+      /* Pull the success values from the original request packet. */
+      nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+      ttl = sent_nmb->additional->ttl;
+      putip(&registered_ip,&sent_nmb->additional->rdata[2]);
+    }
+  }
+  else
+  {
+    /* Unicast - if no responses then it's an error. */
+    if(rrec->num_msgs == 0)
+    {
+      DEBUG(2,("register_name_timeout_response: WINS server at address %s is not \
+responding.\n", inet_ntoa(rrec->packet->ip)));
+
+      /* Keep trying to contact the WINS server periodically. This allows
+         us to work correctly if the WINS server is down temporarily when
+         we come up. */
+
+      /* Reset the number of attempts to zero and double the interval between
+         retries. Max out at 5 minutes. */
+      rrec->repeat_count = 3;
+      rrec->repeat_interval *= 2;
+      if(rrec->repeat_interval > (5 * 60))
+        rrec->repeat_interval = (5 * 60);
+      rrec->repeat_time = time(NULL) + rrec->repeat_interval;
+
+      DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
+              rrec->repeat_interval));
+      return; /* Don't remove the response record. */
+    }
+  }
+
+  DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
+        success ? "success" : "failure", namestr(question_name), subrec->subnet_name));
+  if(success)
+  {
+    /* Enter the registered name into the subnet name database before calling
+       the success function. */
+    standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+    if( rrec->success_fn)
+      (*rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+  }
+  else
+  {
+    if( rrec->fail_fn)
+      (*rrec->fail_fn)(subrec, rrec, question_name);
+    /* Remove the name. */
+    standard_fail_register( subrec, rrec, question_name);
+  }
+
+  /* Ensure we don't retry. */
+  remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Try and register one of our names on the unicast subnet - multihomed.
+****************************************************************************/
+
+static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
+                                      register_name_success_function success_fn,
+                                      register_name_fail_function fail_fn,
+                                      struct userdata_struct *userdata)
+{
+  /*
+     If we are adding a group name, we just send multiple
+     register name packets to the WINS server (this is an
+     internet group name.
+
+     If we are adding a unique name, We need first to add 
+     our names to the unicast subnet namelist. This is 
+     because when a WINS server receives a multihomed 
+     registration request, the first thing it does is to 
+     send a name query to the registering machine, to see 
+     if it has put the name in it's local namelist.
+     We need the name there so the query response code in
+     nmbd_incomingrequests.c will find it.
+
+     We are adding this name prematurely (we don't really
+     have it yet), but as this is on the unicast subnet
+     only we will get away with this (only the WINS server
+     will ever query names from us on this subnet).
+   */
+
+  int num_ips=0;
+  int i;
+  struct in_addr *ip_list = NULL;
+  struct subnet_record *subrec;
+
+  for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
+    num_ips++;
+
+  if((ip_list = (struct in_addr *)malloc(num_ips * sizeof(struct in_addr)))==NULL)
+  {
+    DEBUG(0,("multihomed_register_name: malloc fail !\n"));
+    return True;
+  }
+
+  for(subrec = FIRST_SUBNET, i = 0; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ )
+    ip_list[i] = subrec->myip;
+
+  add_name_to_subnet(unicast_subnet, nmbname->name, nmbname->name_type, 
+                     nb_flags, lp_max_ttl(), SELF_NAME, num_ips, ip_list);
+
+  free((char *)ip_list);
+
+  /* Now try and register the name, num_ips times. On the last time use
+     the given success and fail functions. */
+
+  for( i = 0; i < num_ips; i++)
+  {
+    if(queue_register_multihomed_name( unicast_subnet,
+        register_name_response,
+        register_name_timeout_response,
+        (i == num_ips - 1) ? success_fn : NULL,
+        (i == num_ips - 1) ? fail_fn : NULL,
+        (i == num_ips - 1) ? userdata : NULL,
+        nmbname,
+        nb_flags,
+        ip_list[i]) == NULL)
+    {
+      DEBUG(0,("multihomed_register_name: Failed to send packet trying to \
+register name %s IP %s\n", namestr(nmbname), inet_ntoa(ip_list[i]) ));
+      return True;
+    }
+  }
+
+  return False;
+}
+
+/****************************************************************************
+ Try and register one of our names.
+****************************************************************************/
+
+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)
+{
+  struct nmb_name nmbname;
+
+  make_nmb_name(&nmbname, name, type, scope);
+
+  /* Always set the NB_ACTIVE flag on the name we are
+     registering. Doesn't make sense without it.
+   */
+
+  nb_flags |= NB_ACTIVE;
+
+  /* If this is the unicast subnet, and we are a multi-homed
+     host, then register a multi-homed name. */
+
+  if( (subrec == unicast_subnet) && we_are_multihomed())
+    return multihomed_register_name(&nmbname, nb_flags,
+                                    success_fn, fail_fn,
+                                    userdata);
+
+  if(queue_register_name( subrec,
+        register_name_response,
+        register_name_timeout_response,
+        success_fn,
+        fail_fn,
+        userdata,
+        &nmbname,
+        nb_flags) == NULL)
+  {
+    DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
+          namestr(&nmbname)));
+    return True;
+  }
+  return False;
+}
+
+/****************************************************************************
+ Try and refresh one of our names.
+****************************************************************************/
+
+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)
+{
+  int i;
+
+  /* 
+   * Go through and refresh the name for all known ip addresses.
+   * Only call the success/fail function on the last one (it should
+   * only be done once).
+   */
+
+  for( i = 0; i < namerec->num_ips; i++)
+  {
+    if(queue_refresh_name( subrec,
+        register_name_response,
+        register_name_timeout_response,
+        (i == (namerec->num_ips - 1)) ? success_fn : NULL,
+        (i == (namerec->num_ips - 1)) ? fail_fn : NULL,
+        (i == (namerec->num_ips - 1)) ? userdata : NULL,
+        namerec,
+        namerec->ip[i]) == NULL)
+    {
+      DEBUG(0,("refresh_name: Failed to send packet trying to refresh name %s\n",
+            namestr(&namerec->name)));
+      return True;
+    }
+  }
+  return False;
+}
diff --git a/source/nmbd/nmbd_namerelease.c b/source/nmbd/nmbd_namerelease.c
new file mode 100644 (file)
index 0000000..8632dd7
--- /dev/null
@@ -0,0 +1,238 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+
+/****************************************************************************
+ Deal with a response packet when releasing one of our names.
+****************************************************************************/
+
+static void release_name_response(struct subnet_record *subrec,
+                       struct response_record *rrec, struct packet_struct *p)
+{
+  /* 
+   * If we are releasing broadcast, then getting a response is an
+   * error. If we are releasing unicast, then we expect to get a response.
+   */
+
+  struct nmb_packet *nmb = &p->packet.nmb;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  BOOL success = True;
+  struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+  struct nmb_name *answer_name = &nmb->answers->rr_name;
+  struct in_addr released_ip;
+
+  /* Sanity check. Ensure that the answer name in the incoming packet is the
+     same as the requested name in the outgoing packet. */
+
+  if(!nmb_name_equal(question_name, answer_name))
+  {
+    DEBUG(0,("release_name_response: Answer name %s differs from question \
+name %s.\n", namestr(answer_name), namestr(question_name)));
+    return;
+  }
+
+  if(bcast)
+  {
+    /* Someone sent a response. This shouldn't happen/ */
+    DEBUG(1,("release_name_response: A response for releasing name %s was received on a\
+broadcast subnet %s. This should not happen !\n", namestr(answer_name), subrec->subnet_name));
+    return;
+  }
+  else
+  {
+    /* Unicast - check to see if the response allows us to release the name. */
+    if(nmb->header.rcode != 0)
+    {
+      /* Error code - we were told not to release the name ! What now ! */
+      success = False;
+
+      DEBUG(0,("release_name_response: WINS server at IP %s rejected our \
+name release of name %s with error code %d.\n", inet_ntoa(p->ip), 
+                  namestr(answer_name), nmb->header.rcode));
+
+    }
+    else if(nmb->header.opcode == NMB_WACK_OPCODE)
+    {
+      /* WINS server is telling us to wait. Pretend we didn't get
+         the response but don't send out any more release requests. */
+
+      DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \
+name %s on subnet %s.\n", inet_ntoa(p->ip), namestr(answer_name), subrec->subnet_name));
+
+      rrec->repeat_count = 0;
+      /* How long we should wait for. */
+      rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+      rrec->num_msgs--;
+      return;
+    }
+  } 
+
+  DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n",
+        success ? "success" : "failure", namestr(answer_name), subrec->subnet_name));
+
+  if(success)
+  {
+    putip((char*)&released_ip ,&nmb->answers->rdata[2]);
+
+    if(rrec->success_fn)
+      (*rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip);
+    standard_success_release( subrec, rrec->userdata, answer_name, released_ip);
+  }
+  else
+  {
+    /* We have no standard_fail_release - maybe we should add one ? */
+    if(rrec->fail_fn)
+      (*rrec->fail_fn)(subrec, rrec, answer_name);
+  }
+
+  remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when releasing one of our names.
+****************************************************************************/
+
+static void release_name_timeout_response(struct subnet_record *subrec,
+                       struct response_record *rrec)
+{
+  /*
+   * If we are releasing unicast, then NOT getting a response is an
+   * error - we could not release the name. If we are releasing broadcast,
+   * then we don't expect to get a response.
+   */
+
+  struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+  BOOL bcast = sent_nmb->header.nm_flags.bcast;
+  BOOL success = False;
+  struct nmb_name *question_name = &sent_nmb->question.question_name;
+  struct in_addr released_ip;
+
+  if(bcast)
+  {
+    if(rrec->num_msgs == 0)
+    {
+      /* Not receiving a message is success for broadcast release. */
+      success = True; 
+
+      /* Get the ip address we were trying to release. */
+      putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]);
+    }
+  }
+  else
+  {
+    /* Unicast - if no responses then it's an error. */
+    if(rrec->num_msgs == 0)
+    {
+      DEBUG(2,("release_name_timeout_response: WINS server at address %s is not \
+responding.\n", inet_ntoa(rrec->packet->ip)));
+
+      /* Keep trying to contact the WINS server periodically. This allows
+         us to work correctly if the WINS server is down temporarily when
+         we want to delete the name. */
+
+      /* Reset the number of attempts to zero and double the interval between
+         retries. Max out at 5 minutes. */
+      rrec->repeat_count = 3;
+      rrec->repeat_interval *= 2;
+      if(rrec->repeat_interval > (5 * 60))
+        rrec->repeat_interval = (5 * 60);
+      rrec->repeat_time = time(NULL) + rrec->repeat_interval;
+
+      DEBUG(5,("release_name_timeout_response: increasing WINS timeout to %d seconds.\n",
+              rrec->repeat_interval));
+      return; /* Don't remove the response record. */
+    }
+  }
+
+  DEBUG(5,("release_name_timeout_response: %s in releasing name %s on subnet %s.\n",
+        success ? "success" : "failure", namestr(question_name), subrec->subnet_name));
+
+  if(success && rrec->success_fn)
+  {
+    if(rrec->success_fn)
+      (*rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip);
+    standard_success_release( subrec, rrec->userdata, question_name, released_ip);
+  }
+  else 
+  {
+    /* We have no standard_fail_release - maybe we should add one ? */
+    if( rrec->fail_fn)
+      (*rrec->fail_fn)(subrec, rrec, question_name);
+  }
+
+  remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Try and release one of our names.
+****************************************************************************/
+
+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)
+{
+  int i;
+
+  /* Ensure it's a SELF name, and in the ACTIVE state. */
+  if((namerec->source != SELF_NAME) || !NAME_IS_ACTIVE(namerec))
+  {
+    DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n",
+           namestr(&namerec->name), subrec->subnet_name, namerec->source)); 
+    return True;
+  }
+
+  /* Set the name into the deregistering state. */
+  namerec->nb_flags |= NB_DEREG;
+
+  /*  
+   * Go through and release the name for all known ip addresses.
+   * Only call the success/fail function on the last one (it should
+   * only be done once).
+   */
+
+  for( i = 0; i < namerec->num_ips; i++)
+  {
+    if(queue_release_name( subrec,
+        release_name_response,
+        release_name_timeout_response,
+        (i == (namerec->num_ips - 1)) ? success_fn : NULL,
+        (i == (namerec->num_ips - 1)) ? fail_fn : NULL,
+        (i == (namerec->num_ips - 1)) ? userdata : NULL,
+        &namerec->name,
+        namerec->nb_flags,
+        namerec->ip[i]) == NULL)
+    {
+      DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
+            namestr(&namerec->name), inet_ntoa(namerec->ip[i]) ));
+      return True;
+    }
+  }
+  return False;
+}
diff --git a/source/nmbd/nmbd_nodestatus.c b/source/nmbd/nmbd_nodestatus.c
new file mode 100644 (file)
index 0000000..267446c
--- /dev/null
@@ -0,0 +1,99 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+
+/****************************************************************************
+ Deal with a successful node status response.
+****************************************************************************/
+static void node_status_response(struct subnet_record *subrec,
+                       struct response_record *rrec, struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+  struct nmb_name *answer_name = &nmb->answers->rr_name;
+
+  /* Sanity check. Ensure that the answer name in the incoming packet is the
+     same as the requested name in the outgoing packet. */
+
+  if(!nmb_name_equal(question_name, answer_name))
+  {
+    DEBUG(0,("node_status_response: Answer name %s differs from question \
+name %s.\n", namestr(answer_name), namestr(question_name)));
+    return;
+  }
+
+  DEBUG(5,("node_status_response: response from name %s on subnet %s.\n",
+        namestr(answer_name), subrec->subnet_name));
+
+  /* Just send the whole answer resource record for the success function
+     to parse. */
+  if(rrec->success_fn)
+    (*rrec->success_fn)(subrec, rrec->userdata, nmb->answers, p->ip);
+
+  /* Ensure we don't retry. */
+  remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when requesting a node status.
+****************************************************************************/
+static void node_status_timeout_response(struct subnet_record *subrec,
+                       struct response_record *rrec)
+{
+  struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+  struct nmb_name *question_name = &sent_nmb->question.question_name;
+
+  DEBUG(5,("node_status_timeout_response: failed to get node status from name %s on subnet %s\n",
+           namestr(question_name), subrec->subnet_name));
+
+  if( rrec->fail_fn)
+    (*rrec->fail_fn)(subrec, rrec);
+
+  /* Ensure we don't retry. */
+  remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Try and do a node status to a name - given the name & IP address.
+****************************************************************************/
+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)
+{
+  if(queue_node_status( subrec, 
+              node_status_response, node_status_timeout_response,
+              success_fn, fail_fn, userdata, nmbname, send_ip)==NULL)
+  {
+    DEBUG(0,("node_status: Failed to send packet trying to get node status for \
+name %s, IP address %s\n", namestr(nmbname), inet_ntoa(send_ip)));
+    return True;
+  } 
+  return False;
+}
diff --git a/source/nmbd/nmbd_packets.c b/source/nmbd/nmbd_packets.c
new file mode 100644 (file)
index 0000000..43249cc
--- /dev/null
@@ -0,0 +1,1775 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+extern int global_nmb_port;
+
+extern int DEBUGLEVEL;
+
+extern int num_response_packets;
+
+extern pstring scope;
+extern struct in_addr loopback_ip;
+
+/*******************************************************************
+  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;
+
+/***************************************************************************
+Utility function to find the specific fd to send a packet out on.
+**************************************************************************/
+
+static int find_subnet_fd_for_address( struct in_addr local_ip )
+{
+  struct subnet_record *subrec;
+
+  for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+    if(ip_equal(local_ip, subrec->myip))
+      return subrec->nmb_sock;
+
+  return ClientNMB;
+}
+
+/***************************************************************************
+Get/Set problematic nb_flags as network byte order 16 bit int.
+**************************************************************************/
+
+uint16 get_nb_flags(char *buf)
+{
+  return ((((uint16)*buf)&0xFFFF) & NB_FLGMSK);
+}
+
+void set_nb_flags(char *buf, uint16 nb_flags)
+{
+  *buf++ = ((nb_flags & NB_FLGMSK) & 0xFF);
+  *buf = '\0';
+}
+
+/***************************************************************************
+Dumps out the browse packet data.
+**************************************************************************/
+
+static 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"));
+  }
+}
+
+/***************************************************************************
+  Generates the unique transaction identifier
+**************************************************************************/
+
+static uint16 name_trn_id=0;
+
+static uint16 generate_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;
+  return name_trn_id;
+}
+
+/***************************************************************************
+ Either loops back or sends out a completed NetBIOS packet.
+**************************************************************************/
+
+static BOOL send_netbios_packet(struct packet_struct *p)
+{
+  BOOL loopback_this_packet = False;
+
+  /* Check if we are sending to or from ourselves as a WINS server. */
+  if(ismyip(p->ip) && (p->port == global_nmb_port))
+    loopback_this_packet = True;
+
+  if(loopback_this_packet)
+  {
+    struct packet_struct *lo_packet = NULL;
+    DEBUG(5,("send_netbios_packet: sending packet to ourselves.\n"));
+    if((lo_packet = copy_packet(p)) == NULL)
+      return False;
+    queue_packet(lo_packet);
+  }
+  else if (!send_packet(p))
+  {
+    DEBUG(0,("send_netbios_packet: send_packet() to IP %s port %d failed\n",
+                         inet_ntoa(p->ip),p->port));
+    return False;
+  }
+  
+  return True;
+} 
+
+/***************************************************************************
+ Sets up the common elements of an outgoing NetBIOS packet.
+**************************************************************************/
+
+static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname,
+                                                            BOOL bcast,
+                                                            struct in_addr to_ip)
+{
+  struct packet_struct *packet = NULL;
+  struct nmb_packet *nmb = NULL;
+
+  /* Allocate the packet_struct we will return. */
+  if((packet = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+  {
+    DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n"));
+    return NULL;
+  }
+    
+  bzero((char *)packet,sizeof(*packet));
+
+  nmb = &packet->packet.nmb;
+
+  nmb->header.name_trn_id = generate_name_trn_id();
+  nmb->header.response = False;
+  nmb->header.nm_flags.recursion_desired = False;
+  nmb->header.nm_flags.recursion_available = False;
+  nmb->header.nm_flags.trunc = False;
+  nmb->header.nm_flags.authoritative = False;
+  nmb->header.nm_flags.bcast = bcast;
+  
+  nmb->header.rcode = 0;
+  nmb->header.qdcount = 1;
+  nmb->header.ancount = 0;
+  nmb->header.nscount = 0;
+
+  nmb->question.question_name = *nmbname;
+  nmb->question.question_type = QUESTION_TYPE_NB_QUERY;
+  nmb->question.question_class = QUESTION_CLASS_IN;
+
+  packet->ip = to_ip;
+  packet->port = NMB_PORT;
+  packet->fd = ClientNMB;
+  packet->timestamp = time(NULL);
+  packet->packet_type = NMB_PACKET;
+  packet->locked = False;
+  
+  return packet; /* Caller must free. */
+}
+
+/***************************************************************************
+ Sets up the common elements of register, refresh or release packet.
+**************************************************************************/
+
+static BOOL create_and_init_additional_record(struct packet_struct *packet,
+                                                     uint16 nb_flags,
+                                                     struct in_addr *register_ip)
+{
+  struct nmb_packet *nmb = &packet->packet.nmb;
+
+  if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL)
+  {
+    DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
+    return False;
+  }
+
+  bzero((char *)nmb->additional,sizeof(struct res_rec));
+
+  nmb->additional->rr_name  = nmb->question.question_name;
+  nmb->additional->rr_type  = RR_TYPE_NB;
+  nmb->additional->rr_class = RR_CLASS_IN;
+
+  nmb->additional->ttl = lp_max_ttl();
+
+  nmb->additional->rdlength = 6;
+
+  set_nb_flags(nmb->additional->rdata,nb_flags);
+
+  /* Set the address for the name we are registering. */
+  putip(&nmb->additional->rdata[2], register_ip);
+
+  /* Ensure that we send out the file descriptor to give us the
+     the specific source address we are registering as our
+     IP source address. */
+
+  packet->fd = find_subnet_fd_for_address( *register_ip );
+
+  return True;
+}
+
+/***************************************************************************
+ Sends out a name query.
+**************************************************************************/
+
+static BOOL initiate_name_query_packet( struct packet_struct *packet)
+{
+  struct nmb_packet *nmb = NULL;
+
+  nmb = &packet->packet.nmb;
+
+  nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+  nmb->header.arcount = 0;
+
+  nmb->header.nm_flags.recursion_desired = True;
+
+  DEBUG(4,("initiate_name_query_packet: sending query for name %s (bcast=%s) to IP %s\n",
+          namestr(&nmb->question.question_name), 
+           BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+  return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name register.
+**************************************************************************/
+
+static BOOL initiate_name_register_packet( struct packet_struct *packet,
+                                    uint16 nb_flags, struct in_addr *register_ip)
+{
+  struct nmb_packet *nmb = &packet->packet.nmb;
+
+  nmb->header.opcode = NMB_NAME_REG_OPCODE;
+  nmb->header.arcount = 1;
+
+  nmb->header.nm_flags.recursion_desired = True;
+
+  if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+    return False;
+
+  DEBUG(4,("initiate_name_register_packet: sending registration for name %s (bcast=%s) to IP %s\n",
+          namestr(&nmb->additional->rr_name),
+           BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+  return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a multihomed name register.
+**************************************************************************/
+
+static BOOL initiate_multihomed_name_register_packet( struct packet_struct *packet,
+                                    uint16 nb_flags, struct in_addr *register_ip)
+{
+  struct nmb_packet *nmb = &packet->packet.nmb;
+  char second_ip_buf[25];
+
+  strcpy(second_ip_buf, inet_ntoa(packet->ip));
+
+  nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
+  nmb->header.arcount = 1;
+
+  nmb->header.nm_flags.recursion_desired = True;
+
+  if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+    return False;
+
+  DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
+for name %s IP %s (bcast=%s) to IP %s\n",
+          namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
+           BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
+
+  return send_netbios_packet( packet );
+} 
+
+/***************************************************************************
+ Sends out a name refresh.
+**************************************************************************/
+
+static BOOL initiate_name_refresh_packet( struct packet_struct *packet,
+                                   uint16 nb_flags, struct in_addr *refresh_ip)
+{
+  struct nmb_packet *nmb = &packet->packet.nmb;
+
+  nmb->header.opcode = NMB_NAME_REFRESH_OPCODE_8;
+  nmb->header.arcount = 1;
+
+  nmb->header.nm_flags.recursion_desired = False;
+
+  if(create_and_init_additional_record(packet, nb_flags, refresh_ip) == False)
+    return False;
+
+  DEBUG(4,("initiate_name_refresh_packet: sending refresh for name %s (bcast=%s) to IP %s\n",
+          namestr(&nmb->additional->rr_name),
+           BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+  return send_netbios_packet( packet );
+} 
+
+/***************************************************************************
+ Sends out a name release.
+**************************************************************************/
+
+static BOOL initiate_name_release_packet( struct packet_struct *packet,
+                                   uint16 nb_flags, struct in_addr *release_ip)
+{
+  struct nmb_packet *nmb = &packet->packet.nmb;
+
+  nmb->header.opcode = NMB_NAME_RELEASE_OPCODE;
+  nmb->header.arcount = 1;
+
+  nmb->header.nm_flags.recursion_desired = False;
+
+  if(create_and_init_additional_record(packet, nb_flags, release_ip) == False)
+    return False;
+
+  DEBUG(4,("initiate_name_release_packet: sending release for name %s (bcast=%s) to IP %s\n",
+          namestr(&nmb->additional->rr_name),
+           BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+  return send_netbios_packet( packet );
+} 
+
+/***************************************************************************
+ Sends out a node status.
+**************************************************************************/
+
+static BOOL initiate_node_status_packet( struct packet_struct *packet )
+{
+  struct nmb_packet *nmb = &packet->packet.nmb;
+
+  nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+  nmb->header.arcount = 0;
+
+  nmb->header.nm_flags.recursion_desired = False;
+
+  nmb->question.question_type = QUESTION_TYPE_NB_STATUS;
+
+  DEBUG(4,("initiate_node_status_packet: sending node status request for name %s to IP %s\n",
+          namestr(&nmb->question.question_name),
+           inet_ntoa(packet->ip)));
+
+  return send_netbios_packet( packet );
+}
+
+/****************************************************************************
+  Simplification functions for queuing standard packets.
+  These should be the only publicly callable functions for sending
+  out packets.
+****************************************************************************/
+
+/****************************************************************************
+ Assertion - we should never be sending nmbd packets on the remote
+ broadcast subnet.
+****************************************************************************/
+
+static BOOL assert_check_subnet(struct subnet_record *subrec)
+{
+  if( subrec == remote_broadcast_subnet)
+  {
+    DEBUG(0,("assert_check_subnet: Attempt to send packet on remote broadcast subnet. \
+This is a bug.\n"));
+    return True;
+  }
+  return False;
+}
+
+/****************************************************************************
+ Queue a register name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+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 packet_struct *p;
+  struct response_record *rrec;
+  BOOL bcast = (subrec == unicast_subnet) ? False : True;
+
+  if(assert_check_subnet(subrec))
+    return NULL;
+
+  if(( p = create_and_init_netbios_packet(nmbname, bcast, 
+                     subrec->bcast_ip)) == NULL)
+    return NULL;
+
+  if(initiate_name_register_packet( p, nb_flags, 
+                                    iface_ip(subrec->bcast_ip)) == False)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  if((rrec = make_response_record(subrec,           /* subnet record. */
+           p,                     /* packet we sent. */
+           resp_fn,               /* function to call on response. */
+           timeout_fn,            /* function to call on timeout. */
+           (success_function)success_fn,            /* function to call on operation success. */
+           (fail_function)fail_fn,               /* function to call on operation fail. */
+           userdata)) == NULL)  
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  return rrec;
+}
+
+/****************************************************************************
+ Queue a multihomed register name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+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 packet_struct *p;
+  struct response_record *rrec;
+  BOOL bcast = False;
+  BOOL ret;
+     
+  /* Sanity check. */
+  if(subrec != unicast_subnet)
+  {
+    DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+    return NULL;
+  }
+
+  if(assert_check_subnet(subrec))
+    return NULL;
+     
+  if(( p = create_and_init_netbios_packet(nmbname, bcast,
+                             subrec->bcast_ip)) == NULL)
+    return NULL;
+
+  if (nb_flags & NB_GROUP)
+    ret = initiate_name_register_packet( p, nb_flags, &register_ip);
+  else
+    ret = initiate_multihomed_name_register_packet( p, nb_flags, &register_ip);
+
+  if(ret == False)
+  {  
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }  
+  
+  if((rrec = make_response_record(subrec,    /* subnet record. */
+                p,                     /* packet we sent. */
+                resp_fn,               /* function to call on response. */
+                timeout_fn,            /* function to call on timeout. */
+                (success_function)success_fn,            /* function to call on operation success. */
+                (fail_function)fail_fn,               /* function to call on operation fail. */
+                userdata)) == NULL)
+  {  
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }  
+  
+  return rrec;
+}
+
+/****************************************************************************
+ Queue a release name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+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)
+{
+  BOOL bcast = (subrec == unicast_subnet) ? False : True;
+  struct packet_struct *p;
+  struct response_record *rrec;
+
+  if(assert_check_subnet(subrec))
+    return NULL;
+
+  if(( p = create_and_init_netbios_packet(nmbname, bcast, 
+                     subrec->bcast_ip)) == NULL)
+    return NULL;
+
+  if(initiate_name_release_packet( p, nb_flags, &release_ip) == False)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  if((rrec = make_response_record(subrec,           /* subnet record. */
+                    p,                     /* packet we sent. */
+                    resp_fn,               /* function to call on response. */
+                    timeout_fn,            /* function to call on timeout. */
+                    (success_function)success_fn,            /* function to call on operation success. */
+                    (fail_function)fail_fn,               /* function to call on operation fail. */
+                    userdata)) == NULL)  
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  return rrec;
+}
+
+/****************************************************************************
+ Queue a refresh name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+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)
+{
+  BOOL bcast = (subrec == unicast_subnet) ? False : True;
+  struct packet_struct *p;
+  struct response_record *rrec;
+
+  if(assert_check_subnet(subrec))
+    return NULL;
+
+  if(( p = create_and_init_netbios_packet(&namerec->name, bcast,
+                     subrec->bcast_ip)) == NULL)
+    return NULL;
+
+  if(initiate_name_refresh_packet( p, namerec->nb_flags, &refresh_ip) == False)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  if((rrec = make_response_record(subrec,           /* subnet record. */
+                  p,                     /* packet we sent. */
+                  resp_fn,               /* function to call on response. */
+                  timeout_fn,            /* function to call on timeout. */
+                  (success_function)success_fn,            /* function to call on operation success. */
+                  (fail_function)fail_fn,               /* function to call on operation fail. */
+                  userdata)) == NULL)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+  
+  return rrec;
+}
+
+/****************************************************************************
+ Queue a query name packet to the broadcast address of a subnet.
+****************************************************************************/
+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 packet_struct *p;
+  struct response_record *rrec;
+  BOOL bcast = True;
+
+  if ((subrec == unicast_subnet) || (subrec == wins_server_subnet))
+    bcast = False;
+  if(assert_check_subnet(subrec))
+    return NULL;
+
+  if(( p = create_and_init_netbios_packet(nmbname, bcast,
+                     subrec->bcast_ip)) == NULL)
+    return NULL;
+
+  if(initiate_name_query_packet( p ) == False)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  if((rrec = make_response_record(subrec,           /* subnet record. */
+               p,                     /* packet we sent. */
+               resp_fn,               /* function to call on response. */
+               timeout_fn,            /* function to call on timeout. */
+               (success_function)success_fn,            /* function to call on operation success. */
+               (fail_function)fail_fn,               /* function to call on operation fail. */
+               userdata)) == NULL)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  return rrec;
+}
+
+/****************************************************************************
+ Queue a node status packet to a given name and address.
+****************************************************************************/
+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)
+{
+  struct packet_struct *p;
+  struct response_record *rrec;
+  BOOL bcast = False;
+
+  /* Sanity check. */
+  if(subrec != unicast_subnet)
+  {
+    DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+    return NULL;
+  }
+
+  if(assert_check_subnet(subrec))
+    return NULL;
+
+  if(( p = create_and_init_netbios_packet(nmbname, bcast,
+                             send_ip)) == NULL)
+    return NULL;
+
+  if(initiate_node_status_packet(p) == False)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  } 
+
+  if((rrec = make_response_record(subrec,           /* subnet record. */
+                   p,                     /* packet we sent. */
+                   resp_fn,               /* function to call on response. */
+                   timeout_fn,            /* function to call on timeout. */
+                   (success_function)success_fn,            /* function to call on operation success. */
+                   (fail_function)fail_fn,               /* function to call on operation fail. */
+                   userdata)) == NULL)
+  {
+    p->locked = False;
+    free_packet(p);
+    return NULL;
+  }
+
+  return rrec;
+}
+
+/****************************************************************************
+  Reply to a netbios name packet.  see rfc1002.txt
+****************************************************************************/
+
+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)
+{
+  struct packet_struct packet;
+  struct nmb_packet *nmb = NULL;
+  struct res_rec answers;
+  struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
+  BOOL loopback_this_packet = False;
+  char *packet_type = "unknown";
+  
+  /* Check if we are sending to or from ourselves. */
+  if(ismyip(orig_packet->ip) && (orig_packet->port == global_nmb_port))
+    loopback_this_packet = True;
+  
+  nmb = &packet.packet.nmb;
+
+  /* Do a partial copy of the packet. We clear the locked flag and
+     the resource record pointers. */
+  packet = *orig_packet;   /* Full structure copy. */
+  packet.locked = False;
+  nmb->answers = NULL;
+  nmb->nsrecs = NULL;
+  nmb->additional = NULL;
+
+  switch (rcv_code)
+  {
+    case NMB_STATUS:
+    {
+      packet_type = "nmb_status";
+      nmb->header.nm_flags.recursion_desired = False;
+      nmb->header.nm_flags.recursion_available = False;
+      break;
+    }
+    case NMB_QUERY:
+    {
+      packet_type = "nmb_query";
+      nmb->header.nm_flags.recursion_desired = True;
+      nmb->header.nm_flags.recursion_available = True;
+      break;
+    }
+    case NMB_REG:
+    case NMB_REG_REFRESH:
+    {
+      packet_type = "nmb_reg";
+      nmb->header.nm_flags.recursion_desired = True;
+      nmb->header.nm_flags.recursion_available = True;
+      break;
+    }
+    case NMB_REL:
+    {
+      packet_type = "nmb_rel";
+      nmb->header.nm_flags.recursion_desired = False;
+      nmb->header.nm_flags.recursion_available = False;
+      break;
+    }
+    case NMB_WAIT_ACK:
+    {
+      packet_type = "nmb_wack";
+      nmb->header.nm_flags.recursion_desired = False;
+      nmb->header.nm_flags.recursion_available = False;
+      break;
+    }
+    case WINS_REG:
+    {
+      packet_type = "wins_reg";
+      nmb->header.nm_flags.recursion_desired = True;
+      nmb->header.nm_flags.recursion_available = True;
+      break;
+    }
+    case WINS_QUERY:
+    {
+      packet_type = "wins_query";
+      nmb->header.nm_flags.recursion_desired = True;
+      nmb->header.nm_flags.recursion_available = True;
+      break;
+    }
+
+    default:
+    {
+      DEBUG(0,("reply_netbios_packet: Unknown packet type: %s %s to ip %s\n",
+                   packet_type, namestr(&orig_nmb->question.question_name),
+                    inet_ntoa(packet.ip)));
+
+      return;
+    }
+  }
+
+  DEBUG(4,("reply_netbios_packet: sending a reply of packet type: %s %s to ip %s \
+for id %hu\n",
+          packet_type, namestr(&orig_nmb->question.question_name),
+           inet_ntoa(packet.ip), orig_nmb->header.name_trn_id));
+
+  nmb->header.name_trn_id = orig_nmb->header.name_trn_id;
+  nmb->header.opcode = opcode;
+  nmb->header.response = True;
+  nmb->header.nm_flags.bcast = False;
+  nmb->header.nm_flags.trunc = False;
+  nmb->header.nm_flags.authoritative = True;
+  
+  nmb->header.rcode = rcode;
+  nmb->header.qdcount = 0;
+  nmb->header.ancount = 1;
+  nmb->header.nscount = 0;
+  nmb->header.arcount = 0;
+  
+  bzero((char*)&nmb->question,sizeof(nmb->question));
+  
+  nmb->answers = &answers;
+  bzero((char*)nmb->answers,sizeof(*nmb->answers));
+  
+  nmb->answers->rr_name  = orig_nmb->question.question_name;
+  nmb->answers->rr_type  = orig_nmb->question.question_type;
+  nmb->answers->rr_class = orig_nmb->question.question_class;
+  nmb->answers->ttl      = ttl;
+  
+  if (data && len)
+  {
+    nmb->answers->rdlength = len;
+    memcpy(nmb->answers->rdata, data, len);
+  }
+  
+  packet.packet_type = NMB_PACKET;
+  /* Ensure we send out on the same fd that the original
+     packet came in on to give the correct source IP address. */
+  packet.fd = orig_packet->fd;
+  packet.timestamp = time(NULL);
+
+  debug_nmb_packet(&packet);
+  
+  if(loopback_this_packet)
+  {
+    struct packet_struct *lo_packet;
+    DEBUG(5,("reply_netbios_packet: sending packet to ourselves.\n"));
+    if((lo_packet = copy_packet(&packet)) == NULL)
+      return;
+    queue_packet(lo_packet);
+  }
+  else if (!send_packet(&packet)) 
+  {
+    DEBUG(0,("reply_netbios_packet: send_packet to IP %s port %d failed\n",
+                 inet_ntoa(packet.ip),packet.port));
+  }
+}
+
+/*******************************************************************
+  Queue a packet into a 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;
+}
+
+/****************************************************************************
+ Try and find a matching subnet record for a datagram port 138 packet.
+****************************************************************************/
+
+static struct subnet_record *find_subnet_for_dgram_browse_packet(struct packet_struct *p)
+{
+  struct subnet_record *subrec;
+
+  /* Go through all the broadcast subnets and see if the mask matches. */
+  for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+      return subrec;
+  }
+
+  /* If the subnet record is the remote announce broadcast subnet,
+     hack it here to be the first subnet. This is really gross and
+     is needed due to people turning on port 137/138 broadcast
+     forwarding on their routers. May fire and brimstone rain
+     down upon them...
+   */
+
+  return FIRST_SUBNET;
+}
+
+/****************************************************************************
+Dispatch a browse frame from port 138 to the correct processing function.
+****************************************************************************/
+
+void process_browse_packet(struct packet_struct *p, char *buf,int len)
+{
+  struct dgram_packet *dgram = &p->packet.dgram;
+  int command = CVAL(buf,0);
+  struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
+
+  /* Drop the packet if it's a different NetBIOS scope, or
+     the source is from one of our names. */
+
+  if (!strequal(dgram->dest_name.scope,scope ))
+  {
+    DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Scope (%s) \
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, scope));
+    return;
+  }
+
+  if (is_myname(dgram->source_name.name))
+  {
+    DEBUG(0,("process_browse_packet: Discarding datagram from IP %s. Source name \
+%s is one of our names !\n", inet_ntoa(p->ip), namestr(&dgram->source_name)));
+    return;
+  }
+
+  switch (command)
+  {
+    case ANN_HostAnnouncement:
+    {
+      debug_browse_data(buf, len);
+      process_host_announce(subrec, p, buf+1);
+      break;
+    }
+    case ANN_DomainAnnouncement:
+    {
+      debug_browse_data(buf, len);
+      process_workgroup_announce(subrec, p, buf+1);
+      break;
+    }
+    case ANN_LocalMasterAnnouncement:
+    {
+      debug_browse_data(buf, len);
+      process_local_master_announce(subrec, p, buf+1);
+      break;
+    }
+    case ANN_AnnouncementRequest:
+    {
+      process_announce_request(subrec, p, buf+1);
+      break;
+    }
+    case ANN_Election:
+    {
+      process_election(subrec, p, buf+1);
+      break;
+    }
+    case ANN_GetBackupListReq:
+    {
+      debug_browse_data(buf, len);
+
+      /* This is one occasion where we change a subnet that is
+        given to us. If the packet was sent to WORKGROUP<1b> instead
+        of WORKGROUP<1d> then it was unicast to us a domain master
+        browser. Change subrec to unicast.
+      */
+      if(dgram->dest_name.name_type == 0x1b)
+        subrec = unicast_subnet;
+
+      process_get_backup_list_request(subrec, p, buf+1);
+      break;
+    }
+    case ANN_GetBackupListResp:
+    {
+      debug_browse_data(buf, len);
+      /* We never send ANN_GetBackupListReq so we
+         should never get these. */
+      DEBUG(0,("process_browse_packet: Discarding GetBackupListResponse \
+packet from %s IP %s\n", namestr(&dgram->source_name), inet_ntoa(p->ip)));
+      break;
+    }
+    case ANN_ResetBrowserState:
+    {
+      process_reset_browser(subrec, p, buf+1);
+      break;
+    }
+    case ANN_MasterAnnouncement:
+    {
+      /* Master browser datagrams must be processed
+         on the unicast subnet. */
+      subrec = unicast_subnet;
+
+      process_master_browser_announce(subrec, p, buf+1);
+      break;
+    }
+    default:
+    {
+      DEBUG(0,("process_browse_packet: On subnet %s ignoring browse packet \
+command code %d from %s IP %s to %s\n", 
+            subrec->subnet_name, command, namestr(&dgram->source_name),
+            inet_ntoa(p->ip), namestr(&dgram->dest_name)));
+    }
+  } 
+}
+
+/****************************************************************************
+  Determine if a packet is for us on port 138. 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. 
+****************************************************************************/
+
+static BOOL listening(struct packet_struct *p,struct nmb_name *nbname)
+{
+  struct subnet_record *subrec = NULL;
+
+  for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+      break;
+  }
+
+  if(subrec == NULL)
+    subrec = unicast_subnet;
+
+  return (find_name_on_subnet(subrec, nbname, FIND_SELF_NAME) != 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 from %s\n",
+           namestr(&dgram->dest_name), 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 from IP %s as it is \
+           an error packet of type %x\n",
+           namestr(&dgram->dest_name), 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 IP %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 logon 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 logon mailslot */
+  if (strequal(smb_buf(buf),NT_LOGON_MAILSLOT))
+  {
+    process_logon_packet(p,buf2,len,NT_LOGON_MAILSLOT);
+    return;
+  }
+}
+
+/****************************************************************************
+  Validate a response nmb packet.
+****************************************************************************/
+
+BOOL validate_nmb_response_packet( struct nmb_packet *nmb )
+{
+  BOOL ignore = False;
+
+  switch (nmb->header.opcode) 
+  {
+    case NMB_NAME_REG_OPCODE:
+    case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+    case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+      if (nmb->header.ancount == 0)
+      {
+        DEBUG(0,("validate_nmb_response_packet: Bad REG/REFRESH Packet. "));
+        ignore = True;
+      }
+      break;
+
+    case NMB_NAME_QUERY_OPCODE:
+      if ((nmb->header.ancount != 0) && (nmb->header.ancount != 1))
+      {
+        DEBUG(0,("validate_nmb_response_packet: Bad QUERY Packet. "));
+        ignore = True;
+      }
+      break;
+    case NMB_NAME_RELEASE_OPCODE:
+      if (nmb->header.ancount == 0)
+      {
+        DEBUG(0,("validate_nmb_response_packet: Bad RELEASE Packet. "));
+        ignore = True;
+      }
+      break;
+    case NMB_WACK_OPCODE:
+      /* Check WACK response here. */
+      if (nmb->header.ancount != 1)
+      {
+        DEBUG(0,("validate_nmb_response_packet: Bad WACK Packet. "));
+        ignore = True;
+      }
+      break;
+    default:
+      DEBUG(0,("validate_nmb_response_packet: Ignoring packet with unknown opcode %d.\n",
+        nmb->header.opcode));
+      return True;
+  }
+
+  if(ignore)
+    DEBUG(0,("Ignoring response packet with opcode %d.\n", nmb->header.opcode));
+
+  return ignore;
+}
+/****************************************************************************
+  Validate a request nmb packet.
+****************************************************************************/
+
+BOOL validate_nmb_packet( struct nmb_packet *nmb )
+{
+  BOOL ignore = False;
+
+  switch (nmb->header.opcode) 
+  {
+    case NMB_NAME_REG_OPCODE:
+    case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+    case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+    case NMB_NAME_MULTIHOMED_REG_OPCODE:
+      if (nmb->header.qdcount==0 || nmb->header.arcount==0)
+      {
+        DEBUG(0,("validate_nmb_packet: Bad REG/REFRESH Packet. "));
+        ignore = True;
+      }
+      break;
+
+    case NMB_NAME_QUERY_OPCODE:
+      if ((nmb->header.qdcount == 0) || 
+         ((nmb->question.question_type != QUESTION_TYPE_NB_QUERY) &&
+         (nmb->question.question_type != QUESTION_TYPE_NB_STATUS)))
+      {
+        DEBUG(0,("validate_nmb_packet: Bad QUERY Packet. "));
+        ignore = True;
+      }
+      break;
+
+    case NMB_NAME_RELEASE_OPCODE:
+      if (nmb->header.qdcount==0 || nmb->header.arcount==0)
+      {
+        DEBUG(0,("validate_nmb_packet: Bad RELEASE Packet. "));
+        ignore = True;
+      }
+      break;
+    default:
+      DEBUG(0,("validate_nmb_packet: Ignoring packet with unknown opcode %d.\n",
+        nmb->header.opcode));
+      return True;
+  }
+
+  if(ignore)
+    DEBUG(0,("validate_nmb_packet: Ignoring request packet with opcode %d.\n", nmb->header.opcode));
+
+  return ignore;
+}
+
+/****************************************************************************
+  Find a subnet (and potentially a response record) for a packet.
+****************************************************************************/
+
+static struct subnet_record *find_subnet_for_nmb_packet( struct packet_struct *p,
+                                                         struct response_record **pprrec)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct response_record *rrec = NULL;
+  struct subnet_record *subrec = NULL;
+
+  if(pprrec != NULL)
+    *pprrec = NULL;
+
+  if(nmb->header.response)
+  {
+    /* It's a response packet. Find a record for it or it's an error. */
+
+    rrec = find_response_record( &subrec, nmb->header.name_trn_id);
+    if(rrec == NULL)
+    {
+      DEBUG(0,("find_subnet_for_nmb_packet: response record not found for response id %hu\n",
+               nmb->header.name_trn_id));
+      return NULL;
+    }
+
+    if(subrec == NULL)
+    {
+      DEBUG(0,("find_subnet_for_nmb_packet: subnet record not found for response id %hu\n",
+               nmb->header.name_trn_id));
+      return NULL;
+    }
+
+    if(pprrec != NULL)
+      *pprrec = rrec;
+    return subrec;
+  }
+
+  /* Try and see what subnet this packet belongs to. */
+
+  /* WINS server ? */
+  if(packet_is_for_wins_server(p))
+    return wins_server_subnet;
+
+  /* If it wasn't a broadcast packet then send to the UNICAST subnet. */
+  if(nmb->header.nm_flags.bcast == False)
+    return unicast_subnet;
+
+  /* Go through all the broadcast subnets and see if the mask matches. */
+  for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+      return subrec;
+  }
+
+  /* If none match it must have been a directed broadcast - assign
+     the remote_broadcast_subnet. */
+  return remote_broadcast_subnet;
+}
+
+/****************************************************************************
+  Process a nmb request packet - validate the packet and route it.
+****************************************************************************/
+
+static void process_nmb_request(struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct subnet_record *subrec = NULL;
+
+  debug_nmb_packet(p);
+
+  /* Ensure we have a good packet. */
+  if(validate_nmb_packet(nmb))
+    return;
+
+  /* Allocate a subnet to this packet - if we cannot - fail. */
+  if((subrec = find_subnet_for_nmb_packet(p, NULL))==NULL)
+    return;
+
+  switch (nmb->header.opcode) 
+  {
+    case NMB_NAME_REG_OPCODE:
+      if(subrec == wins_server_subnet)
+        wins_process_name_registration_request(subrec, p);
+      else
+        process_name_registration_request(subrec, p);
+      break;
+
+    case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+    case NMB_NAME_REFRESH_OPCODE_9:
+      if(subrec == wins_server_subnet)
+        wins_process_name_refresh_request(subrec, p);
+      else
+        process_name_refresh_request(subrec, p);
+      break;
+
+    case NMB_NAME_MULTIHOMED_REG_OPCODE:
+      if(subrec == wins_server_subnet)
+        wins_process_multihomed_name_registration_request(subrec, p);
+      else
+      {
+        DEBUG(0,("process_nmb_request: Multihomed registration request must be \
+directed at a WINS server.\n"));
+      }
+      break;
+
+    case NMB_NAME_QUERY_OPCODE:
+      switch (nmb->question.question_type)
+      {
+        case QUESTION_TYPE_NB_QUERY:
+        {
+          if(subrec == wins_server_subnet)
+            wins_process_name_query_request(subrec, p);
+          else
+            process_name_query_request(subrec, p);
+          break;
+        }
+        case QUESTION_TYPE_NB_STATUS:
+        {
+          if(subrec == wins_server_subnet)
+          {
+            DEBUG(0,("process_nmb_request: NB_STATUS request directed at WINS server is \
+not allowed.\n"));
+            break;
+          }
+          else
+            process_node_status_request(subrec, p);
+          break;
+        }
+      }
+      break;
+      
+    case NMB_NAME_RELEASE_OPCODE:
+      if(subrec == wins_server_subnet)
+        wins_process_name_release_request(subrec, p);
+      else
+        process_name_release_request(subrec, p);
+      break;
+  }
+}
+
+/****************************************************************************
+  Process a nmb response packet - validate the packet and route it.
+  to either the WINS server or a normal response.
+****************************************************************************/
+
+static void process_nmb_response(struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct subnet_record *subrec = NULL;
+  struct response_record *rrec = NULL;
+
+  debug_nmb_packet(p);
+
+  if(validate_nmb_response_packet(nmb))
+    return;
+
+  if((subrec = find_subnet_for_nmb_packet(p, &rrec))==NULL)
+    return;
+
+  if(rrec == NULL)
+  {
+    DEBUG(0,("process_nmb_response: response packet received but no response record \
+found for id = %hu. Ignoring packet.\n", nmb->header.name_trn_id));
+    return;
+  }
+
+  /* Increment the number of responses received for this record. */
+  rrec->num_msgs++;
+  /* Ensure we don't re-send the request. */
+  rrec->repeat_count = 0;
+  
+  /* Call the response received function for this packet. */
+  (*rrec->resp_fn)(subrec, rrec, p);
+}
+
+
+/*******************************************************************
+  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:
+        if(p->packet.nmb.header.response)
+          process_nmb_response(p);
+        else
+          process_nmb_request(p);
+        break;
+
+      case DGRAM_PACKET:
+        process_dgram(p);
+        break;
+    }
+    free_packet(p);
+  }
+} 
+
+/*******************************************************************
+ Retransmit or timeout elements from all the outgoing subnet response
+ record queues.
+******************************************************************/
+
+void retransmit_or_expire_response_records(time_t t)
+{
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    struct response_record *rrec, *nextrrec;
+
+    for (rrec = subrec->responselist; rrec; rrec = nextrrec)
+    {
+      nextrrec = rrec->next;
+   
+      if (rrec->repeat_time <= t) 
+      {
+        if (rrec->repeat_count > 0)
+        {
+          /* Resend while we have a non-zero repeat_count. */
+          if(!send_packet(rrec->packet))
+          {
+            DEBUG(0,("retransmit_or_expire_response_records: Failed to resend packet id %hu \
+to IP %s on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), 
+                          subrec->subnet_name));
+          }
+          rrec->repeat_time += rrec->repeat_interval;
+          rrec->repeat_count--;
+        }
+        else
+        {
+          DEBUG(4,("retransmit_or_expire_response_records: timeout for packet id %hu to IP %s \
+on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), 
+                 subrec->subnet_name));
+
+          /* Call the timeout function. This will deal with removing the
+             timed out packet. */
+          if(rrec->timeout_fn)
+            (*rrec->timeout_fn)(subrec, rrec);
+          else
+          {
+            /* We must remove the record ourself if there is
+               no timeout function. */
+            remove_response_record(subrec, rrec);
+          }
+        } /* rrec->repeat_count > 0 */
+      } /* rrec->repeat_time <= t */
+    } /* end for rrec */
+  } /* end for subnet */
+}
+
+/****************************************************************************
+  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 *subrec = 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 (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+    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 (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    FD_SET(subrec->nmb_sock,pset);
+    sock_array[num++] = subrec->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 (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    FD_SET(subrec->dgram_sock,pset);
+    sock_array[num++] = subrec->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 == global_nmb_port)
+            {
+              DEBUG(7,("discarding own packet from %s:%d\n",
+                        inet_ntoa(packet->ip),packet->port));    
+              free_packet(packet);
+            }
+            else
+            {
+              /* Save the file descriptor this packet came in on. */
+              packet->fd = sock_array[i];
+              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
+            {
+              /* Save the file descriptor this packet came in on. */
+              packet->fd = sock_array[i];
+              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 packets to port 138.
+**************************************************************************/
+
+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)
+{
+  BOOL loopback_this_packet = False;
+  struct packet_struct p;
+  struct dgram_packet *dgram = &p.packet.dgram;
+  char *ptr,*p2;
+  char tmp[4];
+
+  bzero((char *)&p,sizeof(p));
+
+  if(ismyip(dest_ip))
+    loopback_this_packet = True;
+
+  generate_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,0,scope);
+  make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
+
+  ptr = &dgram->data[0];
+
+  /* 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 = ClientDGRAM;
+  p.timestamp = time(NULL);
+  p.packet_type = DGRAM_PACKET;
+
+  DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
+                    namestr(&dgram->source_name), inet_ntoa(src_ip)));
+  DEBUG(4,("to %s IP %s\n", namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
+
+  debug_browse_data(buf, len);
+
+  if(loopback_this_packet)
+  {
+    struct packet_struct *lo_packet = NULL;
+    DEBUG(5,("send_mailslot: sending packet to ourselves.\n"));
+    if((lo_packet = copy_packet(&p)) == NULL)
+      return False;
+    queue_packet(lo_packet);
+    return True;
+  }
+  else
+    return(send_packet(&p));
+}
diff --git a/source/nmbd/nmbd_processlogon.c b/source/nmbd/nmbd_processlogon.c
new file mode 100644 (file)
index 0000000..ae91756
--- /dev/null
@@ -0,0 +1,250 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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:
+
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+extern fstring myworkgroup;
+
+/****************************************************************************
+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,("process_logon_packet: Logon packet received from IP %S and domain \
+logons are not enabled.\n", inet_ntoa(p->ip) ));
+    return;
+  }
+
+  strcpy(my_name, myname);
+  strupper(my_name);
+
+  code = SVAL(buf,0);
+  DEBUG(1,("process_logon_packet: Logon from %s: code = %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,("process_logon_packet: Domain login request from %s at IP %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(True, getdc, 
+                    outbuf,PTR_DIFF(q,outbuf),
+                    dgram->dest_name.name,
+                    dgram->dest_name.name_type,
+                    dgram->source_name.name,
+                    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, myworkgroup); /* 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,("process_logon_packet: GETDC request from %s at IP %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(True, getdc,
+                  outbuf,PTR_DIFF(q,outbuf),
+                  dgram->dest_name.name,
+                  dgram->dest_name.name_type,
+                  dgram->source_name.name,
+                  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,("process_logon_packet: 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,("process_logon_packet: 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,("process_logon_packet: SAMLOGON request from %s(%s) for %s, not in password file\n",
+           unistr(unicomp),inet_ntoa(p->ip), ascuser));
+        return;
+      }
+      else
+      {
+        DEBUG(3,("process_logon_packet: 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, myworkgroup,
+           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(True, getdc,
+                   outbuf,PTR_DIFF(q,outbuf),
+                   dgram->dest_name.name,
+                   dgram->dest_name.name_type,
+                   dgram->source_name.name,
+                   dgram->source_name.name_type,
+                   p->ip, *iface_ip(p->ip));  
+      break;
+    }
+
+    default:
+    {
+      DEBUG(3,("process_logon_packet: Unknown domain request %d\n",code));
+      return;
+    }
+  }
+}
diff --git a/source/nmbd/nmbd_responserecordsdb.c b/source/nmbd/nmbd_responserecordsdb.c
new file mode 100644 (file)
index 0000000..bc0c074
--- /dev/null
@@ -0,0 +1,238 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios library routines
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+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 *subrec,
+                               struct response_record *rrec)
+{
+  struct response_record *rrec2;
+
+  num_response_packets++; /* count of total number of packets still around */
+
+  DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n",
+            rrec->response_id, subrec->subnet_name, num_response_packets));
+
+  if (!subrec->responselist)
+  {
+    subrec->responselist = rrec;
+    rrec->prev = NULL;
+    rrec->next = NULL;
+    return;
+  }
+  
+  for (rrec2 = subrec->responselist; rrec2->next; rrec2 = rrec2->next) 
+    ;
+  
+  rrec2->next = rrec;
+  rrec->next = NULL;
+  rrec->prev = rrec2;
+}
+
+/***************************************************************************
+  Remove an expected response record from the list
+  **************************************************************************/
+
+void remove_response_record(struct subnet_record *subrec,
+                               struct response_record *rrec)
+{
+  if (rrec->prev)
+    rrec->prev->next = rrec->next;
+  if (rrec->next)
+    rrec->next->prev = rrec->prev;
+
+  if (subrec->responselist == rrec) 
+    subrec->responselist = rrec->next; 
+
+  if(rrec->userdata)
+  {
+    if(rrec->userdata->free_fn)
+      (*rrec->userdata->free_fn)(rrec->userdata);
+    else
+      free((char *)rrec->userdata);
+  }
+
+  /* Ensure we can delete. */
+  rrec->packet->locked = False;
+  free_packet(rrec->packet);
+
+  free((char *)rrec);
+
+  num_response_packets--; /* count of total number of packets still around */
+}
+
+/****************************************************************************
+  Create a response record for an outgoing packet.
+  **************************************************************************/
+
+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 *rrec;
+  struct nmb_packet *nmb = &p->packet.nmb;
+
+  if (!(rrec = (struct response_record *)malloc(sizeof(*rrec)))) 
+  {
+    DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n"));
+    return NULL;
+  }
+
+  bzero((char *)rrec, sizeof(*rrec));
+
+  rrec->response_id = nmb->header.name_trn_id;
+
+  rrec->resp_fn = resp_fn;
+  rrec->timeout_fn = timeout_fn;
+  rrec->success_fn = success_fn;
+  rrec->fail_fn = fail_fn;
+
+  rrec->packet = p;
+
+  if(userdata)
+  {
+    /* Intelligent userdata. */
+    if(userdata->copy_fn)
+    {
+      if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL)
+      {
+        DEBUG(0,("make_response_queue_record: copy fail for userdata.\n"));
+        free(rrec);
+        return NULL;
+      }
+    }
+    else
+    {
+      /* Primitive userdata, do a memcpy. */
+      if((rrec->userdata = (struct userdata_struct *)
+           malloc(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL)
+      {
+        DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n"));
+        free(rrec);
+        return NULL;
+      }
+      rrec->userdata->copy_fn = userdata->copy_fn;
+      rrec->userdata->free_fn = userdata->free_fn;
+      rrec->userdata->userdata_len = userdata->userdata_len;
+      memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len);
+    }
+  }
+  else
+    rrec->userdata = NULL;
+
+  rrec->num_msgs = 0;
+
+  if(!nmb->header.nm_flags.bcast)
+    rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */
+  else
+    rrec->repeat_interval = 1; /* XXXX should be in ms */
+  rrec->repeat_count = 3; /* 3 retries */
+  rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */
+
+  /* Lock the packet so we won't lose it while it's on the list. */
+  p->locked = True;
+
+  add_response_record(subrec, rrec);
+
+  return rrec;
+}
+
+/****************************************************************************
+  Find a response in a subnet's name query response list. 
+  **************************************************************************/
+
+static struct response_record *find_response_record_on_subnet(
+                                struct subnet_record *subrec, uint16 id)
+{  
+  struct response_record *rrec = NULL;
+
+  for (rrec = subrec->responselist; rrec; rrec = rrec->next)
+  {
+    if (rrec->response_id == id) 
+    {
+      DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n",
+               id, subrec->subnet_name));
+      break;
+    }
+  }
+  return rrec;
+}
+
+/****************************************************************************
+  Find a response in any subnet's name query response list. 
+  **************************************************************************/
+
+struct response_record *find_response_record(struct subnet_record **ppsubrec,
+                               uint16 id)
+{  
+  struct response_record *rrec = NULL;
+
+  for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec); 
+                  (*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec))
+  {
+    if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL)
+      return rrec;
+  }
+
+  /* There should never be response records on the remote_broadcast subnet.
+     Sanity check to ensure this is so. */
+  if(remote_broadcast_subnet->responselist != NULL)
+  {
+    DEBUG(0,("find_response_record: response record found on subnet %s. This should \
+never happen !\n", remote_broadcast_subnet->subnet_name));
+  }
+
+  /* Now check the WINS server subnet if it exists. */
+  if(wins_server_subnet != NULL)
+  {
+    *ppsubrec = wins_server_subnet;
+    if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL)
+      return rrec;
+  }
+
+  DEBUG(0,("find_response_record: repsonse packet id %hu received with no \
+matching record.\n", id));
+  *ppsubrec = NULL;
+
+  return NULL;
+}
diff --git a/source/nmbd/nmbd_sendannounce.c b/source/nmbd/nmbd_sendannounce.c
new file mode 100644 (file)
index 0000000..e4b288a
--- /dev/null
@@ -0,0 +1,477 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+extern int  updatecount;
+
+/****************************************************************************
+ Send a browser reset packet.
+**************************************************************************/
+
+void send_browser_reset(int reset_type, char *to_name, int to_type, struct in_addr to_ip)
+{
+  pstring outbuf;
+  char *p;
+
+  DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
+       reset_type, to_name, to_type, inet_ntoa(to_ip) ));
+
+  bzero(outbuf,sizeof(outbuf));
+  p = outbuf;
+  CVAL(p,0) = ANN_ResetBrowserState;
+  p++;
+  CVAL(p,0) = reset_type;
+  p++;
+
+  send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+                myname, 0x0, to_name, to_type, to_ip, FIRST_SUBNET->myip);
+}
+
+/****************************************************************************
+  Broadcast a packet to the local net requesting that all servers in this
+  workgroup announce themselves to us.
+  **************************************************************************/
+
+void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
+{
+  pstring outbuf;
+  char *p;
+
+  work->needannounce = True;
+
+  DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
+to subnet %s\n", work->work_group, subrec->subnet_name));
+
+  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,15);
+  strupper(p);
+  p = skip_string(p,1);
+  
+  send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+                myname, 0x0, work->work_group,0x1e, subrec->bcast_ip, subrec->myip);
+}
+
+/****************************************************************************
+  Broadcast an announcement.
+  **************************************************************************/
+
+static void send_announcement(struct subnet_record *subrec, int announce_type,
+                              char *from_name, 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;
+
+  CVAL(outbuf,0) = announce_type;
+
+  /* Announcement parameters. */
+  CVAL(p,0) = updatecount;
+  SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
+
+  StrnCpy(p+5,server_name,15);
+  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);
+
+  send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
+                from_name, 0x0, to_name, to_type, to_ip, subrec->myip);
+}
+
+/****************************************************************************
+ We are a local master browser. Announce this to WORKGROUP<1e>.
+****************************************************************************/
+
+static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
+                                           struct server_record *servrec)
+{
+  /* Ensure we don't have the prohibited bit set. */
+  uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+  DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
+            type, myname, subrec->subnet_name, work->work_group));
+
+  send_announcement(subrec, ANN_LocalMasterAnnouncement,
+                    myname,                          /* From nbt name. */
+                    work->work_group, 0x1e,          /* To nbt name. */
+                    subrec->bcast_ip,                /* To ip. */
+                    work->announce_interval,         /* Time until next announce. */
+                    myname,                          /* Name to announce. */
+                    type,                            /* Type field. */
+                    servrec->serv.comment);
+}
+
+/****************************************************************************
+ Announce the workgroup WORKGROUP to MSBROWSE<01>.
+****************************************************************************/
+
+static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
+{
+  DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
+            subrec->subnet_name, work->work_group));
+
+  send_announcement(subrec, ANN_DomainAnnouncement,
+                    myname,                          /* From nbt name. */
+                    MSBROWSE, 0x1,                   /* To nbt name. */
+                    subrec->bcast_ip,                /* To ip. */
+                    work->announce_interval,         /* Time until next announce. */
+                    work->work_group,                /* Name to announce. */
+                    SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT,  /* workgroup announce flags. */
+                    myname);                         /* From name as comment. */
+}
+
+/****************************************************************************
+ Announce the given host to WORKGROUP<1d>.
+****************************************************************************/
+
+static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
+                                   struct server_record *servrec)
+{
+  /* Ensure we don't have the prohibited bits set. */
+  uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+  DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
+            type, servrec->serv.name, subrec->subnet_name, work->work_group));
+
+  send_announcement(subrec, ANN_HostAnnouncement,
+                    servrec->serv.name,              /* From nbt name. */
+                    work->work_group, 0x1d,          /* To nbt name. */
+                    subrec->bcast_ip,                /* To ip. */
+                    work->announce_interval,         /* Time until next announce. */
+                    servrec->serv.name,              /* Name to announce. */
+                    type,                            /* Type field. */
+                    servrec->serv.comment);
+}
+
+/****************************************************************************
+  Announce a server record.
+  ****************************************************************************/
+
+static void announce_server(struct subnet_record *subrec, struct work_record *work,
+                     struct server_record *servrec)
+{
+  /* Only do domain announcements if we are a master and it's
+     our primary name we're being asked to announce. */
+
+  if (AM_LOCAL_MASTER_BROWSER(work) && strequal(myname,servrec->serv.name))
+  {
+    send_local_master_announcement(subrec, work, servrec);
+    send_workgroup_announcement(subrec, work);
+  }
+  else
+  {
+    send_host_announcement(subrec, work, servrec);
+  }
+}
+
+/****************************************************************************
+  Go through all my registered names on all broadcast subnets and announce
+  them if the timeout requires it.
+  **************************************************************************/
+
+void announce_my_server_names(time_t t)
+{
+  struct subnet_record *subrec;
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work = find_workgroup_on_subnet(subrec, myworkgroup);
+
+    if(work)
+    {
+      struct server_record *servrec;
+
+      if (work->needannounce)
+      {
+        /* Drop back to a max 3 minute announce. This is to prevent a
+           single lost packet from breaking things for too long. */
+
+        work->announce_interval = MIN(work->announce_interval,
+                                    CHECK_TIME_MIN_HOST_ANNCE*60);
+        work->lastannounce_time = t - (work->announce_interval+1);
+        work->needannounce = False;
+      }
+
+      /* Announce every minute at first then progress to every 12 mins */
+      if ((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 (servrec = work->serverlist; servrec; servrec = servrec->next)
+      {
+        if (is_myname(servrec->serv.name))
+          announce_server(subrec, work, servrec);
+      }
+    } /* if work */
+  } /* for subrec */
+}
+
+/* Announce timer. Moved into global static so it can be reset
+   when a machine becomes a local master browser. */
+static time_t announce_timer_last=0;
+
+/****************************************************************************
+ Reset the announce_timer so that a local 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 local master browser to a domain master browser.
+  **************************************************************************/
+
+void announce_myself_to_domain_master_browser(time_t t)
+{
+  struct subnet_record *subrec;
+  struct work_record *work;
+
+  if(!we_are_a_wins_client())
+  {
+    DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
+    return;
+  }
+
+  if (!announce_timer_last)
+    announce_timer_last = t;
+
+  if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60))
+  {
+    DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
+               t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 ));
+    return;
+  }
+
+  announce_timer_last = t;
+
+  /* Look over all our broadcast subnets to see if any of them
+     has the state set as local master browser. */
+
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    for (work = subrec->workgrouplist; work; work = work->next)
+    {
+      if (AM_LOCAL_MASTER_BROWSER(work))
+      {
+        DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
+workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
+
+        /* Look in nmbd_browsersync.c for the rest of this code. */
+        announce_and_sync_with_domain_master_browser(subrec, work);
+      }
+    }
+  }
+}
+
+/****************************************************************************
+Announce all samba's server entries as 'gone'.
+This must *only* be called on shutdown.
+****************************************************************************/
+
+void announce_my_servers_removed(void)
+{
+  struct subnet_record *subrec; 
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work;
+    for (work = subrec->workgrouplist; work; work = work->next)
+    {
+      struct server_record *servrec;
+
+      work->announce_interval = 0;
+      for (servrec = work->serverlist; servrec; servrec = servrec->next)
+      {
+        if (!is_myname(servrec->serv.name))
+          continue;
+        servrec->serv.type = 0;
+        if(AM_LOCAL_MASTER_BROWSER(work))
+          send_local_master_announcement(subrec, work, servrec);
+        send_host_announcement(subrec, work, servrec);
+      }
+    }
+  }
+}
+
+/****************************************************************************
+  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 local master browser 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;
+  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();
+
+  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 i;
+
+    wgroup = strchr(s2,'/');
+    if (wgroup)
+      *wgroup++ = 0;
+    if (!wgroup || !*wgroup)
+      wgroup = myworkgroup;
+
+    addr = *interpret_addr2(s2);
+    
+    /* Announce all our names including aliases */
+    /* Give the ip address as the address of our first
+       broadcast subnet. */
+
+    for(i=0; my_netbios_names[i]; i++) 
+    {
+      char *name = my_netbios_names[i];
+
+      DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
+                 name, inet_ntoa(addr) ));
+
+      send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
+                    name,                      /* From nbt name. */
+                    wgroup, 0x1e,              /* To nbt name. */
+                    addr,                      /* To ip. */
+                    REMOTE_ANNOUNCE_INTERVAL,  /* Time until next announce. */
+                    name,                      /* Name to announce. */
+                    stype,                     /* Type field. */
+                    comment);
+    }
+  }
+}
+
+/****************************************************************************
+  Implement the 'remote browse sync' feature Andrew added.
+  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;
+  struct work_record *work;
+  pstring outbuf;
+  char *p;
+  if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
+    return;
+   
+  last_time = t;
+
+  s = lp_remote_browse_sync();
+  if (!*s)
+    return;
+
+  /*
+   * We only do this if we are the local master browser
+   * for our workgroup on the firsst subnet.
+   */
+
+  if((work = find_workgroup_on_subnet(FIRST_SUBNET, myworkgroup)) == NULL)
+  {   
+    DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
+           myworkgroup, FIRST_SUBNET->subnet_name ));
+    return;
+  }   
+         
+  if(!AM_LOCAL_MASTER_BROWSER(work))
+  {
+    DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
+for workgroup %s on subnet %s.\n", myworkgroup, FIRST_SUBNET->subnet_name ));
+    return;
+  } 
+
+  bzero(outbuf,sizeof(outbuf));
+  p = outbuf;
+  CVAL(p,0) = ANN_MasterAnnouncement;
+  p++;
+
+  StrnCpy(p,myname,15);
+  strupper(p);
+  p = skip_string(p,1);
+
+  for (ptr=s; next_token(&ptr,s2,NULL); ) 
+  {
+    /* The entries are of the form a.b.c.d */
+    addr = *interpret_addr2(s2);
+
+    DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
+                 myname, inet_ntoa(addr) ));
+
+    send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+          myname, 0x0, "*", 0x0, addr, FIRST_SUBNET->myip);
+  }
+}
diff --git a/source/nmbd/nmbd_serverlistdb.c b/source/nmbd/nmbd_serverlistdb.c
new file mode 100644 (file)
index 0000000..1281fe2
--- /dev/null
@@ -0,0 +1,454 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+
+int updatecount = 0;
+
+/*******************************************************************
+  Remove all the servers in a work group.
+  ******************************************************************/
+
+void remove_all_servers(struct work_record *work)
+{
+  struct server_record *servrec;
+  struct server_record *nexts;
+
+  for (servrec = work->serverlist; servrec; servrec = nexts)
+  {
+    DEBUG(7,("remove_all_servers: Removing server %s\n",servrec->serv.name));
+    nexts = servrec->next;
+
+    if (servrec->prev)
+      servrec->prev->next = servrec->next;
+    if (servrec->next)
+      servrec->next->prev = servrec->prev;
+
+    if (work->serverlist == servrec)
+      work->serverlist = servrec->next;
+
+    free((char *)servrec);
+
+  }
+
+  work->subnet->work_changed = True;
+}
+
+/***************************************************************************
+  Add a server into the a workgroup serverlist.
+  **************************************************************************/
+
+static void add_server_to_workgroup(struct work_record *work,
+                             struct server_record *servrec)
+{
+  struct server_record *servrec2;
+
+  if (!work->serverlist)
+  {
+    work->serverlist = servrec;
+    servrec->prev = NULL;
+    servrec->next = NULL;
+    return;
+  }
+
+  for (servrec2 = work->serverlist; servrec2->next; servrec2 = servrec2->next)
+    ;
+
+  servrec2->next = servrec;
+  servrec->next = NULL;
+  servrec->prev = servrec2;
+  work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+  Find a server in a server list.
+  **************************************************************************/
+
+struct server_record *find_server_in_workgroup(struct work_record *work, char *name)
+{
+  struct server_record *ret;
+  
+  for (ret = work->serverlist; ret; ret = ret->next)
+  {
+    if (strequal(ret->serv.name,name))
+      return ret;
+  }
+  return NULL;
+}
+
+
+/****************************************************************************
+  Remove a server entry from this workgroup.
+  ****************************************************************************/
+
+static void remove_server_from_workgroup(struct work_record *work, struct server_record *servrec)
+{
+  if (servrec->prev)
+    servrec->prev->next = servrec->next;
+  if (servrec->next)
+    servrec->next->prev = servrec->prev;
+
+  if (work->serverlist == servrec) 
+    work->serverlist = servrec->next; 
+
+  free((char *)servrec);
+  work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+  Create a server entry on this workgroup.
+  ****************************************************************************/
+
+struct server_record *create_server_on_workgroup(struct work_record *work,
+                                                 char *name,int servertype, 
+                                                 int ttl,char *comment)
+{
+  struct server_record *servrec;
+  
+  if (name[0] == '*')
+  {
+      DEBUG(7,("create_server_on_workgroup: not adding name starting with '*' (%s)\n",
+             name));
+      return (NULL);
+  }
+  
+  if((servrec = find_server_in_workgroup(work, name)) != NULL)
+  {
+    DEBUG(0,("create_server_on_workgroup: Server %s already exists on \
+workgroup %s. This is a bug.\n", name, work->work_group));
+    return NULL;
+  }
+  
+  if((servrec = (struct server_record *)malloc(sizeof(*servrec))) == NULL)
+  {
+    DEBUG(0,("create_server_entry_on_workgroup: malloc fail !\n"));
+    return NULL;
+  }
+
+  bzero((char *)servrec,sizeof(*servrec));
+  servrec->subnet = work->subnet;
+  StrnCpy(servrec->serv.name,name,sizeof(servrec->serv.name)-1);
+  StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
+  strupper(servrec->serv.name);
+  servrec->serv.type  = servertype;
+
+  update_server_ttl(servrec, ttl);
+  
+  add_server_to_workgroup(work, servrec);
+      
+  DEBUG(3,("create_server_on_workgroup: Created server entry %s of type %x (%s) on \
+workgroup %s.\n", name,servertype,comment, work->work_group));
+  work->subnet->work_changed = True;
+  return(servrec);
+}
+
+/*******************************************************************
+ Update the ttl field of a server record.
+*******************************************************************/
+
+void update_server_ttl(struct server_record *servrec, int ttl)
+{
+  if(ttl > lp_max_ttl())
+    ttl = lp_max_ttl();
+
+  if(is_myname(servrec->serv.name))
+    servrec->death_time = PERMANENT_TTL;
+  else
+    servrec->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
+
+  servrec->subnet->work_changed = True;
+}
+
+/*******************************************************************
+  Expire old servers in the serverlist. A time of -1 indicates 
+  everybody dies except those with a death_time of PERMANENT_TTL (which is 0).
+  This should only be called from expire_workgroups_and_servers().
+  ******************************************************************/
+
+void expire_servers(struct work_record *work, time_t t)
+{
+  struct server_record *servrec;
+  struct server_record *nexts;
+  
+  for (servrec = work->serverlist; servrec; servrec = nexts)
+  {
+    nexts = servrec->next;
+
+    if ((servrec->death_time != PERMANENT_TTL) && ((t == -1) || (servrec->death_time < t)))
+    {
+      DEBUG(3,("expire_old_servers: Removing timed out server %s\n",servrec->serv.name));
+      remove_server_from_workgroup(work, servrec);
+      work->subnet->work_changed = True;
+    }
+  }
+}
+
+/*******************************************************************
+ Decide if we should write out a server record for this server.
+ We return zero if we should not. Check if we've already written
+ out this server record from an earlier subnet.
+******************************************************************/
+
+static uint32 write_this_server_name( struct subnet_record *subrec,
+                                      struct work_record *work,
+                                      struct server_record *servrec)
+{
+  struct subnet_record *ssub;
+  struct work_record *iwork;
+  struct server_record *sserv;
+
+  /* Go through all the subnets we have already seen. */
+  for (ssub = FIRST_SUBNET; ssub != subrec; ssub = NEXT_SUBNET_INCLUDING_UNICAST(ssub)) 
+  {
+    for(iwork = ssub->workgrouplist; iwork; iwork = iwork->next)
+    {
+      if((sserv = find_server_in_workgroup( iwork, servrec->serv.name)) != NULL)
+      {
+        /*
+         * We have already written out this server record, don't
+         * do it again. This gives precedence to servers we have seen
+         * on the broadcast subnets over servers that may have been
+         * added via a sync on the unicast_subet.
+         *
+         * The correct way to do this is to have a serverlist file
+         * per subnet - this means changes to smbd as well. I may
+         * add this at a later date (JRA).
+         */
+
+        return 0;
+      }
+    }
+  }
+
+  return servrec->serv.type;
+}
+
+/*******************************************************************
+ Decide if we should write out a workgroup record for this workgroup.
+ We return zero if we should not. Don't write out myworkgroup (we've
+ already done it) and also don't write out a second workgroup record
+ on the unicast subnet that we've already written out on one of the
+ broadcast subnets.
+******************************************************************/
+
+static uint32 write_this_workgroup_name( struct subnet_record *subrec, 
+                                         struct work_record *work)
+{
+  struct subnet_record *ssub;
+
+  if(strequal(myworkgroup, work->work_group))
+    return 0;
+
+  /* This is a workgroup we have seen on a broadcast subnet. All
+     these have the same type. */
+
+  if(subrec != unicast_subnet)
+    return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
+
+  for(ssub = FIRST_SUBNET; ssub;  ssub = NEXT_SUBNET_EXCLUDING_UNICAST(ssub))
+  {
+    /* This is the unicast subnet so check if we've already written out
+       this subnet when we passed over the broadcast subnets. */
+
+    if(find_workgroup_on_subnet( ssub, work->work_group) != NULL)
+      return 0;
+  }
+
+  /* All workgroups on the unicast subnet (except our own, which we
+     have already written out) cannot be local. */
+
+  return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT);
+}
+
+/*******************************************************************
+  Write out the browse.dat file.
+  ******************************************************************/
+
+void write_browse_list(time_t t, BOOL force_write)
+{   
+  struct subnet_record *subrec;
+  struct work_record *work;
+  struct server_record *servrec;
+  pstring fname,fnamenew;
+  uint32 stype;
+  fstring tmp;
+  int i;
+  FILE *fp;
+  BOOL list_changed = force_write;
+  static time_t lasttime = 0;
+    
+  if (!lasttime)
+    lasttime = t;
+  if (t - lasttime < 5)
+    return;
+
+  for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    if(subrec->work_changed)
+    {
+      list_changed = True;
+      break;
+    }
+  }
+
+  if(!list_changed)
+    return;
+
+  lasttime = t;
+  updatecount++;
+    
+  dump_workgroups();
+  pstrcpy(fname,lp_lockdir());
+  trim_string(fname,NULL,"/");
+  strcat(fname,"/");
+  strcat(fname,SERVER_LIST);
+  pstrcpy(fnamenew,fname);
+  strcat(fnamenew,".");
+  fp = fopen(fnamenew,"w");
+  if (!fp)
+  {
+    DEBUG(0,("write_browse_list: Can't open file %s. Error was %s\n",
+              fnamenew,strerror(errno)));
+    return;
+  } 
+  
+  /*
+   * Write out a record for our workgroup. Use the record from the first
+   * subnet.
+   */
+
+  if((work = find_workgroup_on_subnet(FIRST_SUBNET, myworkgroup)) == NULL)
+  { 
+    DEBUG(0,("write_browse_list: Fatal error - cannot find my workgroup %s\n",
+             myworkgroup));
+    fclose(fp);
+    return;
+  }
+
+  sprintf(tmp, "\"%s\"", work->work_group);
+  fprintf(fp, "%-25s ", tmp);
+  fprintf(fp, "%08x ", SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
+  sprintf(tmp, "\"%s\" ", *work->local_master_browser_name ? work->local_master_browser_name : "Unknown");
+  fprintf(fp, "%-30s", tmp);
+  fprintf(fp, "\"%s\"\n", work->work_group);
+
+  /* 
+   * We need to do something special for our own names.
+   * This is due to the fact that we may be a local master browser on
+   * one of our broadcast subnets, and a domain master on the unicast
+   * subnet. We iterate over the subnets and only write out the name
+   * once.
+   */
+
+  for (i=0; my_netbios_names[i]; i++)
+  {
+    stype = 0;
+    for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+    {
+      if((work = find_workgroup_on_subnet( subrec, myworkgroup )) == NULL)
+        continue;
+      if((servrec = find_server_in_workgroup( work, my_netbios_names[i])) == NULL)
+        continue;
+
+      stype |= servrec->serv.type;
+    }
+
+    /* Output server details, plus what workgroup they're in. */
+    sprintf(tmp, "\"%s\"", my_netbios_names[i]);
+    fprintf(fp, "%-25s ", tmp);
+    fprintf(fp, "%08x ", stype);
+    sprintf(tmp, "\"%s\" ", lp_serverstring());
+    fprintf(fp, "%-30s", tmp);
+    fprintf(fp, "\"%s\"\n", myworkgroup);
+  }
+      
+  for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) 
+  { 
+    subrec->work_changed = False;
+
+    for (work = subrec->workgrouplist; work ; work = work->next)
+    {
+      /* Write out a workgroup record for a workgroup. */
+      uint32 wg_type = write_this_workgroup_name( subrec, work);
+
+      if(wg_type)
+      {
+        sprintf(tmp, "\"%s\"", work->work_group);
+        fprintf(fp, "%-25s ", tmp);
+
+        fprintf(fp, "%08x ", wg_type);
+        sprintf(tmp, "\"%s\" ", *work->local_master_browser_name ? 
+                                     work->local_master_browser_name : "Unknown" );
+        fprintf(fp, "%-30s", tmp);
+        fprintf(fp, "\"%s\"\n", work->work_group);
+      }
+
+      /* Now write out any server records a workgroup may have. */
+
+      for (servrec = work->serverlist; servrec ; servrec = servrec->next)
+      {
+        uint32 serv_type;
+
+        /* We have already written our names here. */
+        if(is_myname(servrec->serv.name))
+          continue; 
+
+        serv_type = write_this_server_name(subrec, work, servrec);
+
+        if(serv_type)
+        {
+          /* Output server details, plus what workgroup they're in. */
+          sprintf(tmp, "\"%s\"", servrec->serv.name);
+          fprintf(fp, "%-25s ", tmp);
+          fprintf(fp, "%08x ", serv_type);
+          sprintf(tmp, "\"%s\" ", servrec->serv.comment);
+          fprintf(fp, "%-30s", tmp);
+          fprintf(fp, "\"%s\"\n", work->work_group);
+        }
+      }
+    }
+  } 
+  
+  fclose(fp);
+  unlink(fname);
+  chmod(fnamenew,0644);
+  rename(fnamenew,fname);
+  DEBUG(3,("write_browse_list: Wrote browse list into file %s\n",fname));
+}
diff --git a/source/nmbd/nmbd_subnetdb.c b/source/nmbd/nmbd_subnetdb.c
new file mode 100644 (file)
index 0000000..93aecc2
--- /dev/null
@@ -0,0 +1,291 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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:
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+extern int global_nmb_port;
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+extern struct in_addr ipzero;
+
+/* This is the broadcast subnets database. */
+struct subnet_record *subnetlist = NULL;
+
+/* Extra subnets - keep these separate so enumeration code doesn't
+   run onto it by mistake. */
+
+struct subnet_record *unicast_subnet = NULL;
+struct subnet_record *remote_broadcast_subnet = NULL;
+struct subnet_record *wins_server_subnet = NULL;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
+
+/****************************************************************************
+  Add a subnet into the list.
+  **************************************************************************/
+
+static void add_subnet(struct subnet_record *subrec)
+{
+  struct subnet_record *subrec2;
+
+  if (!subnetlist)
+  {
+    subnetlist = subrec;
+    subrec->prev = NULL;
+    subrec->next = NULL;
+    return;
+  }
+
+  for (subrec2 = subnetlist; subrec2->next; subrec2 = subrec2->next)
+    ;
+
+  subrec2->next = subrec;
+  subrec->next = NULL;
+  subrec->prev = subrec2;
+}
+
+/****************************************************************************
+  Create a subnet entry.
+  ****************************************************************************/
+
+static struct subnet_record *make_subnet(char *name, enum subnet_type type,
+                                         struct in_addr myip, struct in_addr bcast_ip, 
+                                         struct in_addr mask_ip)
+{
+  struct subnet_record *subrec = NULL;
+  int nmb_sock, dgram_sock;
+
+  /* Check if we are creating a non broadcast subnet - if so don't create
+     sockets.
+   */
+
+  if(type != NORMAL_SUBNET)
+  {
+    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");
+
+  }
+
+  subrec = (struct subnet_record *)malloc(sizeof(*subrec));
+  
+  if (!subrec) 
+  {
+    DEBUG(0,("make_subnet: malloc fail !\n"));
+    close(nmb_sock);
+    close(dgram_sock);
+    return(NULL);
+  }
+  
+  bzero((char *)subrec,sizeof(*subrec));
+  
+  if((subrec->subnet_name = strdup(name)) == NULL)
+  {
+    DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
+    close(nmb_sock);
+    close(dgram_sock);
+    free((char *)subrec);
+    return(NULL);
+  }
+
+  DEBUG(2, ("making subnet name:%s ", name ));
+  DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
+  DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
+  subrec->namelist_changed = False;
+  subrec->work_changed = False;
+  subrec->bcast_ip = bcast_ip;
+  subrec->mask_ip  = mask_ip;
+  subrec->myip = myip;
+  subrec->type = type;
+  subrec->nmb_sock = nmb_sock;
+  subrec->dgram_sock = dgram_sock;
+  
+  return subrec;
+}
+
+/****************************************************************************
+  Create subnet entries.
+**************************************************************************/
+
+BOOL create_subnets()
+{    
+  int num_interfaces = iface_count();
+  int i;
+  struct in_addr unicast_ip;
+
+  if(num_interfaces == 0)
+  {
+    DEBUG(0,("create_subnets: No local interfaces !\n"));
+    return False;
+  }
+
+  /* 
+   * Create subnets from all the local interfaces and thread them onto
+   * the linked list. 
+   */
+
+  for (i = 0 ; i < num_interfaces; i++)
+  {
+    struct subnet_record *subrec;
+    struct interface *iface = get_interface(i);
+
+    if((subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
+                 iface->ip, iface->bcast,iface->nmask)) == NULL)
+      return False;
+    add_subnet(subrec);
+  }
+
+  /* 
+   * If we have been configured to use a WINS server, then try and
+   * get the ip address of it here. If we are the WINS server then
+   * set the unicast subnet address to be the first of our own real
+   * addresses.
+   */
+
+  if(*lp_wins_server())
+  {
+    struct in_addr real_wins_ip;
+    real_wins_ip = *interpret_addr2(lp_wins_server());
+
+    if (!zero_ip(real_wins_ip))
+    {
+      unicast_ip = real_wins_ip;
+    }
+    else
+    {
+      /* The smb.conf's wins server parameter MUST be a host_name
+         or an ip_address. */
+      DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
+      return False;
+    }
+  } 
+  else if(lp_we_are_a_wins_server())
+  {
+    /* Pick the first interface ip address as the WINS server ip. */
+    unicast_ip = *iface_n_ip(0);
+  }
+  else
+  {
+    /* We should not be using a WINS server at all. Set the
+      ip address of the subnet to be zero. */
+    unicast_ip = ipzero;
+  }
+
+  /*
+   * Create the unicast and remote broadcast subnets.
+   * Don't put these onto the linked list.
+   * The ip address of the unicast subnet is set to be
+   * the WINS server address, if it exists, or ipzero if not.
+   */
+
+  unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
+                                 unicast_ip, unicast_ip, unicast_ip);
+
+  remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
+                                         REMOTE_BROADCAST_SUBNET,
+                                         ipzero, ipzero, ipzero);
+
+  if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
+    return False;
+
+  /* 
+   * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
+   * the linked list.
+   */
+
+  if (lp_we_are_a_wins_server())
+  {
+    if((wins_server_subnet = make_subnet("WINS_SERVER_SUBNET",
+                                       WINS_SERVER_SUBNET, 
+                                       ipzero, ipzero, ipzero)) == NULL)
+      return False;
+  }
+
+  return True;
+}
+
+/*******************************************************************
+Function to tell us if we can use the unicast subnet.
+******************************************************************/
+
+BOOL we_are_a_wins_client()
+{
+  static int cache_we_are_a_wins_client = -1;
+
+  if(cache_we_are_a_wins_client == -1)
+    cache_we_are_a_wins_client = (ip_equal(ipzero, unicast_subnet->myip) ? 
+                                  False : True);
+
+  return cache_we_are_a_wins_client;
+}
+
+/*******************************************************************
+Access function used by NEXT_SUBNET_INCLUDING_UNICAST
+******************************************************************/
+
+struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
+{
+  if(subrec == unicast_subnet)
+    return NULL;
+  else if((subrec->next == NULL) && we_are_a_wins_client())
+    return unicast_subnet;
+  else
+    return subrec->next;
+}
diff --git a/source/nmbd/nmbd_winsproxy.c b/source/nmbd/nmbd_winsproxy.c
new file mode 100644 (file)
index 0000000..ed8653b
--- /dev/null
@@ -0,0 +1,195 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+Function called when the name lookup succeeded.
+****************************************************************************/
+
+static void wins_proxy_name_query_request_success( struct subnet_record *subrec,
+                        struct userdata_struct *userdata,
+                        struct nmb_name *nmbname, struct in_addr ip, struct res_rec *rrec)
+{
+  struct packet_struct *original_packet;
+  struct subnet_record *orig_broadcast_subnet;
+  uint16 nb_flags;
+  int num_ips;
+  int i;
+  int ttl;
+  struct in_addr *iplist;
+
+  /* Extract the original packet and the original broadcast subnet from
+     the userdata. */
+
+  memcpy( (char *)&orig_broadcast_subnet, userdata->data, sizeof(struct subnet_record *) );
+  memcpy( (char *)&original_packet, &userdata->data[sizeof(struct subnet_record *)],
+          sizeof(struct packet_struct *) );
+
+  nb_flags = get_nb_flags( rrec->rdata );
+
+  num_ips = rrec->rdlength / 6;
+  if(num_ips == 0)
+  {
+    DEBUG(0,("wins_proxy_name_query_request_success: Invalid number of IP records (0) \
+returned for name %s.\n", namestr(nmbname) ));
+    return;
+  }
+
+  if(num_ips == 1)
+    iplist = &ip;
+  else
+  {
+    if((iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) )) == NULL)
+    {
+      DEBUG(0,("wins_proxy_name_query_request_success: malloc fail !\n"));
+      return;
+    }
+
+    for(i = 0; i < num_ips; i++)
+      putip( (char *)&iplist[i], (char *)&rrec->rdata[ (i*6) + 2]);
+  }
+
+  /* Add the queried name to the original subnet as a WINS_PROXY_NAME. */
+
+  if(rrec == PERMANENT_TTL)
+    ttl = lp_max_ttl();
+
+  add_name_to_subnet( orig_broadcast_subnet, nmbname->name, nmbname->name_type,
+                         nb_flags, ttl, WINS_PROXY_NAME, num_ips, iplist);
+
+  if(iplist != &ip)
+    free((char *)iplist);
+
+  /* Finally reply to the original name query. */
+  reply_netbios_packet(original_packet,                /* Packet to reply to. */
+                       0,                              /* Result code. */
+                       NMB_QUERY,                      /* nmbd type code. */
+                       NMB_NAME_QUERY_OPCODE,          /* opcode. */
+                       ttl,                            /* ttl. */
+                       rrec->rdata,                    /* data to send. */
+                       rrec->rdlength);                /* data length. */
+}
+
+/****************************************************************************
+Function called when the name lookup failed.
+****************************************************************************/
+
+static void wins_proxy_name_query_request_fail(struct subnet_record *subrec,
+                                    struct response_record *rrec,
+                                    struct nmb_name *question_name, int fail_code)
+{
+  DEBUG(4,("wins_proxy_name_query_request_fail: WINS server returned error code %d for lookup \
+of name %s.\n", fail_code, namestr(question_name) ));
+}
+
+/****************************************************************************
+Function to make a deep copy of the userdata we will need when the WINS
+proxy query returns.
+****************************************************************************/
+
+static struct userdata_struct *wins_proxy_userdata_copy_fn(struct userdata_struct *userdata)
+{
+  struct packet_struct *p, *copy_of_p;
+  struct userdata_struct *new_userdata = 
+        (struct userdata_struct *)malloc( userdata->userdata_len );
+
+  if(new_userdata == NULL)
+    return NULL;
+
+  new_userdata->copy_fn = userdata->copy_fn;
+  new_userdata->free_fn = userdata->free_fn;
+  new_userdata->userdata_len = userdata->userdata_len;
+
+  /* Copy the subnet_record pointer. */
+  memcpy( new_userdata->data, userdata->data, sizeof(struct subnet_record *) );
+
+  /* Extract the pointer to the packet struct */
+  memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
+         sizeof(struct packet_struct *) );
+
+  /* Do a deep copy of the packet. */
+  if((copy_of_p = copy_packet(p)) == NULL)
+  {
+    free((char *)new_userdata);
+    return NULL;
+  }
+
+  /* Lock the copy. */
+  copy_of_p->locked = True;
+
+  memcpy( &new_userdata->data[sizeof(struct subnet_record *)], (char *)&copy_of_p,
+          sizeof(struct packet_struct *) );
+
+  return new_userdata;
+}
+
+/****************************************************************************
+Function to free the deep copy of the userdata we used when the WINS
+proxy query returned.
+****************************************************************************/
+
+static void wins_proxy_userdata_free_fn(struct userdata_struct *userdata)
+{
+  struct packet_struct *p;
+
+  /* Extract the pointer to the packet struct */
+  memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
+         sizeof(struct packet_struct *));
+
+  /* Unlock the packet. */
+  p->locked = False;
+
+  free_packet(p);
+  free((char *)userdata);
+}
+
+/****************************************************************************
+ Make a WINS query on behalf of a broadcast client name query request.
+****************************************************************************/
+
+void make_wins_proxy_name_query_request( struct subnet_record *subrec, 
+                                         struct packet_struct *incoming_packet,
+                                         struct nmb_name *question_name)
+{
+  char ud[sizeof(struct userdata_struct) + sizeof(struct subrec *) + 
+          sizeof(struct packet_struct *)];
+  struct userdata_struct *userdata = (struct userdata_struct *)ud;
+
+  bzero(ud, sizeof(ud));
+  userdata->copy_fn = wins_proxy_userdata_copy_fn;
+  userdata->free_fn = wins_proxy_userdata_free_fn;
+  userdata->userdata_len = sizeof(ud);
+  memcpy( userdata->data, (char *)&subrec, sizeof(struct subnet_record *));
+  memcpy( &userdata->data[sizeof(struct subnet_record *)], (char *)&incoming_packet,
+          sizeof(struct packet_struct *));
+
+  /* Now use the unicast subnet to query the name with the WINS server. */
+  query_name( unicast_subnet, question_name->name, question_name->name_type,
+              wins_proxy_name_query_request_success,
+              wins_proxy_name_query_request_fail,
+              userdata);
+}
diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c
new file mode 100644 (file)
index 0000000..ba7b62e
--- /dev/null
@@ -0,0 +1,1565 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+
+#define WINS_LIST "wins.dat"
+
+extern int DEBUGLEVEL;
+extern struct in_addr ipzero;
+
+/****************************************************************************
+Determine if this packet should be allocated to the WINS server.
+*****************************************************************************/
+
+BOOL packet_is_for_wins_server(struct packet_struct *packet)
+{
+  struct nmb_packet *nmb = &packet->packet.nmb;
+
+  /* Only unicast packets go to a WINS server. */
+  if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True))
+  {
+    DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
+    return False;
+  }
+
+  /* Check for node status requests. */
+  if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY)
+    return False;
+
+  switch(nmb->header.opcode)
+  { 
+    /*
+     * A WINS server issues WACKS, not receives them.
+     */
+    case NMB_WACK_OPCODE:
+      DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
+      return False;
+    /*
+     * A WINS server only processes registration and
+     * release requests, not responses.
+     */
+    case NMB_NAME_REG_OPCODE:
+    case NMB_NAME_MULTIHOMED_REG_OPCODE:
+    case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+    case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+      if(nmb->header.response)
+      {
+        DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
+        return False;
+      }
+      break;
+
+    case NMB_NAME_RELEASE_OPCODE:
+      if(nmb->header.response)
+      {
+        DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
+        return False;
+      }
+      break;
+
+    /*
+     * Only process unicast name queries with rd = 1.
+     */
+    case NMB_NAME_QUERY_OPCODE:
+      if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired)
+      {
+        DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
+        return False;
+      }
+      break;
+  }
+
+  return True;
+}
+
+/****************************************************************************
+Utility function to decide what ttl to give a register/refresh request.
+*****************************************************************************/
+
+static int get_ttl_from_packet(struct nmb_packet *nmb)
+{
+  int ttl = nmb->additional->ttl;
+
+  if(ttl < lp_min_wins_ttl() )
+    ttl = lp_min_wins_ttl();
+
+  if(ttl > lp_max_wins_ttl() )
+    ttl = lp_max_wins_ttl();
+
+  return ttl;
+}
+
+/****************************************************************************
+Load or create the WINS database.
+*****************************************************************************/
+
+BOOL initialise_wins(void)
+{
+  fstring fname;
+  time_t time_now = time(NULL);
+  FILE *fp;
+  pstring line;
+
+  if(!lp_we_are_a_wins_server())
+    return True;
+
+  add_samba_names_to_subnet(wins_server_subnet);
+
+#ifndef SYNC_DNS
+  /* Setup the async dns. */
+  start_async_dns();
+#endif
+
+  fstrcpy(fname,lp_lockdir());
+  trim_string(fname,NULL,"/");
+  strcat(fname,"/");
+  strcat(fname,WINS_LIST);
+
+  if((fp = fopen(fname,"r")) == NULL)
+  {
+    DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
+           fname, strerror(errno) ));
+    return True;
+  }
+
+  while (!feof(fp))
+  {
+    pstring name_str, ip_str, ttl_str, nb_flags_str;
+    unsigned int num_ips;
+    pstring name;
+    struct in_addr *ip_list;
+    int type = 0;
+    uint16 nb_flags;
+    time_t ttl;
+    enum name_source source;
+    char *ptr;
+    char *p;
+    BOOL got_token;
+    BOOL was_ip;
+    int i;
+
+    /* Read a line from the wins.dat file. Strips whitespace
+       from the beginning and end of the line.
+     */
+    if (!fgets_slash(line,sizeof(pstring),fp))
+      continue;
+      
+    if (*line == '#')
+      continue;
+
+    ptr = line;
+
+    /* 
+     * Now we handle multiple IP addresses per name we need
+     * to iterate over the line twice. The first time to
+     * determine how many IP addresses there are, the second
+     * time to actually parse them into the ip_list array.
+     */
+
+    if (!next_token(&ptr,name_str,NULL)) 
+    {
+      DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
+      continue;
+    }
+
+    if (!next_token(&ptr,ttl_str,NULL))
+    {
+      DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
+      continue;
+    }
+
+    /*
+     * Determine the number of IP addresses per line.
+     */
+    num_ips = 0;
+    do
+    {
+      got_token = next_token(&ptr,ip_str,NULL);
+      was_ip = False;
+
+      if(got_token && strchr(ip_str, '.'))
+      {
+        num_ips++;
+        was_ip = True;
+      }
+    } while( got_token && was_ip);
+
+    if(num_ips == 0)
+    {
+      DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
+      continue;
+    }
+
+    if(!got_token)
+    {
+      DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
+      continue;
+    }
+
+    /* Allocate the space for the ip_list. */
+    if((ip_list = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr))) == NULL)
+    {
+      DEBUG(0,("initialise_wins: Malloc fail !\n"));
+      return False;
+    }
+    /* Reset and re-parse the line. */
+    ptr = line;
+    next_token(&ptr,name_str,NULL); 
+    next_token(&ptr,ttl_str,NULL);
+    for(i = 0; i < num_ips; i++)
+    {
+      next_token(&ptr, ip_str, NULL);
+      ip_list[i] = *interpret_addr2(ip_str);
+      if (ip_equal(ip_list[i], ipzero)) 
+         source = SELF_NAME;
+    }
+    next_token(&ptr,nb_flags_str,NULL);
+
+    /* 
+     * 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,("initialise_wins: Ignoring SELF name %s\n", line));
+      free((char *)ip_list);
+      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);
+      
+    if((p = strchr(name,'#')) != NULL)
+    {
+      *p = 0;
+      sscanf(p+1,"%x",&type);
+    }
+      
+    /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
+    sscanf(nb_flags_str,"%hx",&nb_flags);
+    sscanf(ttl_str,"%ld",&ttl);
+
+    /* add all entries that have 60 seconds or more to live */
+    if ((ttl - 60) > time_now || ttl == PERMANENT_TTL)
+    {
+      struct name_record *namerec;
+
+      if(ttl != PERMANENT_TTL)
+        ttl -= time_now;
+    
+      DEBUG(4, ("initialise_wins: add name: %s#%02x ttl = %ld first IP %s flags = %2hx\n",
+           name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
+
+      namerec = add_name_to_subnet(wins_server_subnet, name, type, nb_flags, 
+                                   ttl, REGISTER_NAME, num_ips, ip_list);
+
+    }
+    else
+    {
+      DEBUG(4, ("initialise_wins: not adding name (ttl problem) %s#%02x ttl = %ld first IP %s flags = %2hx\n",
+             name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
+    }
+
+    free((char *)ip_list);
+  } 
+    
+  fclose(fp);
+  return True;
+}
+
+/****************************************************************************
+Send a WINS WACK (Wait ACKnowledgement) response.
+**************************************************************************/
+
+static void send_wins_wack_response(int ttl, struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  unsigned char rdata[2];
+
+  rdata[0] = rdata[1] = 0;
+
+  /* Taken from nmblib.c - we need to send back almost
+     identical bytes from the requesting packet header. */
+
+  rdata[0] = (nmb->header.opcode & 0xF) << 3;
+  if (nmb->header.nm_flags.authoritative &&
+      nmb->header.response) rdata[0] |= 0x4;
+  if (nmb->header.nm_flags.trunc) rdata[0] |= 0x2;
+  if (nmb->header.nm_flags.recursion_desired) rdata[0] |= 0x1;
+  if (nmb->header.nm_flags.recursion_available &&
+      nmb->header.response) rdata[1] |= 0x80;
+  if (nmb->header.nm_flags.bcast) rdata[1] |= 0x10;
+
+  reply_netbios_packet(p,                             /* Packet to reply to. */
+                       0,                             /* Result code. */
+                       NMB_WAIT_ACK,                  /* nmbd type code. */
+                       NMB_WACK_OPCODE,               /* opcode. */
+                       ttl,                           /* ttl. */
+                       (char *)rdata,                 /* data to send. */
+                       2);                            /* data length. */
+}
+
+/****************************************************************************
+Send a WINS name registration response.
+**************************************************************************/
+
+static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  char rdata[6];
+
+  memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+  reply_netbios_packet(p,                             /* Packet to reply to. */
+                       rcode,                         /* Result code. */
+                       WINS_REG,                      /* nmbd type code. */
+                       NMB_NAME_REG_OPCODE,           /* opcode. */
+                       ttl,                           /* ttl. */
+                       rdata,                         /* data to send. */
+                       6);                            /* data length. */
+}
+
+/***********************************************************************
+ Deal with a name refresh request to a WINS server.
+************************************************************************/
+
+void wins_process_name_refresh_request(struct subnet_record *subrec,
+                                            struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question = &nmb->question.question_name;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+  BOOL group = (nb_flags & NB_GROUP) ? True : False;
+  struct name_record *namerec = NULL;
+  int ttl = get_ttl_from_packet(nmb);
+  struct in_addr from_ip;
+
+  putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+  if(bcast)
+  {
+    /*
+     * We should only get unicast name refresh packets here.
+     * Anyone trying to refresh broadcast should not be going to a WINS
+     * server. Log an error here.
+     */
+
+    DEBUG(0,("wins_process_name_refresh_request: broadcast name refresh request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+          namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+    return;
+  }
+
+  DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s \
+IP %s\n", namestr(question), inet_ntoa(from_ip) ));
+
+  /* 
+   * See if the name already exists.
+   */
+
+  namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+  /*
+   * If this is a refresh request and the name doesn't exist then
+   * fail it.
+   */
+
+  if(namerec == NULL)
+  {
+    DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s and \
+the name does not exist.\n", namestr(question) ));
+    send_wins_name_registration_response(NAM_ERR, 0, p);
+    return;
+  }
+
+  /*
+   * Check that the group bits for the refreshing name and the
+   * name in our database match.
+   */
+
+  if((namerec != NULL) && ((group && !NAME_GROUP(namerec)) || (!group && NAME_GROUP(namerec))) )
+  {
+    DEBUG(3,("wins_process_name_refresh_request: Name %s group bit = %s \
+does not match group bit in WINS for this name.\n", namestr(question), group ? "True" : "False" ));
+    send_wins_name_registration_response(RFS_ERR, 0, p);
+    return;
+  }
+
+  /*
+   * For a unique name check that the person refreshing the name is one of the registered IP
+   * addresses. If not - fail the refresh. Do the same for group names with a type of 0x1c.
+   * Just return success for unique 0x1d refreshes. For normal group names update the ttl
+   * and return success.
+   */
+
+  if((!group || (group && (question->name_type == 0x1c))) && find_ip_in_name_record(namerec, from_ip ))
+  {
+    /*
+     * Update the ttl.
+     */
+    update_name_ttl(namerec, ttl);
+    send_wins_name_registration_response(0, ttl, p);
+    return;
+  }
+  else if(group)
+  {
+    /* 
+     * Normal groups are all registered with an IP address of 255.255.255.255 
+     * so we can't search for the IP address.
+     */
+    update_name_ttl(namerec, ttl);
+    send_wins_name_registration_response(0, ttl, p);
+    return;
+  }
+  else if(!group && (question->name_type == 0x1d))
+  {
+    /*
+     * Special name type - just pretend the refresh succeeded.
+     */
+    send_wins_name_registration_response(0, ttl, p);
+    return;
+  }
+  else
+  {
+    /*
+     * Fail the refresh.
+     */
+
+    DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s with IP %s and \
+is IP is not known to the name.\n", namestr(question), inet_ntoa(from_ip) ));
+    send_wins_name_registration_response(RFS_ERR, 0, p);
+    return;
+  }
+}
+
+/***********************************************************************
+ Deal with a name registration request query success to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer. The success here is actually a failure as it means
+ the client we queried wants to keep the name, so we must return
+ a registration failure to the original requestor.
+************************************************************************/
+
+static void wins_register_query_success(struct subnet_record *subrec,
+                                             struct userdata_struct *userdata,
+                                             struct nmb_name *question_name,
+                                             struct in_addr ip,
+                                             struct res_rec *answers)
+{
+  struct packet_struct *orig_reg_packet;
+
+  memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+  DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
+name %s. Rejecting registration request.\n", inet_ntoa(ip), namestr(question_name) ));
+
+  send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+
+  orig_reg_packet->locked = False;
+  free_packet(orig_reg_packet);
+}
+
+/***********************************************************************
+ Deal with a name registration request query failure to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer. The failure here is actually a success as it means
+ the client we queried didn't want to keep the name, so we can remove
+ the old name record and then successfully add the new name.
+************************************************************************/
+
+static void wins_register_query_fail(struct subnet_record *subrec,
+                                          struct response_record *rrec,
+                                          struct nmb_name *question_name,
+                                          int rcode)
+{
+  struct userdata_struct *userdata = rrec->userdata;
+  struct packet_struct *orig_reg_packet;
+  struct nmb_packet *nmb;
+  struct name_record *namerec = NULL;
+  uint16 nb_flags;
+  BOOL group;
+
+  memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+  nmb = &orig_reg_packet->packet.nmb;
+
+  nb_flags = get_nb_flags(nmb->additional->rdata);
+  group = (nb_flags & NB_GROUP) ? True : False;
+
+  /*
+   * We want to just add the name, as we now know the original owner
+   * didn't want it. But we can't just do that as an arbitary
+   * amount of time may have taken place between the name query
+   * request and this timeout/error response. So we check that
+   * the name still exists and is in the same state - if so
+   * we remove it and call wins_process_name_registration_request()
+   * as we know it will do the right thing now.
+   */
+
+  namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
+
+  if((namerec != NULL) && (namerec->source == REGISTER_NAME) && 
+            ip_equal(rrec->packet->ip, *namerec->ip) )
+  {
+    remove_name_from_namelist( subrec, namerec);
+    namerec = NULL;
+  }
+
+  if(namerec == NULL)
+    wins_process_name_registration_request(subrec, orig_reg_packet);
+  else
+    DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between \
+querying for name %s in order to replace it and this reply.\n", namestr(question_name) ));
+
+  orig_reg_packet->locked = False;
+  free_packet(orig_reg_packet);
+}
+
+/***********************************************************************
+ Deal with a name registration request to a WINS server.
+
+ Use the following pseudocode :
+
+ registering_group
+     |
+     |
+     +--------name exists
+     |                  |
+     |                  |
+     |                  +--- existing name is group
+     |                  |                      |
+     |                  |                      |
+     |                  |                      +--- add name (return).
+     |                  |
+     |                  |
+     |                  +--- exiting name is unique
+     |                                         |
+     |                                         |
+     |                                         +--- query existing owner (return).
+     |
+     |
+     +--------name doesn't exist
+                        |
+                        |
+                        +--- add name (return).
+
+ registering_unique
+     |
+     |
+     +--------name exists
+     |                  |
+     |                  |
+     |                  +--- existing name is group 
+     |                  |                      |
+     |                  |                      |
+     |                  |                      +--- fail add (return).
+     |                  | 
+     |                  |
+     |                  +--- exiting name is unique
+     |                                         |
+     |                                         |
+     |                                         +--- query existing owner (return).
+     |
+     |
+     +--------name doesn't exist
+                        |
+                        |
+                        +--- add name (return).
+
+ As can be seen from the above, the two cases may be collapsed onto each
+ other with the exception of the case where the name already exists and
+ is a group name. This case we handle with an if statement.
+************************************************************************/
+
+void wins_process_name_registration_request(struct subnet_record *subrec,
+                                            struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question = &nmb->question.question_name;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+  int ttl = get_ttl_from_packet(nmb);
+  struct name_record *namerec = NULL;
+  struct in_addr from_ip;
+  BOOL registering_group_name = (nb_flags & NB_GROUP) ? True : False;;
+
+  putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+  if(bcast)
+  {
+    /*
+     * We should only get unicast name registration packets here.
+     * Anyone trying to register broadcast should not be going to a WINS
+     * server. Log an error here.
+     */
+
+    DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+          namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+    return;
+  }
+
+  DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
+IP %s\n", registering_group_name ? "Group" : "Unique", namestr(question), inet_ntoa(from_ip) ));
+
+  /*
+   * See if the name already exists.
+   */
+
+  namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+  /*
+   * Deal with the case where the name found was a dns entry.
+   * Remove it as we now have a NetBIOS client registering the
+   * name.
+   */
+
+  if((namerec != NULL) && ((namerec->source == DNS_NAME) || (namerec->source == DNSFAIL_NAME)))
+  {
+    DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was a dns lookup \
+- removing it.\n", namestr(question) ));
+    remove_name_from_namelist( subrec, namerec);
+    namerec = NULL;
+  }
+
+  /*
+   * Reject if the name exists and is not a REGISTER_NAME.
+   * (ie. Don't allow any static names to be overwritten.
+   */
+
+  if((namerec != NULL) && (namerec->source != REGISTER_NAME))
+  {
+    DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS with source type %d.\n", namestr(question), namerec->source ));
+    send_wins_name_registration_response(RFS_ERR, 0, p);
+    return;
+  }
+
+  /*
+   * Special policy decisions based on MS documentation.
+   * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
+   * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
+   */
+
+  /*
+   * A group name is always added as the local broadcast address, except
+   * for group names ending in 0x1c.
+   * Group names with type 0x1c are registered with individual IP addresses.
+   */
+
+  if(registering_group_name && (question->name_type != 0x1c))
+    from_ip = *interpret_addr2("255.255.255.255");
+
+  /*
+   * Ignore all attempts to register a unique 0x1d name, although return success.
+   */
+
+  if(!registering_group_name && (question->name_type == 0x1d))
+  {
+    DEBUG(3,("wins_process_name_registration_request: Ignoring request \
+to register name %s from IP %s.", namestr(question), inet_ntoa(p->ip) ));
+    send_wins_name_registration_response(0, ttl, p);
+    return;
+  }
+
+  /*
+   * Next two cases are the 'if statement' mentioned above.
+   */
+
+  if((namerec != NULL) && NAME_GROUP(namerec))
+  {
+    if(registering_group_name)
+    {
+      /*
+       * If we are adding a group name, the name exists and is also a group entry just add this
+       * IP address to it and update the ttl.
+       */
+
+      DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
+            inet_ntoa(from_ip), namestr(question) ));
+      /* 
+       * Check the ip address is not already in the group.
+       */
+      if(!find_ip_in_name_record(namerec, from_ip))
+        add_ip_to_name_record(namerec, from_ip);
+      update_name_ttl(namerec, ttl);
+      send_wins_name_registration_response(0, ttl, p);
+      return;
+    }
+    else
+    {
+      /*
+       * If we are adding a unique name, the name exists in the WINS db 
+       * and is a group name then reject the registration.
+       */
+
+      DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS as a GROUP name.\n", namestr(question) ));
+      send_wins_name_registration_response(RFS_ERR, 0, p);
+      return;
+    } 
+  }
+
+  /*
+   * From here on down we know that if the name exists in the WINS db it is
+   * a unique name, not a group name.
+   */
+
+  /* 
+   * If the name exists and is one of our names then check the
+   * registering IP address. If it's not one of ours then automatically
+   * reject without doing the query - we know we will reject it.
+   */
+
+  if((namerec != NULL) && (is_myname(namerec->name.name)) )
+  {
+    if(!ismyip(from_ip))
+    {
+      DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+is one of our (WINS server) names. Denying registration.\n", namestr(question) ));
+      send_wins_name_registration_response(RFS_ERR, 0, p);
+      return;
+    }
+    else
+    {
+      /*
+       * It's one of our names and one of our IP's - update the ttl.
+       */
+      update_name_ttl(namerec, ttl);
+      send_wins_name_registration_response(0, ttl, p);
+      return;
+    }
+  }
+
+  /*
+   * If the name exists and it is a unique registration and the registering IP 
+   * is the same as the the (single) already registered IP then just update the ttl.
+   */
+
+  if(!registering_group_name && (namerec != NULL) && (namerec->num_ips == 1) && 
+           ip_equal(namerec->ip[0], from_ip))
+  {
+    update_name_ttl(namerec, ttl);
+    send_wins_name_registration_response(0, ttl, p);
+    return;
+  }
+
+  /*
+   * Finally if the name exists do a query to the registering machine 
+   * to see if they still claim to have the name.
+   */
+
+  if(namerec != NULL)
+  {
+    char ud[sizeof(struct userdata_struct) + sizeof(struct packet_struct *)];
+    struct userdata_struct *userdata = (struct userdata_struct *)&ud;
+
+    /*
+     * First send a WACK to the registering machine.
+     */
+
+    send_wins_wack_response(60, p);
+
+    /*
+     * When the reply comes back we need the original packet.
+     * Lock this so it won't be freed and then put it into
+     * the userdata structure.
+     */
+
+    p->locked = True;
+
+    userdata = (struct userdata_struct *)ud;
+
+    userdata->copy_fn = NULL;
+    userdata->free_fn = NULL;
+    userdata->userdata_len = sizeof(struct packet_struct *);
+    memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
+
+    /*
+     * As query_name uses the subnet broadcast address as the destination
+     * of the packet we temporarily change the subnet broadcast address to
+     * be the first IP address of the name owner and send the packet. This
+     * is a *horrible* hack but the alternative is to add the destination
+     * address parameter to all query_name() calls. I hate this code :-).
+     */
+
+    subrec->bcast_ip = *namerec->ip;
+
+    query_name( subrec, question->name, question->name_type, 
+                wins_register_query_success,
+                wins_register_query_fail,
+                userdata);
+    subrec->bcast_ip = ipzero;
+    return;
+  }
+
+  /*
+   * Name did not exist - add it.
+   */
+
+  add_name_to_subnet(subrec, question->name, question->name_type,
+                     nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
+
+  send_wins_name_registration_response(0, ttl, p);
+}
+
+/***********************************************************************
+ Deal with a mutihomed name query success to the machine that
+ requested the multihomed name registration.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer.
+************************************************************************/
+
+static void wins_multihomed_register_query_success(struct subnet_record *subrec,
+                                             struct userdata_struct *userdata,
+                                             struct nmb_name *question_name,
+                                             struct in_addr ip,
+                                             struct res_rec *answers)
+{
+  struct packet_struct *orig_reg_packet;
+  struct nmb_packet *nmb;
+  struct name_record *namerec = NULL;
+  struct in_addr from_ip;
+  int ttl;
+
+  memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+  nmb = &orig_reg_packet->packet.nmb;
+
+  putip((char *)&from_ip,&nmb->additional->rdata[2]);
+  ttl = get_ttl_from_packet(nmb);
+
+  /*
+   * We want to just add the new IP, as we now know the requesting
+   * machine claims to own it. But we can't just do that as an arbitary
+   * amount of time may have taken place between the name query
+   * request and this response. So we check that
+   * the name still exists and is in the same state - if so
+   * we just add the extra IP and update the ttl.
+   */
+
+  namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
+
+  if( (namerec == NULL) || (namerec->source != REGISTER_NAME) )
+  {
+    DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
+a subsequent IP addess.\n", namestr(question_name) ));
+    send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+    return;
+  }
+
+  if(!find_ip_in_name_record(namerec, from_ip))
+    add_ip_to_name_record(namerec, from_ip);
+  update_name_ttl(namerec, ttl);
+  send_wins_name_registration_response(0, ttl, orig_reg_packet);
+
+}
+
+/***********************************************************************
+ Deal with a name registration request query failure to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer.
+************************************************************************/
+
+static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
+                                          struct response_record *rrec,
+                                          struct nmb_name *question_name,
+                                          int rcode)
+{
+  struct userdata_struct *userdata = rrec->userdata;
+  struct packet_struct *orig_reg_packet;
+
+  memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+  DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
+query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), namestr(question_name) ));
+  send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+  return;
+}
+
+/***********************************************************************
+ Deal with a multihomed name registration request to a WINS server.
+ These cannot be group name registrations.
+***********************************************************************/
+
+void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
+                                                        struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question = &nmb->question.question_name;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+  int ttl = get_ttl_from_packet(nmb);
+  struct name_record *namerec = NULL;
+  struct in_addr from_ip;
+  BOOL group = (nb_flags & NB_GROUP) ? True : False;;
+
+  putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+  if(bcast)
+  {
+    /*
+     * We should only get unicast name registration packets here.
+     * Anyone trying to register broadcast should not be going to a WINS
+     * server. Log an error here.
+     */
+
+    DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+          namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+    return;
+  }
+
+  /*
+   * Only unique names should be registered multihomed.
+   */
+
+  if(group)
+  {
+    DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
+received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
+          namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+    return;
+  }
+
+  DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
+IP %s\n", namestr(question), inet_ntoa(from_ip) ));
+
+  /*
+   * Deal with policy regarding 0x1d names.
+   */
+
+  if(question->name_type == 0x1d)
+  {
+    DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
+to register name %s from IP %s.", namestr(question), inet_ntoa(p->ip) ));
+    send_wins_name_registration_response(0, ttl, p);  
+    return;
+  }
+
+  /*
+   * See if the name already exists.
+   */
+
+  namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+  /*
+   * Deal with the case where the name found was a dns entry.
+   * Remove it as we now have a NetBIOS client registering the
+   * name.
+   */
+
+  if((namerec != NULL) && ((namerec->source == DNS_NAME) || (namerec->source == DNSFAIL_NAME)))
+  {
+    DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
+- removing it.\n", namestr(question) ));
+    remove_name_from_namelist( subrec, namerec);
+    namerec = NULL;
+  }
+
+  /*
+   * Reject if the name exists and is not a REGISTER_NAME.
+   * (ie. Don't allow any static names to be overwritten.
+   */
+
+  if((namerec != NULL) && (namerec->source != REGISTER_NAME))
+  {
+    DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS with source type %d.\n", namestr(question), namerec->source ));
+    send_wins_name_registration_response(RFS_ERR, 0, p);
+    return;
+  }
+
+  /*
+   * Reject if the name exists and is a GROUP name.
+   */
+
+  if((namerec != NULL) && NAME_GROUP(namerec))
+  {
+    DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS as a GROUP name.\n", namestr(question) ));
+    send_wins_name_registration_response(RFS_ERR, 0, p);
+    return;
+  } 
+
+  /*
+   * From here on down we know that if the name exists in the WINS db it is
+   * a unique name, not a group name.
+   */
+
+  /*
+   * If the name exists and is one of our names then check the
+   * registering IP address. If it's not one of ours then automatically
+   * reject without doing the query - we know we will reject it.
+   */
+
+  if((namerec != NULL) && (is_myname(namerec->name.name)) )
+  {
+    if(!ismyip(from_ip))
+    {
+      DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
+is one of our (WINS server) names. Denying registration.\n", namestr(question) ));
+      send_wins_name_registration_response(RFS_ERR, 0, p);
+      return;
+    }
+    else
+    {
+      /*
+       * It's one of our names and one of our IP's. Ensure the IP is in the record and
+       *  update the ttl.
+       */
+      if(!find_ip_in_name_record(namerec, from_ip))
+        add_ip_to_name_record(namerec, from_ip);
+      update_name_ttl(namerec, ttl);
+      send_wins_name_registration_response(0, ttl, p);
+      return;
+    }
+  }
+
+  /*
+   * If the name exists do a query to the owner
+   * to see if they still want the name.
+   */
+
+  if(namerec != NULL)
+  {
+    char ud[sizeof(struct userdata_struct) + sizeof(struct packet_struct *)];
+    struct userdata_struct *userdata = (struct userdata_struct *)&ud;
+
+    /*
+     * First send a WACK to the registering machine.
+     */
+
+    send_wins_wack_response(60, p);
+
+    /*
+     * When the reply comes back we need the original packet.
+     * Lock this so it won't be freed and then put it into
+     * the userdata structure.
+     */
+
+    p->locked = True;
+
+    userdata = (struct userdata_struct *)ud;
+
+    userdata->copy_fn = NULL;
+    userdata->free_fn = NULL;
+    userdata->userdata_len = sizeof(struct packet_struct *);
+    memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
+
+    /*
+     * As query_name uses the subnet broadcast address as the destination
+     * of the packet we temporarily change the subnet broadcast address to
+     * be the IP address of the requesting machine and send the packet. This
+     * is a *horrible* hack but the alternative is to add the destination
+     * address parameter to all query_name() calls. I hate this code :-).
+     */
+
+    subrec->bcast_ip = p->ip;
+    query_name( subrec, question->name, question->name_type,
+                wins_multihomed_register_query_success, 
+                wins_multihomed_register_query_fail,
+                userdata);
+    subrec->bcast_ip = ipzero;
+    return;
+  }
+
+  /*
+   * Name did not exist - add it.
+   */
+
+  add_name_to_subnet(subrec, question->name, question->name_type,
+                     nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
+
+  send_wins_name_registration_response(0, ttl, p);
+}
+
+/***********************************************************************
+ Deal with the special name query for *<1b>.
+***********************************************************************/
+   
+static void process_wins_dmb_query_request(struct subnet_record *subrec,  
+                                           struct packet_struct *p)
+{  
+  struct name_record *namerec = NULL;
+  char *prdata;
+  int num_ips;
+
+  /*
+   * Go through all the names in the WINS db looking for those
+   * ending in <1b>. Use this to calculate the number of IP
+   * addresses we need to return.
+   */
+
+  num_ips = 0;
+  for(namerec = subrec->namelist; namerec; namerec = namerec->next)
+  {
+    if(namerec->name.name_type == 0x1b)
+      num_ips += namerec->num_ips;
+  }
+
+  if(num_ips == 0)
+  {
+    /*
+     * There are no 0x1b names registered. Return name query fail.
+     */
+    send_wins_name_query_response(NAM_ERR, p, NULL);
+    return;
+  }
+
+  if((prdata = (char *)malloc( num_ips * 6 )) == NULL)
+  {
+    DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
+    return;
+  }
+
+  /*
+   * Go through all the names again in the WINS db looking for those
+   * ending in <1b>. Add their IP addresses into the list we will
+   * return.
+   */ 
+
+  num_ips = 0;
+  for(namerec = subrec->namelist; namerec; namerec = namerec->next)
+  {
+    if(namerec->name.name_type == 0x1b)
+    {
+      int i;
+      for(i = 0; i < namerec->num_ips; i++)
+      {
+        set_nb_flags(&prdata[num_ips * 6],namerec->nb_flags);
+        putip((char *)&prdata[(num_ips * 6) + 2], &namerec->ip[i]);
+        num_ips++;
+      }
+    }
+  }
+
+  /*
+   * Send back the reply containing the IP list.
+   */
+
+  reply_netbios_packet(p,                             /* Packet to reply to. */
+                       0,                             /* Result code. */
+                       WINS_QUERY,                    /* nmbd type code. */
+                       NMB_NAME_QUERY_OPCODE,         /* opcode. */
+                       lp_min_wins_ttl(),             /* ttl. */
+                       prdata,                        /* data to send. */
+                       num_ips*6);                    /* data length. */
+
+  free(prdata);
+}
+
+/****************************************************************************
+Send a WINS name query response.
+**************************************************************************/
+
+void send_wins_name_query_response(int rcode, struct packet_struct *p, 
+                                          struct name_record *namerec)
+{
+  char rdata[6];
+  char *prdata = rdata;
+  int reply_data_len = 0;
+  int ttl = 0;
+  int i = 0;
+  int j;
+
+  bzero(rdata,6);
+
+  if(rcode == 0)
+  {
+    int same_net_index;
+
+    ttl = (namerec->death_time != PERMANENT_TTL) ?
+             namerec->death_time - p->timestamp : lp_max_wins_ttl();
+
+    /* Copy all known ip addresses into the return data. */
+    /* Optimise for the common case of one IP address so
+       we don't need a malloc. */
+
+    if(namerec->num_ips == 1 )
+      prdata = rdata;
+    else
+    {
+      if((prdata = (char *)malloc( namerec->num_ips * 6 )) == NULL)
+      {
+        DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
+        return;
+      }
+
+      /* 
+       * Look over the known IP addresses and see if one of them
+       * is on the same (local) net as the requesting IP address. If so then
+       * put that IP address into the packet as the first IP.
+       * We can only do this for local nets as they're the only
+       * ones we know the netmask for.
+       */
+
+      same_net_index = -1;
+      i = 0;
+
+      if(is_local_net(p->ip))
+      {
+        struct in_addr *n_mask = iface_nmask(p->ip);
+
+        for( j = 0; j < namerec->num_ips; j++)
+        {
+          if(same_net( namerec->ip[j], p->ip, *n_mask))
+          {
+            set_nb_flags(&prdata[0],namerec->nb_flags);
+            putip((char *)&prdata[2], &namerec->ip[j]);
+            same_net_index = j;
+            i = 1;
+          }
+        }
+      }
+    }
+
+    for(; i < namerec->num_ips; i++)
+    {
+      if(i == same_net_index)
+        continue;
+      set_nb_flags(&prdata[i*6],namerec->nb_flags);
+      putip((char *)&prdata[2+(i*6)], &namerec->ip[i]);
+    }
+    reply_data_len = namerec->num_ips * 6;
+
+  }
+
+  reply_netbios_packet(p,                             /* Packet to reply to. */
+                       rcode,                         /* Result code. */
+                       WINS_QUERY,                    /* nmbd type code. */
+                       NMB_NAME_QUERY_OPCODE,         /* opcode. */
+                       ttl,                           /* ttl. */
+                       prdata,                        /* data to send. */
+                       reply_data_len);               /* data length. */
+
+  if((prdata != rdata) && (prdata != NULL))
+    free(prdata);
+}
+
+/***********************************************************************
+ Deal with a name query.
+***********************************************************************/
+
+void wins_process_name_query_request(struct subnet_record *subrec, 
+                                     struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question = &nmb->question.question_name;
+  struct name_record *namerec = NULL;
+
+  DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n", 
+            namestr(question), inet_ntoa(p->ip) ));
+
+  /*
+   * Special name code. If the queried name is *<1b> then search
+   * the entire WINS database and return a list of all the IP addresses
+   * registered to any <1b> name. This is to allow domain master browsers
+   * to discover other domains that may not have a presence on their subnet.
+   */
+
+  if(strequal( question->name, "*") && (question->name_type == 0x1b))
+  {
+    process_wins_dmb_query_request( subrec, p);
+    return;
+  }
+
+  namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+  if(namerec != NULL)
+  {
+    /* 
+     * If it's a DNSFAIL_NAME then reply name not found.
+     */
+
+    if(namerec->source == DNSFAIL_NAME)
+    {
+      DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
+             namestr(question) ));
+      send_wins_name_query_response(NAM_ERR, p, namerec);
+      return;
+    }
+
+    /*
+     * If the name has expired then reply name not found.
+     */
+
+    if((namerec->death_time != PERMANENT_TTL) && (namerec->death_time < p->timestamp))
+    {
+      DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
+                namestr(question) ));
+      send_wins_name_query_response(NAM_ERR, p, namerec);
+      return;
+    }
+
+    DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
+           namestr(question), inet_ntoa(namerec->ip[0]) ));
+
+    send_wins_name_query_response(0, p, namerec);
+    return;
+  }
+
+  /* 
+   * Name not found in WINS - try a dns query if it's a 0x20 name.
+   */
+
+  if(lp_dns_proxy() && (question->name_type == 0x20))
+  {
+
+    DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
+              namestr(question) ));
+
+    queue_dns_query(p, question, &namerec);
+    return;
+  }
+
+  /*
+   * Name not found - return error.
+   */
+
+  send_wins_name_query_response(NAM_ERR, p, NULL);
+}
+
+/****************************************************************************
+Send a WINS name release response.
+**************************************************************************/
+
+static void send_wins_name_release_response(int rcode, struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  char rdata[6];
+
+  memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+  reply_netbios_packet(p,                            /* Packet to reply to. */
+                       rcode,                        /* Result code. */
+                       NMB_REL,                      /* nmbd type code. */
+                       NMB_NAME_RELEASE_OPCODE,      /* opcode. */
+                       0,                            /* ttl. */
+                       rdata,                        /* data to send. */
+                       6);                           /* data length. */
+}
+
+/***********************************************************************
+ Deal with a name release.
+***********************************************************************/
+
+void wins_process_name_release_request(struct subnet_record *subrec,
+                                       struct packet_struct *p)
+{
+  struct nmb_packet *nmb = &p->packet.nmb;
+  struct nmb_name *question = &nmb->question.question_name;
+  BOOL bcast = nmb->header.nm_flags.bcast;
+  uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+  struct name_record *namerec = NULL;
+  struct in_addr from_ip;
+  BOOL releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
+
+  putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+  if(bcast)
+  {
+    /*
+     * We should only get unicast name registration packets here.
+     * Anyone trying to register broadcast should not be going to a WINS
+     * server. Log an error here.
+     */
+
+    DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+          namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+    return;
+  }
+  
+  DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
+IP %s\n", releasing_group_name ? "Group" : "Unique", namestr(question), inet_ntoa(from_ip) ));
+    
+  /*
+   * Deal with policy regarding 0x1d names.
+   */
+
+  if(!releasing_group_name && (question->name_type == 0x1d))
+  {
+    DEBUG(3,("wins_process_name_release_request: Ignoring request \
+to release name %s from IP %s.", namestr(question), inet_ntoa(p->ip) ));
+    send_wins_name_release_response(0, p);
+    return;
+  }
+
+  /*
+   * See if the name already exists.
+   */
+    
+  namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+  if((namerec == NULL) || ((namerec != NULL) && (namerec->source != REGISTER_NAME)) )
+  {
+    send_wins_name_release_response(NAM_ERR, p);
+    return;
+  }
+
+  /* 
+   * Check that the sending machine has permission to release this name.
+   * If it's a group name not ending in 0x1c then just say yes and let
+   * the group time out.
+   */
+
+  if(releasing_group_name && (question->name_type != 0x1c))
+  {
+    send_wins_name_release_response(0, p);
+    return;
+  }
+
+  /* 
+   * Check that the releasing node is on the list of IP addresses
+   * for this name. Disallow the release if not.
+   */
+
+  if(!find_ip_in_name_record(namerec, from_ip))
+  {
+    DEBUG(3,("wins_process_name_release_request: Refusing request to \
+release name %s as IP %s is not one of the known IP's for this name.\n",
+           namestr(question), inet_ntoa(from_ip) ));
+    send_wins_name_release_response(NAM_ERR, p);
+    return;
+  }    
+
+  /* 
+   * Release the name and then remove the IP from the known list.
+   */
+
+  send_wins_name_release_response(0, p);
+  remove_ip_from_name_record(namerec, from_ip);
+
+  /* 
+   * Remove the name entirely if no IP addresses left.
+   */
+  if (namerec->num_ips == 0)
+    remove_name_from_namelist(subrec, namerec);
+
+}
+
+/*******************************************************************
+ WINS time dependent processing.
+******************************************************************/
+
+void initiate_wins_processing(time_t t)
+{
+  static time_t lasttime = 0;
+
+  if (!lasttime)
+    lasttime = t;
+  if (t - lasttime < 5)
+    return;
+
+  if(!lp_we_are_a_wins_server())
+    return;
+
+  expire_names_on_subnet(wins_server_subnet, t);
+
+  if(wins_server_subnet->namelist_changed)
+    wins_write_database();
+
+  wins_server_subnet->namelist_changed = False;
+}
+
+/*******************************************************************
+ Write out the current WINS database.
+******************************************************************/
+
+void wins_write_database(void)
+{
+  struct name_record *namerec;
+  fstring fname, fnamenew;
+   
+  FILE *fp;
+   
+  if(!lp_we_are_a_wins_server())
+    return;
+
+  fstrcpy(fname,lp_lockdir());
+  trim_string(fname,NULL,"/");
+  strcat(fname,"/");
+  strcat(fname,WINS_LIST);
+  fstrcpy(fnamenew,fname);
+  strcat(fnamenew,".");
+
+  if((fp = fopen(fnamenew,"w")) == NULL)
+  {
+    DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
+    return;
+  }
+
+  DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
+  for (namerec = wins_server_subnet->namelist; namerec; namerec = namerec->next)
+  {
+    int i;
+    struct tm *tm;
+
+    DEBUG(4,("%-19s ", namestr(&namerec->name) ));
+
+    if(namerec->death_time != PERMANENT_TTL)
+    {
+      tm = LocalTime(&namerec->death_time);
+      DEBUG(4,("TTL = %s", asctime(tm) ));
+    }
+    else
+      DEBUG(4,("TTL = PERMANENT\t"));
+
+    for (i = 0; i < namerec->num_ips; i++)
+      DEBUG(4,("%15s ", inet_ntoa(namerec->ip[i]) ));
+    DEBUG(4,("%2x\n", namerec->nb_flags ));
+
+    if (namerec->source == REGISTER_NAME)
+    {
+      fprintf(fp, "%s#%02x %ld ",
+               namerec->name.name,namerec->name.name_type, /* Ignore scope. */
+               namerec->death_time);
+
+      for (i = 0; i < namerec->num_ips; i++)
+        fprintf(fp, "%s ", inet_ntoa(namerec->ip[i]));
+      fprintf(fp, "%2xR\n", namerec->nb_flags);
+    }
+  }
+  
+  fclose(fp);
+  unlink(fname);
+  chmod(fnamenew,0644);
+  rename(fnamenew,fname);
+}
diff --git a/source/nmbd/nmbd_workgroupdb.c b/source/nmbd/nmbd_workgroupdb.c
new file mode 100644 (file)
index 0000000..828e29a
--- /dev/null
@@ -0,0 +1,356 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
+   Copyright (C) Jeremy Allison 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.
+   
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+extern uint16 samba_nb_type;
+extern struct in_addr ipzero;
+
+int workgroup_count = 0; /* unique index key: one for each workgroup */
+
+/****************************************************************************
+  Add a workgroup into the list.
+  **************************************************************************/
+
+static void add_workgroup(struct subnet_record *subrec, struct work_record *work)
+{
+  struct work_record *w2;
+
+  work->subnet = subrec;
+
+  if (!subrec->workgrouplist)
+  {
+    subrec->workgrouplist = work;
+    work->prev = NULL;
+    work->next = NULL;
+    return;
+  }
+  
+  for (w2 = subrec->workgrouplist; w2->next; w2 = w2->next)
+    ;
+  
+  w2->next = work;
+  work->next = NULL;
+  work->prev = w2;
+
+  subrec->work_changed = True;
+}
+
+/****************************************************************************
+  Create an empty workgroup.
+  **************************************************************************/
+
+static struct work_record *create_workgroup(char *name, int ttl)
+{
+  struct work_record *work;
+  struct subnet_record *subrec;
+  int t = -1;
+  
+  if((work = (struct work_record *)malloc(sizeof(*work))) == NULL)
+  {
+    DEBUG(0,("create_workgroup: malloc fail !\n"));
+    return NULL;
+  }
+  bzero((char *)work, sizeof(*work));
+  StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
+  work->serverlist = NULL;
+  
+  work->RunningElection = False;
+  work->ElectionCount = 0;
+  work->announce_interval = 0;
+  work->needelection = False;
+  work->needannounce = True;
+  work->lastannounce_time = time(NULL);
+  work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+  work->dom_state = DOMAIN_NONE;
+  work->log_state = LOGON_NONE;
+  
+  work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
+
+  /* Make sure all token representations of workgroups are unique. */
+  
+  for (subrec = FIRST_SUBNET; subrec && (t == -1); 
+           subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    struct work_record *w;
+    for (w = subrec->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;
+  
+  /* No known local master browser as yet. */
+  *work->local_master_browser_name = '\0';
+
+  /* No known domain master browser as yet. */
+  *work->dmb_name.name = '\0';
+  putip((char *)&work->dmb_addr, &ipzero);
+
+  /* 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 a workgroup.
+  ******************************************************************/
+
+static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec, 
+                                     struct work_record *work)
+{
+  struct work_record *ret_work = NULL;
+  
+  DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
+  
+  ret_work = work->next;
+
+  remove_all_servers(work);
+  
+  if (!work->serverlist)
+  {
+    if (work->prev)
+      work->prev->next = work->next;
+    if (work->next)
+      work->next->prev = work->prev;
+  
+    if (subrec->workgrouplist == work)
+      subrec->workgrouplist = work->next; 
+  
+    free((char *)work);
+  }
+  
+  subrec->work_changed = True;
+
+  return ret_work;
+}
+
+
+/****************************************************************************
+  Find a workgroup in the workgroup list of a subnet.
+  **************************************************************************/
+
+struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec, 
+                                             fstring name)
+{
+  struct work_record *ret;
+  
+  DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
+            name, subrec->subnet_name));
+  
+  for (ret = subrec->workgrouplist; ret; ret = ret->next)
+  {
+    if (!strcmp(ret->work_group,name))
+    {
+      DEBUG(4, ("found\n"));
+      return(ret);
+    }
+  }
+  DEBUG(4, ("not found\n"));
+  return NULL;
+}
+
+/****************************************************************************
+  Create a workgroup in the workgroup list of the subnet.
+  **************************************************************************/
+
+struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
+                                               fstring name, int ttl)
+{
+  struct work_record *work = NULL;
+
+  DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
+           name, subrec->subnet_name));
+  
+  if ((work = create_workgroup(name, ttl)))
+  {
+    add_workgroup(subrec, work);
+
+    subrec->work_changed = True;
+
+    return(work);
+  }
+
+  return NULL;
+}
+
+/****************************************************************************
+  Update a workgroup ttl.
+  **************************************************************************/
+
+void update_workgroup_ttl(struct work_record *work, int ttl)
+{
+  if(work->death_time != PERMANENT_TTL)
+    work->death_time = time(NULL)+(ttl*3);
+  work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+ Fail function called if we cannot register the WORKGROUP<0> and
+ WORKGROUP<1e> names on the net.
+**************************************************************************/
+     
+static void fail_register(struct subnet_record *subrec, struct response_record *rrec,
+                          struct nmb_name *nmbname)
+{  
+  DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
+            namestr(nmbname), subrec->subnet_name));
+}  
+
+/****************************************************************************
+ If the workgroup is our primary workgroup, add the required names to it.
+**************************************************************************/
+
+void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work)
+{
+  int i;
+
+  if(!strequal(myworkgroup, work->work_group))
+    return;
+
+  /* If this is a broadcast subnet then start elections on it
+     if we are so configured. */
+
+  if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
+      (subrec != wins_server_subnet) && lp_preferred_master() &&
+      lp_local_master())
+  {
+    DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
+workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
+    work->needelection = True;
+    work->ElectionCriterion |= (1<<3);
+  }  
+  
+  /* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
+
+  register_name(subrec,myworkgroup,0x0,samba_nb_type|NB_GROUP,
+                NULL,
+                fail_register,NULL);
+     
+  register_name(subrec,myworkgroup,0x1e,samba_nb_type|NB_GROUP,
+                NULL,
+                fail_register,NULL);
+     
+  for( i = 0; my_netbios_names[i]; i++)
+  {
+    char *name = my_netbios_names[i];
+    int stype = lp_default_server_announce() | (lp_local_master() ?
+                        SV_TYPE_POTENTIAL_BROWSER : 0 );
+   
+    if(!strequal(myname, name))
+        stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
+                   SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
+   
+    create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY,
+                PERMANENT_TTL, lp_serverstring());
+    DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
+on subnet %s\n", name, subrec->subnet_name));
+  }
+} 
+
+/****************************************************************************
+  Dump a copy of the workgroup database into the log file.
+  **************************************************************************/
+
+void dump_workgroups(void)
+{
+  struct subnet_record *subrec;
+  
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    if (subrec->workgrouplist)
+    {
+      struct work_record *work;
+         
+      DEBUG(4,("dump_workgroups: dump workgroup on subnet %15s: ", subrec->subnet_name));
+      DEBUG(4,(" netmask=%15s:\n", inet_ntoa(subrec->mask_ip)));
+         
+      for (work = subrec->workgrouplist; work; work = work->next)
+      {
+        DEBUG(4,("\t%s(%d) current master browser = %s\n", work->work_group, 
+                  work->token, 
+                  *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ));
+        if (work->serverlist)
+        {
+          struct server_record *servrec;                 
+          for (servrec = work->serverlist; servrec; servrec = servrec->next)
+          {
+            DEBUG(4,("\t\t%s %8x (%s)\n",
+                  servrec->serv.name, servrec->serv.type, servrec->serv.comment));
+          }
+        }
+      }
+    }
+  }
+}
+
+/****************************************************************************
+  Expire any dead servers on all workgroups. If the workgroup has expired
+  remove it.
+  **************************************************************************/
+
+void expire_workgroups_and_servers(time_t t)
+{
+  struct subnet_record *subrec;
+   
+  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+  {
+    struct work_record *work;
+    struct work_record *nextwork;
+
+    for (work = subrec->workgrouplist; work; work = nextwork)
+    {
+      nextwork = work->next;
+      expire_servers(work, t);
+
+      if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) && 
+                     ((t == -1) || (work->death_time < t)))
+      {
+        DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
+                  work->work_group));
+        remove_workgroup_from_subnet(subrec, work);
+      }
+    }
+  }
+}
diff --git a/source/nmbsync.c b/source/nmbsync.c
deleted file mode 100644 (file)
index c1db37f..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
-   NBT netbios routines to synchronise browse lists
-   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.
-   
-*/
-
-#include "includes.h"
-
-extern int DEBUGLEVEL;
-
-static struct work_record *call_w;
-static struct subnet_record *call_d;
-
-/*******************************************************************
-  This is the NetServerEnum callback
-  ******************************************************************/
-static void callback(char *sname, uint32 stype, char *comment)
-{
-       struct work_record *w = call_w;
-
-       stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
-
-       if (stype & SV_TYPE_DOMAIN_ENUM) {
-               /* creates workgroup on remote subnet */
-               if ((w = find_workgroupstruct(call_d,sname,True))) {
-                       announce_request(w, call_d->bcast_ip);
-               }
-       }
-             
-       if (w) {
-               add_server_entry(call_d,w,sname,stype,
-                                lp_max_ttl(),comment,False);
-       }
-}
-
-
-/*******************************************************************
-  synchronise browse lists with another browse server.
-
-  log in on the remote server's SMB port to their IPC$ service,
-  do a NetServerEnum and update our server and workgroup databases.
-  ******************************************************************/
-void sync_browse_lists(struct subnet_record *d, struct work_record *work,
-                      char *name, int nm_type, struct in_addr ip, BOOL local)
-{
-       extern fstring local_machine;
-       static struct cli_state cli;
-       uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
-
-       if (!d || !work ) return;
-
-       if(d != wins_client_subnet) {
-               DEBUG(0,("sync_browse_lists: ERROR sync requested on non-WINS subnet.\n"));
-               return;
-       }
-
-       DEBUG(2,("sync_browse_lists: Sync browse lists with %s for %s %s\n",
-                name, work->work_group, inet_ntoa(ip)));
-
-       if (!cli_initialise(&cli) || !cli_connect(&cli, name, &ip)) {
-               DEBUG(1,("Failed to start browse sync with %s\n", name));
-       }
-
-       if (!cli_session_request(&cli, name, nm_type, local_machine)) {
-               DEBUG(1,("%s rejected the browse sync session\n",name));
-               cli_shutdown(&cli);
-               return;
-       }
-
-       if (!cli_negprot(&cli)) {
-               DEBUG(1,("%s rejected the negprot\n",name));
-               cli_shutdown(&cli);
-               return;
-       }
-
-       if (!cli_session_setup(&cli, "", "", 1, "", 0, work->work_group)) {
-               DEBUG(1,("%s rejected the browse sync sessionsetup\n", 
-                        name));
-               cli_shutdown(&cli);
-               return;
-       }
-
-       if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
-               DEBUG(1,("%s refused browse sync IPC$ connect\n", name));
-               cli_shutdown(&cli);
-               return;
-       }
-
-       call_w = work;
-       call_d = d;
-       
-       cli_NetServerEnum(&cli, work->work_group, 
-                         local_type|SV_TYPE_DOMAIN_ENUM,
-                         callback);
-
-       cli_NetServerEnum(&cli, work->work_group, 
-                         local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
-                         callback);
-
-       cli_shutdown(&cli);
-}
index a8e70717b610c037d4b3826f68edb956be7aa52b..76618e9a79100bceafdaedbe2e39e07deff72373 100644 (file)
@@ -157,6 +157,8 @@ typedef struct
   int syslog;
   int os_level;
   int max_ttl;
+  int max_wins_ttl;
+  int min_wins_ttl;
   int ReadSize;
   int shmem_size;
   int client_code_page;
@@ -503,6 +505,8 @@ static struct parm_struct
   {"client code page", P_INTEGER, P_GLOBAL, &Globals.client_code_page, NULL,   NULL},
   {"os level",         P_INTEGER, P_GLOBAL, &Globals.os_level,          NULL,   NULL},
   {"max ttl",          P_INTEGER, P_GLOBAL, &Globals.max_ttl,           NULL,   NULL},
+  {"max wins ttl",     P_INTEGER, P_GLOBAL, &Globals.max_wins_ttl,      NULL,   NULL},
+  {"min wins ttl",     P_INTEGER, P_GLOBAL, &Globals.min_wins_ttl,      NULL,   NULL},
   {"dns proxy",        P_BOOL,    P_GLOBAL, &Globals.bDNSproxy,         NULL,   NULL},
   {"wins support",     P_BOOL,    P_GLOBAL, &Globals.bWINSsupport,      NULL,   NULL},
   {"wins proxy",       P_BOOL,    P_GLOBAL, &Globals.bWINSproxy,        NULL,   NULL},
@@ -691,7 +695,9 @@ static void init_globals(void)
   Globals.syslog = 1;
   Globals.bSyslogOnly = False;
   Globals.os_level = 0;
-  Globals.max_ttl = 60*60*4; /* 2 hours default */
+  Globals.max_ttl = 60*60*4; /* 4 hours default */
+  Globals.max_wins_ttl = 60*60*24*3; /* 3 days default */
+  Globals.min_wins_ttl = 60*60*6; /* 6 hours default */
   Globals.ReadSize = 16*1024;
   Globals.shmem_size = SHMEM_SIZE;
   Globals.announce_as = ANNOUNCE_AS_NT;
@@ -921,6 +927,8 @@ FN_GLOBAL_BOOL(lp_bind_interfaces_only,&Globals.bBindInterfacesOnly)
 
 FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
 FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
+FN_GLOBAL_INTEGER(lp_max_wins_ttl,&Globals.max_wins_ttl)
+FN_GLOBAL_INTEGER(lp_min_wins_ttl,&Globals.max_wins_ttl)
 FN_GLOBAL_INTEGER(lp_max_log_size,&Globals.max_log_size)
 FN_GLOBAL_INTEGER(lp_mangledstack,&Globals.mangled_stack)
 FN_GLOBAL_INTEGER(lp_maxxmit,&Globals.max_xmit)
index 1f74d7a130f08bf2aea1a384ba3ec6c40d4ae992..b14887afabea4fb7db8cd02c18796fe39e15349c 100644 (file)
@@ -186,9 +186,10 @@ int main(int argc,char *argv[])
 
   for (i=optind;i<argc;i++)
   {
-      int retries = 2;
+      int j, count, retries = 2;
       char *p;
       struct in_addr ip;
+      struct in_addr *ip_list;
 
       fstrcpy(lookup,argv[i]);
 
@@ -219,26 +220,23 @@ int main(int argc,char *argv[])
        retries = 1;
       }
 
-      if (name_query(ServerFD,lookup,lookup_type,use_bcast,recursion_desired,
-                    bcast_addr,&ip,NULL)) 
-      {
-        printf("%s %s\n",inet_ntoa(ip),lookup);
-
-        /* We can only do find_status if the ip address returned
-           was valid - ie. name_query returned true.
-         */
-       if (find_status) 
-       {
-             printf("Looking up status of %s\n",inet_ntoa(ip));
-             name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL);
-             printf("\n");
-       }
-      }
-      else
-      {
-        printf("name_query failed to find name %s\n", lookup);
+      if ((ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,recursion_desired,
+                               bcast_addr,&count,NULL))) {
+             for (j=0;j<count;j++)
+                     printf("%s %s<%02x>\n",inet_ntoa(ip_list[j]),lookup, lookup_type);
+             
+             /* We can only do find_status if the ip address returned
+                was valid - ie. name_query returned true.
+                */
+             if (find_status) {
+                     printf("Looking up status of %s\n",inet_ntoa(ip_list[0]));
+                     name_status(ServerFD,lookup,lookup_type,True,ip_list[0],NULL,NULL,NULL);
+                     printf("\n");
+             }
+      } else {
+             printf("name_query failed to find name %s\n", lookup);
       }
   }
-
+  
   return(0);
 }