#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
#define NET_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NETLOGON"
#define NT_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NTLOGON"
+#define LANMAN_MAILSLOT "\\MAILSLOT\\LANMAN"
/* Samba definitions for find_name_on_subnet(). */
#define FIND_ANY_NAME 0
int lp_syslog(void);
int lp_client_code_page(void);
int lp_announce_as(void);
+int lp_lm_announce(void);
+int lp_lm_interval(void);
char *lp_preexec(int );
char *lp_postexec(int );
char *lp_rootpreexec(int );
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);
+void set_workgroup_local_master_browser_name( struct work_record *work, char *newname);
/*The following definitions come from nmbd_browserdb.c */
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_lm_host_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);
+void process_lm_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf);
/*The following definitions come from nmbd_incomingrequests.c */
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);
+void process_lanman_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 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 announce_my_lm_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);
/* are we running as a daemon ? */
static BOOL is_daemon = False;
+/* have we found LanMan clients yet? */
+BOOL found_lm_clients = False;
+
/* what server type are we currently */
time_t StartupTime = 0;
*/
announce_my_server_names(t);
+ /*
+ * Send out any LanMan broadcast announcements
+ * of our server names.
+ * (nmbd_sendannounce.c)
+ */
+ announce_my_lm_server_names(t);
+
/*
* If we are a local master browser, periodically
* announce ourselves to the domain master browser.
/* Forget who the local master browser was for
this workgroup. */
- *work->local_master_browser_name = '\0';
+ set_workgroup_local_master_browser_name( work, "");
/*
* Ensure the IP address of this subnet is not registered as one
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);
+ set_workgroup_local_master_browser_name( work, myname);
/* Count the number of servers we have on our list. If it's
less than 10 (just a heuristic) request the servers
become_local_master_fail1,
userdata);
}
+
+/***************************************************************
+ Utility function to set the local master browser name. Does
+ some sanity checking as old versions of Samba seem to sometimes
+ say that the master browser name for a workgroup is the same
+ as the workgroup name.
+****************************************************************/
+
+void set_workgroup_local_master_browser_name( struct work_record *work, char *newname)
+{
+ DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
+for workgroup %s.\n", newname, work->work_group ));
+
+ if(strequal( work->work_group, newname))
+ {
+ DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
+local_master_browser_name for workgroup %s to workgroup name.\n",
+ work->work_group ));
+ return;
+ }
+
+ StrnCpy(work->local_master_browser_name, newname,
+ sizeof(work->local_master_browser_name)-1);
+}
extern pstring myname;
extern fstring myworkgroup;
+extern BOOL found_lm_clients;
#if 0
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);
-
+ set_workgroup_local_master_browser_name( work, master_name );
}
subrec->work_changed = True;
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);
+ set_workgroup_local_master_browser_name( work, server_name );
subrec->work_changed = True;
}
update_browser_death_time(browrec);
}
+/*******************************************************************
+ Process an incoming LanMan host announcement packet.
+*******************************************************************/
+
+void process_lm_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ uint32 servertype = IVAL(buf,1);
+ int osmajor=CVAL(buf,5); /* major version of node software */
+ int osminor=CVAL(buf,6); /* minor version of node software */
+ int ttl = SVAL(buf,7);
+ char *announce_name = buf+9;
+ struct work_record *work;
+ struct server_record *servrec;
+ char *work_name;
+ char *source_name = dgram->source_name.name;
+ pstring comment;
+ char *s = buf+9;
+
+ s = skip_string(s,1);
+ StrnCpy(comment, s, 43);
+
+ DEBUG(3,("process_lm_host_announce: LM Announcement 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_lm_host_announce: os=(%d,%d) ttl=%d server type=%08x comment=%s\n",
+ osmajor, osminor, ttl, servertype,comment));
+
+ if ((osmajor < 36) || (osmajor > 38) || (osminor !=0))
+ {
+ DEBUG(5,("process_lm_host_announce: LM Announcement packet does not " \
+ "originate from OS/2 Warp client. Ignoring packet.\n"));
+ /* Could have been from a Windows machine (with its LM Announce enabled),
+ or a Samba server. Then don't disrupt the current browse list. */
+ return;
+ }
+
+ /* Filter servertype to remove impossible bits. */
+ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+ /* A LanMan host announcement must be sent to the name WORKGROUP<00>. */
+ if(dgram->dest_name.name_type != 0x00)
+ {
+ DEBUG(2,("process_lm_host_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x00. Allowing packet anyway.\n",
+ inet_ntoa(p->ip), dgram->dest_name.name_type));
+ /* Change it so it was. */
+ dgram->dest_name.name_type = 0x00;
+ }
+
+ /* For a LanMan host announce the workgroup name is the destination name. */
+ work_name = dgram->dest_name.name;
+
+ /*
+ * Syntax servers version 5.1 send HostAnnounce packets to
+ * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
+ * instead of WORKGROUP<1d> name. So to fix this we check if
+ * the workgroup name is our own name, and if so change it
+ * to be our primary workgroup name. This code is probably
+ * not needed in the LanMan announce code, but it won't hurt.
+ */
+
+ if(strequal(work_name, myname))
+ work_name = myworkgroup;
+
+ /*
+ * 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;
+ found_lm_clients = True;
+}
+
/****************************************************************************
Send a backup list response.
*****************************************************************************/
}
/*******************************************************************
- Process a announcement request packet.
+ Process an 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
+ our 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)
{
work->needannounce = True;
}
+
+/*******************************************************************
+ Process a LanMan announcement request packet.
+ We don't respond immediately, we just check it's a request for
+ our workgroup and then set the flag telling that we have found
+ a LanMan client (DOS or OS/2) and that we will have to start
+ sending LanMan announcements (unless specifically disabled
+ through the "lm_announce" parameter in smb.conf)
+******************************************************************/
+
+void process_lm_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_lm_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_lm_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;
+ }
+
+ found_lm_clients = True;
+}
}
}
+/****************************************************************************
+ Dispatch a LanMan browse frame from port 138 to the correct processing function.
+****************************************************************************/
+
+void process_lanman_packet(struct packet_struct *p, char *buf,int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int command = SVAL(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_lanman_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_lanman_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_lm_host_announce(subrec, p, buf+1);
+ break;
+ }
+ case ANN_AnnouncementRequest:
+ {
+ process_lm_announce_request(subrec, p, buf+1);
+ break;
+ }
+ default:
+ {
+ DEBUG(0,("process_lanman_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
return;
}
+ /* Datagram packet received for the LAN Manager mailslot */
+ if (strequal(smb_buf(buf),LANMAN_MAILSLOT)) {
+ process_lanman_packet(p,buf2,len);
+ return;
+ }
+
/* Datagram packet received for the domain logon mailslot */
if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT))
{
if (!lp_domain_logons())
{
- DEBUG(3,("process_logon_packet: Logon packet received from IP %S and domain \
+ DEBUG(3,("process_logon_packet: Logon packet received from IP %s and domain \
logons are not enabled.\n", inet_ntoa(p->ip) ));
return;
}
extern fstring myworkgroup;
extern char **my_netbios_names;
extern int updatecount;
+extern BOOL found_lm_clients;
/****************************************************************************
Send a browser reset packet.
from_name, 0x0, to_name, to_type, to_ip, subrec->myip);
}
+/****************************************************************************
+ Broadcast a LanMan announcement.
+**************************************************************************/
+
+static void send_lm_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=outbuf;
+
+ bzero(outbuf,sizeof(outbuf));
+
+ SSVAL(p,0,announce_type);
+ SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
+ CVAL(p,6) = lp_major_announce_version(); /* Major version. */
+ CVAL(p,7) = lp_minor_announce_version(); /* Minor version. */
+ SSVAL(p,8,announce_interval); /* In seconds - according to spec. */
+
+ p += 10;
+ StrnCpy(p,server_name,15);
+ strupper(p);
+ p = skip_string(p,1);
+ pstrcpy(p,server_comment);
+ p = skip_string(p,1);
+
+ send_mailslot(False,LANMAN_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>.
****************************************************************************/
servrec->serv.comment);
}
+/****************************************************************************
+ Announce the given LanMan host
+****************************************************************************/
+
+static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec, int lm_interval)
+{
+ /* Ensure we don't have the prohibited bits set. */
+ uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
+ type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
+
+ send_lm_announcement(subrec, ANN_HostAnnouncement,
+ servrec->serv.name, /* From nbt name. */
+ work->work_group, 0x00, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ lm_interval, /* Time until next announce. */
+ servrec->serv.name, /* Name to announce. */
+ type, /* Type field. */
+ servrec->serv.comment);
+}
+
/****************************************************************************
Announce a server record.
****************************************************************************/
} /* for subrec */
}
+/****************************************************************************
+ Go through all my registered names on all broadcast subnets and announce
+ them as a LanMan server if the timeout requires it.
+**************************************************************************/
+
+void announce_my_lm_server_names(time_t t)
+{
+ struct subnet_record *subrec;
+ static time_t last_lm_announce_time=0;
+ int announce_interval = lp_lm_interval();
+ int lm_announce = lp_lm_announce();
+
+ if ((announce_interval <= 0) || (lm_announce <= 0))
+ {
+ /* user absolutely does not want LM announcements to be sent. */
+ return;
+ }
+
+ if ((lm_announce >= 2) && (!found_lm_clients))
+ {
+ /* has been set to 2 (Auto) but no LM clients detected (yet). */
+ return;
+ }
+
+ /* Otherwise: must have been set to 1 (Yes), or LM clients *have*
+ been detected. */
+
+ 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 (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
+ continue;
+
+ last_lm_announce_time = t;
+
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ if (is_myname(servrec->serv.name))
+ /* skipping equivalent of announce_server() */
+ send_lm_host_announcement(subrec, work, servrec, announce_interval);
+ }
+ } /* 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;
if(AM_LOCAL_MASTER_BROWSER(work))
send_local_master_announcement(subrec, work, servrec);
send_host_announcement(subrec, work, servrec);
+ send_lm_host_announcement(subrec, work, servrec, 0);
}
}
}
int max_wins_ttl;
int min_wins_ttl;
int ReadSize;
+ int lm_announce;
+ int lm_interval;
int shmem_size;
int client_code_page;
int announce_as; /* This is initialised in init_globals */
static struct enum_list enum_case[] = {{CASE_LOWER, "lower"}, {CASE_UPPER, "upper"}, {-1, NULL}};
+static struct enum_list enum_lm_announce[] = {{0, "False"}, {1, "True"}, {2, "Auto"}};
+
static struct parm_struct
{
char *label;
{"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},
+ {"lm announce", P_ENUM, P_GLOBAL, &Globals.lm_announce, NULL, enum_lm_announce},
+ {"lm interval", P_INTEGER, P_GLOBAL, &Globals.lm_interval, 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},
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.lm_announce = 2; /* = Auto: send only if LM clients found */
+ Globals.lm_interval = 60;
Globals.shmem_size = SHMEM_SIZE;
Globals.announce_as = ANNOUNCE_AS_NT;
Globals.bUnixRealname = False;
FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
FN_GLOBAL_INTEGER(lp_client_code_page,&Globals.client_code_page)
FN_GLOBAL_INTEGER(lp_announce_as,&Globals.announce_as)
+FN_GLOBAL_INTEGER(lp_lm_announce,&Globals.lm_announce)
+FN_GLOBAL_INTEGER(lp_lm_interval,&Globals.lm_interval)
FN_LOCAL_STRING(lp_preexec,szPreExec)
FN_LOCAL_STRING(lp_postexec,szPostExec)