diff options
author | Jeremy Allison <jra@samba.org> | 1997-12-16 09:20:34 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 1997-12-16 09:20:34 +0000 |
commit | 16bf14adf1b78f7ec4d3d267d500258fdf399627 (patch) | |
tree | 5933e3edc94f51bce97bf9ebca498b373fdcdc2e /source3/nmbd | |
parent | 5d4345b66de2bbf9d60e78682d820adb30b52a79 (diff) | |
download | samba-16bf14adf1b78f7ec4d3d267d500258fdf399627.tar.gz samba-16bf14adf1b78f7ec4d3d267d500258fdf399627.tar.bz2 samba-16bf14adf1b78f7ec4d3d267d500258fdf399627.zip |
Added Lanman announce patch from Jacco de Leeuw <leeuw@wins.uva.nl>.
Also added code to stop old Samba servers that announce the workgroup
name as master browser name when they are a local master browser.
Jeremy.
(This used to be commit 3605da055737e2cc0fbfffe7772721943a5be8bd)
Diffstat (limited to 'source3/nmbd')
-rw-r--r-- | source3/nmbd/nmbd.c | 10 | ||||
-rw-r--r-- | source3/nmbd/nmbd_become_lmb.c | 29 | ||||
-rw-r--r-- | source3/nmbd/nmbd_incomingdgrams.c | 151 | ||||
-rw-r--r-- | source3/nmbd/nmbd_packets.c | 56 | ||||
-rw-r--r-- | source3/nmbd/nmbd_processlogon.c | 2 | ||||
-rw-r--r-- | source3/nmbd/nmbd_sendannounce.c | 106 |
6 files changed, 341 insertions, 13 deletions
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c index 11cd50cd76..86f01d8e79 100644 --- a/source3/nmbd/nmbd.c +++ b/source3/nmbd/nmbd.c @@ -47,6 +47,9 @@ extern char **my_netbios_names; /* 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; @@ -289,6 +292,13 @@ static void process(void) 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. * This also deals with syncronising the domain master diff --git a/source3/nmbd/nmbd_become_lmb.c b/source3/nmbd/nmbd_become_lmb.c index 7f54471a24..6496a2f9e5 100644 --- a/source3/nmbd/nmbd_become_lmb.c +++ b/source3/nmbd/nmbd_become_lmb.c @@ -115,7 +115,7 @@ in workgroup %s on subnet %s\n", /* 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 @@ -333,8 +333,7 @@ on subnet %s\n", work->work_group, subrec->subnet_name)); 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 @@ -532,3 +531,27 @@ in workgroup %s on subnet %s\n", 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); +} diff --git a/source3/nmbd/nmbd_incomingdgrams.c b/source3/nmbd/nmbd_incomingdgrams.c index d43b1369e6..452516b64e 100644 --- a/source3/nmbd/nmbd_incomingdgrams.c +++ b/source3/nmbd/nmbd_incomingdgrams.c @@ -28,6 +28,7 @@ extern int DEBUGLEVEL; extern pstring myname; extern fstring myworkgroup; +extern BOOL found_lm_clients; #if 0 @@ -223,9 +224,7 @@ void process_workgroup_announce(struct subnet_record *subrec, struct packet_stru 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; @@ -324,9 +323,7 @@ a local master browser for workgroup %s and we think we are master. Forcing elec 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; } @@ -384,6 +381,105 @@ master - ignoring master announce.\n")); 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. *****************************************************************************/ @@ -600,12 +696,12 @@ request from %s IP %s state=0x%X\n", } /******************************************************************* - 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) { @@ -634,3 +730,40 @@ void process_announce_request(struct subnet_record *subrec, struct packet_struct 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; +} diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c index 43249cc0a3..4fb0543967 100644 --- a/source3/nmbd/nmbd_packets.c +++ b/source3/nmbd/nmbd_packets.c @@ -1024,6 +1024,56 @@ command code %d from %s IP %s to %s\n", } /**************************************************************************** + 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 stage as subsequent processing is expensive. @@ -1100,6 +1150,12 @@ static void process_dgram(struct packet_struct *p) 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)) { diff --git a/source3/nmbd/nmbd_processlogon.c b/source3/nmbd/nmbd_processlogon.c index ae917564fe..cd2fbfd0a5 100644 --- a/source3/nmbd/nmbd_processlogon.c +++ b/source3/nmbd/nmbd_processlogon.c @@ -63,7 +63,7 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len, 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; } diff --git a/source3/nmbd/nmbd_sendannounce.c b/source3/nmbd/nmbd_sendannounce.c index e4b288aea5..aac3dad366 100644 --- a/source3/nmbd/nmbd_sendannounce.c +++ b/source3/nmbd/nmbd_sendannounce.c @@ -32,6 +32,7 @@ extern pstring myname; extern fstring myworkgroup; extern char **my_netbios_names; extern int updatecount; +extern BOOL found_lm_clients; /**************************************************************************** Send a browser reset packet. @@ -127,6 +128,37 @@ static void send_announcement(struct subnet_record *subrec, int announce_type, } /**************************************************************************** + 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>. ****************************************************************************/ @@ -192,6 +224,29 @@ static void send_host_announcement(struct subnet_record *subrec, struct work_rec } /**************************************************************************** + 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. ****************************************************************************/ @@ -258,6 +313,56 @@ void announce_my_server_names(time_t t) } /* 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; @@ -342,6 +447,7 @@ void announce_my_servers_removed(void) 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); } } } |