1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 | NBT netbios routines and daemon - version 2
|
---|
4 | Copyright (C) Andrew Tridgell 1994-1998
|
---|
5 | Copyright (C) Luke Kenneth Casson Leighton 1994-1998
|
---|
6 | Copyright (C) Jeremy Allison 1994-1998
|
---|
7 |
|
---|
8 | This program is free software; you can redistribute it and/or modify
|
---|
9 | it under the terms of the GNU General Public License as published by
|
---|
10 | the Free Software Foundation; either version 2 of the License, or
|
---|
11 | (at your option) any later version.
|
---|
12 |
|
---|
13 | This program is distributed in the hope that it will be useful,
|
---|
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
16 | GNU General Public License for more details.
|
---|
17 |
|
---|
18 | You should have received a copy of the GNU General Public License
|
---|
19 | along with this program; if not, write to the Free Software
|
---|
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
21 |
|
---|
22 | */
|
---|
23 |
|
---|
24 | #include "includes.h"
|
---|
25 |
|
---|
26 | extern BOOL found_lm_clients;
|
---|
27 |
|
---|
28 | #if 0
|
---|
29 |
|
---|
30 | /* XXXX note: This function is currently unsuitable for use, as it
|
---|
31 | does not properly check that a server is in a fit state to become
|
---|
32 | a backup browser before asking it to be one.
|
---|
33 | The code is left here to be worked on at a later date.
|
---|
34 | */
|
---|
35 |
|
---|
36 | /****************************************************************************
|
---|
37 | Tell a server to become a backup browser
|
---|
38 | **************************************************************************/
|
---|
39 |
|
---|
40 | void tell_become_backup(void)
|
---|
41 | {
|
---|
42 | struct subnet_record *subrec;
|
---|
43 | for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
|
---|
44 | {
|
---|
45 | struct work_record *work;
|
---|
46 | for (work = subrec->workgrouplist; work; work = work->next)
|
---|
47 | {
|
---|
48 | struct server_record *servrec;
|
---|
49 | int num_servers = 0;
|
---|
50 | int num_backups = 0;
|
---|
51 |
|
---|
52 | for (servrec = work->serverlist; servrec; servrec = servrec->next)
|
---|
53 | {
|
---|
54 | num_servers++;
|
---|
55 |
|
---|
56 | if (is_myname(servrec->serv.name))
|
---|
57 | continue;
|
---|
58 |
|
---|
59 | if (servrec->serv.type & SV_TYPE_BACKUP_BROWSER)
|
---|
60 | {
|
---|
61 | num_backups++;
|
---|
62 | continue;
|
---|
63 | }
|
---|
64 |
|
---|
65 | if (servrec->serv.type & SV_TYPE_MASTER_BROWSER)
|
---|
66 | continue;
|
---|
67 |
|
---|
68 | if (!(servrec->serv.type & SV_TYPE_POTENTIAL_BROWSER))
|
---|
69 | continue;
|
---|
70 |
|
---|
71 | DEBUG(3,("num servers: %d num backups: %d\n",
|
---|
72 | num_servers, num_backups));
|
---|
73 |
|
---|
74 | /* make first server a backup server. thereafter make every
|
---|
75 | tenth server a backup server */
|
---|
76 | if (num_backups != 0 && (num_servers+9) / num_backups > 10)
|
---|
77 | continue;
|
---|
78 |
|
---|
79 | DEBUG(2,("sending become backup to %s %s for %s\n",
|
---|
80 | servrec->serv.name, inet_ntoa(subrec->bcast_ip),
|
---|
81 | work->work_group));
|
---|
82 |
|
---|
83 | /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
|
---|
84 | do_announce_request(servrec->serv.name, work->work_group,
|
---|
85 | ANN_BecomeBackup, 0x20, 0x1e, subrec->bcast_ip);
|
---|
86 | }
|
---|
87 | }
|
---|
88 | }
|
---|
89 | }
|
---|
90 | #endif
|
---|
91 |
|
---|
92 | /*******************************************************************
|
---|
93 | Process an incoming host announcement packet.
|
---|
94 | *******************************************************************/
|
---|
95 |
|
---|
96 | void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
|
---|
97 | {
|
---|
98 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
99 | int ttl = IVAL(buf,1)/1000;
|
---|
100 | unstring announce_name;
|
---|
101 | uint32 servertype = IVAL(buf,23);
|
---|
102 | fstring comment;
|
---|
103 | struct work_record *work;
|
---|
104 | struct server_record *servrec;
|
---|
105 | unstring work_name;
|
---|
106 | unstring source_name;
|
---|
107 |
|
---|
108 | START_PROFILE(host_announce);
|
---|
109 |
|
---|
110 | pull_ascii_fstring(comment, buf+31);
|
---|
111 |
|
---|
112 | pull_ascii_nstring(announce_name, sizeof(announce_name), buf+5);
|
---|
113 | pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
|
---|
114 |
|
---|
115 | DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \
|
---|
116 | %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
|
---|
117 | nmb_namestr(&dgram->dest_name),announce_name));
|
---|
118 |
|
---|
119 | DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n",
|
---|
120 | ttl, servertype,comment));
|
---|
121 |
|
---|
122 | /* Filter servertype to remove impossible bits. */
|
---|
123 | servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
|
---|
124 |
|
---|
125 | /* A host announcement must be sent to the name WORKGROUP<1d>. */
|
---|
126 | if(dgram->dest_name.name_type != 0x1d) {
|
---|
127 | DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \
|
---|
128 | (was %02x) should be 0x1d. Allowing packet anyway.\n",
|
---|
129 | inet_ntoa(p->ip), dgram->dest_name.name_type));
|
---|
130 | /* Change it so it was. */
|
---|
131 | dgram->dest_name.name_type = 0x1d;
|
---|
132 | }
|
---|
133 |
|
---|
134 | /* For a host announce the workgroup name is the destination name. */
|
---|
135 | pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name);
|
---|
136 |
|
---|
137 | /*
|
---|
138 | * Syntax servers version 5.1 send HostAnnounce packets to
|
---|
139 | * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
|
---|
140 | * instead of WORKGROUP<1d> name. So to fix this we check if
|
---|
141 | * the workgroup name is our own name, and if so change it
|
---|
142 | * to be our primary workgroup name.
|
---|
143 | */
|
---|
144 |
|
---|
145 | if(strequal(work_name, global_myname()))
|
---|
146 | unstrcpy(work_name,lp_workgroup());
|
---|
147 |
|
---|
148 | /*
|
---|
149 | * We are being very agressive here in adding a workgroup
|
---|
150 | * name on the basis of a host announcing itself as being
|
---|
151 | * in that workgroup. Maybe we should wait for the workgroup
|
---|
152 | * announce instead ? JRA.
|
---|
153 | */
|
---|
154 |
|
---|
155 | work = find_workgroup_on_subnet(subrec, work_name);
|
---|
156 |
|
---|
157 | if(servertype != 0) {
|
---|
158 | if (work ==NULL ) {
|
---|
159 | /* We have no record of this workgroup. Add it. */
|
---|
160 | if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
|
---|
161 | goto done;
|
---|
162 | }
|
---|
163 |
|
---|
164 | if((servrec = find_server_in_workgroup( work, announce_name))==NULL) {
|
---|
165 | /* If this server is not already in the workgroup, add it. */
|
---|
166 | create_server_on_workgroup(work, announce_name,
|
---|
167 | servertype|SV_TYPE_LOCAL_LIST_ONLY,
|
---|
168 | ttl, comment);
|
---|
169 | } else {
|
---|
170 | /* Update the record. */
|
---|
171 | servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
|
---|
172 | update_server_ttl( servrec, ttl);
|
---|
173 | fstrcpy(servrec->serv.comment,comment);
|
---|
174 | }
|
---|
175 | } else {
|
---|
176 | /*
|
---|
177 | * This server is announcing it is going down. Remove it from the
|
---|
178 | * workgroup.
|
---|
179 | */
|
---|
180 | if(!is_myname(announce_name) && (work != NULL) &&
|
---|
181 | ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) {
|
---|
182 | remove_server_from_workgroup( work, servrec);
|
---|
183 | }
|
---|
184 | }
|
---|
185 |
|
---|
186 | subrec->work_changed = True;
|
---|
187 | done:
|
---|
188 |
|
---|
189 | END_PROFILE(host_announce);
|
---|
190 | }
|
---|
191 |
|
---|
192 | /*******************************************************************
|
---|
193 | Process an incoming WORKGROUP announcement packet.
|
---|
194 | *******************************************************************/
|
---|
195 |
|
---|
196 | void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
|
---|
197 | {
|
---|
198 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
199 | int ttl = IVAL(buf,1)/1000;
|
---|
200 | unstring workgroup_announce_name;
|
---|
201 | unstring master_name;
|
---|
202 | uint32 servertype = IVAL(buf,23);
|
---|
203 | struct work_record *work;
|
---|
204 | unstring source_name;
|
---|
205 | unstring dest_name;
|
---|
206 |
|
---|
207 | START_PROFILE(workgroup_announce);
|
---|
208 |
|
---|
209 | pull_ascii_nstring(workgroup_announce_name,sizeof(workgroup_announce_name),buf+5);
|
---|
210 | pull_ascii_nstring(master_name,sizeof(master_name),buf+31);
|
---|
211 | pull_ascii_nstring(source_name,sizeof(source_name),dgram->source_name.name);
|
---|
212 | pull_ascii_nstring(dest_name,sizeof(dest_name),dgram->dest_name.name);
|
---|
213 |
|
---|
214 | DEBUG(3,("process_workgroup_announce: from %s<%02x> IP %s to \
|
---|
215 | %s for workgroup %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
|
---|
216 | nmb_namestr(&dgram->dest_name),workgroup_announce_name));
|
---|
217 |
|
---|
218 | DEBUG(5,("process_workgroup_announce: ttl=%d server type=%08x master browser=%s\n",
|
---|
219 | ttl, servertype, master_name));
|
---|
220 |
|
---|
221 | /* Workgroup announcements must only go to the MSBROWSE name. */
|
---|
222 | if (!strequal(dest_name, MSBROWSE) || (dgram->dest_name.name_type != 0x1)) {
|
---|
223 | DEBUG(0,("process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s\n",
|
---|
224 | inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
|
---|
225 | goto done;
|
---|
226 | }
|
---|
227 |
|
---|
228 | if ((work = find_workgroup_on_subnet(subrec, workgroup_announce_name))==NULL) {
|
---|
229 | /* We have no record of this workgroup. Add it. */
|
---|
230 | if((work = create_workgroup_on_subnet(subrec, workgroup_announce_name, ttl))==NULL)
|
---|
231 | goto done;
|
---|
232 | } else {
|
---|
233 | /* Update the workgroup death_time. */
|
---|
234 | update_workgroup_ttl(work, ttl);
|
---|
235 | }
|
---|
236 |
|
---|
237 | if(*work->local_master_browser_name == '\0') {
|
---|
238 | /* Set the master browser name. */
|
---|
239 | set_workgroup_local_master_browser_name( work, master_name );
|
---|
240 | }
|
---|
241 |
|
---|
242 | subrec->work_changed = True;
|
---|
243 |
|
---|
244 | done:
|
---|
245 |
|
---|
246 | END_PROFILE(workgroup_announce);
|
---|
247 | }
|
---|
248 |
|
---|
249 | /*******************************************************************
|
---|
250 | Process an incoming local master browser announcement packet.
|
---|
251 | *******************************************************************/
|
---|
252 |
|
---|
253 | void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
|
---|
254 | {
|
---|
255 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
256 | int ttl = IVAL(buf,1)/1000;
|
---|
257 | unstring server_name;
|
---|
258 | uint32 servertype = IVAL(buf,23);
|
---|
259 | fstring comment;
|
---|
260 | unstring work_name;
|
---|
261 | struct work_record *work;
|
---|
262 | struct server_record *servrec;
|
---|
263 | unstring source_name;
|
---|
264 |
|
---|
265 | START_PROFILE(local_master_announce);
|
---|
266 |
|
---|
267 | pull_ascii_nstring(server_name,sizeof(server_name),buf+5);
|
---|
268 | pull_ascii_fstring(comment, buf+31);
|
---|
269 | pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
|
---|
270 | pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name);
|
---|
271 |
|
---|
272 | DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \
|
---|
273 | %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
|
---|
274 | nmb_namestr(&dgram->dest_name),server_name));
|
---|
275 |
|
---|
276 | DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n",
|
---|
277 | ttl, servertype, comment));
|
---|
278 |
|
---|
279 | /* A local master announcement must be sent to the name WORKGROUP<1e>. */
|
---|
280 | if(dgram->dest_name.name_type != 0x1e) {
|
---|
281 | DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \
|
---|
282 | (was %02x) should be 0x1e. Ignoring packet.\n",
|
---|
283 | inet_ntoa(p->ip), dgram->dest_name.name_type));
|
---|
284 | goto done;
|
---|
285 | }
|
---|
286 |
|
---|
287 | /* Filter servertype to remove impossible bits. */
|
---|
288 | servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
|
---|
289 |
|
---|
290 | /* For a local master announce the workgroup name is the destination name. */
|
---|
291 |
|
---|
292 | if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL) {
|
---|
293 | /* Don't bother adding if it's a local master release announce. */
|
---|
294 | if(servertype == 0)
|
---|
295 | goto done;
|
---|
296 |
|
---|
297 | /* We have no record of this workgroup. Add it. */
|
---|
298 | if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
|
---|
299 | goto done;
|
---|
300 | }
|
---|
301 |
|
---|
302 | /* If we think we're the local master browser for this workgroup,
|
---|
303 | we should never have got this packet. We don't see our own
|
---|
304 | packets.
|
---|
305 | */
|
---|
306 | if(AM_LOCAL_MASTER_BROWSER(work)) {
|
---|
307 | DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \
|
---|
308 | a local master browser for workgroup %s and we think we are master. Forcing election.\n",
|
---|
309 | server_name, inet_ntoa(p->ip), work_name));
|
---|
310 |
|
---|
311 | /* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
|
---|
312 | they have become a local master browser once, they will never
|
---|
313 | stop sending local master announcements. To fix this we send
|
---|
314 | them a reset browser packet, with level 0x2 on the __SAMBA__
|
---|
315 | name that only they should be listening to. */
|
---|
316 |
|
---|
317 | send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip);
|
---|
318 |
|
---|
319 | /* We should demote ourself and force an election. */
|
---|
320 |
|
---|
321 | unbecome_local_master_browser( subrec, work, True);
|
---|
322 |
|
---|
323 | /* The actual election requests are handled in nmbd_election.c */
|
---|
324 | goto done;
|
---|
325 | }
|
---|
326 |
|
---|
327 | /* Find the server record on this workgroup. If it doesn't exist, add it. */
|
---|
328 |
|
---|
329 | if(servertype != 0) {
|
---|
330 | if((servrec = find_server_in_workgroup( work, server_name))==NULL) {
|
---|
331 | /* If this server is not already in the workgroup, add it. */
|
---|
332 | create_server_on_workgroup(work, server_name,
|
---|
333 | servertype|SV_TYPE_LOCAL_LIST_ONLY,
|
---|
334 | ttl, comment);
|
---|
335 | } else {
|
---|
336 | /* Update the record. */
|
---|
337 | servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
|
---|
338 | update_server_ttl(servrec, ttl);
|
---|
339 | fstrcpy(servrec->serv.comment,comment);
|
---|
340 | }
|
---|
341 |
|
---|
342 | set_workgroup_local_master_browser_name( work, server_name );
|
---|
343 | } else {
|
---|
344 | /*
|
---|
345 | * This server is announcing it is going down. Remove it from the
|
---|
346 | * workgroup.
|
---|
347 | */
|
---|
348 | if(!is_myname(server_name) && (work != NULL) &&
|
---|
349 | ((servrec = find_server_in_workgroup( work, server_name))!=NULL)) {
|
---|
350 | remove_server_from_workgroup( work, servrec);
|
---|
351 | }
|
---|
352 | }
|
---|
353 |
|
---|
354 | subrec->work_changed = True;
|
---|
355 | done:
|
---|
356 |
|
---|
357 | END_PROFILE(local_master_announce);
|
---|
358 | }
|
---|
359 |
|
---|
360 | /*******************************************************************
|
---|
361 | Process a domain master announcement frame.
|
---|
362 | Domain master browsers receive these from local masters. The Domain
|
---|
363 | master should then issue a sync with the local master, asking for
|
---|
364 | that machines local server list.
|
---|
365 | ******************************************************************/
|
---|
366 |
|
---|
367 | void process_master_browser_announce(struct subnet_record *subrec,
|
---|
368 | struct packet_struct *p,char *buf)
|
---|
369 | {
|
---|
370 | unstring local_master_name;
|
---|
371 | struct work_record *work;
|
---|
372 | struct browse_cache_record *browrec;
|
---|
373 |
|
---|
374 | START_PROFILE(master_browser_announce);
|
---|
375 |
|
---|
376 | pull_ascii_nstring(local_master_name,sizeof(local_master_name),buf);
|
---|
377 |
|
---|
378 | DEBUG(3,("process_master_browser_announce: Local master announce from %s IP %s.\n",
|
---|
379 | local_master_name, inet_ntoa(p->ip)));
|
---|
380 |
|
---|
381 | if (!lp_domain_master()) {
|
---|
382 | DEBUG(0,("process_master_browser_announce: Not configured as domain \
|
---|
383 | master - ignoring master announce.\n"));
|
---|
384 | goto done;
|
---|
385 | }
|
---|
386 |
|
---|
387 | if((work = find_workgroup_on_subnet(subrec, lp_workgroup())) == NULL) {
|
---|
388 | DEBUG(0,("process_master_browser_announce: Cannot find workgroup %s on subnet %s\n",
|
---|
389 | lp_workgroup(), subrec->subnet_name));
|
---|
390 | goto done;
|
---|
391 | }
|
---|
392 |
|
---|
393 | if(!AM_DOMAIN_MASTER_BROWSER(work)) {
|
---|
394 | DEBUG(0,("process_master_browser_announce: Local master announce made to us from \
|
---|
395 | %s IP %s and we are not a domain master browser.\n", local_master_name, inet_ntoa(p->ip)));
|
---|
396 | goto done;
|
---|
397 | }
|
---|
398 |
|
---|
399 | /* Add this host as a local master browser entry on the browse lists.
|
---|
400 | This causes a sync request to be made to it at a later date.
|
---|
401 | */
|
---|
402 |
|
---|
403 | if((browrec = find_browser_in_lmb_cache( local_master_name )) == NULL) {
|
---|
404 | /* Add it. */
|
---|
405 | create_browser_in_lmb_cache( work->work_group, local_master_name, p->ip);
|
---|
406 | } else {
|
---|
407 | update_browser_death_time(browrec);
|
---|
408 | }
|
---|
409 |
|
---|
410 | done:
|
---|
411 |
|
---|
412 | END_PROFILE(master_browser_announce);
|
---|
413 | }
|
---|
414 |
|
---|
415 | /*******************************************************************
|
---|
416 | Process an incoming LanMan host announcement packet.
|
---|
417 | *******************************************************************/
|
---|
418 |
|
---|
419 | void process_lm_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf, int len)
|
---|
420 | {
|
---|
421 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
422 | uint32 servertype = IVAL(buf,1);
|
---|
423 | int osmajor=CVAL(buf,5); /* major version of node software */
|
---|
424 | int osminor=CVAL(buf,6); /* minor version of node software */
|
---|
425 | int ttl = SVAL(buf,7);
|
---|
426 | unstring announce_name;
|
---|
427 | struct work_record *work;
|
---|
428 | struct server_record *servrec;
|
---|
429 | unstring work_name;
|
---|
430 | unstring source_name;
|
---|
431 | fstring comment;
|
---|
432 | char *s = get_safe_str_ptr(buf,len,buf,9);
|
---|
433 |
|
---|
434 | START_PROFILE(lm_host_announce);
|
---|
435 | if (!s) {
|
---|
436 | goto done;
|
---|
437 | }
|
---|
438 | s = skip_string(buf,len,s);
|
---|
439 | if (!s) {
|
---|
440 | goto done;
|
---|
441 | }
|
---|
442 | pull_ascii(comment, s, sizeof(fstring), 43, STR_TERMINATE);
|
---|
443 |
|
---|
444 | pull_ascii_nstring(announce_name,sizeof(announce_name),buf+9);
|
---|
445 | pull_ascii_nstring(source_name,sizeof(source_name),dgram->source_name.name);
|
---|
446 | /* For a LanMan host announce the workgroup name is the destination name. */
|
---|
447 | pull_ascii_nstring(work_name,sizeof(work_name),dgram->dest_name.name);
|
---|
448 |
|
---|
449 | DEBUG(3,("process_lm_host_announce: LM Announcement from %s IP %s to \
|
---|
450 | %s for server %s.\n", nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
|
---|
451 | nmb_namestr(&dgram->dest_name),announce_name));
|
---|
452 |
|
---|
453 | DEBUG(5,("process_lm_host_announce: os=(%d,%d) ttl=%d server type=%08x comment=%s\n",
|
---|
454 | osmajor, osminor, ttl, servertype,comment));
|
---|
455 |
|
---|
456 | if ((osmajor < 36) || (osmajor > 38) || (osminor !=0)) {
|
---|
457 | DEBUG(5,("process_lm_host_announce: LM Announcement packet does not \
|
---|
458 | originate from OS/2 Warp client. Ignoring packet.\n"));
|
---|
459 | /* Could have been from a Windows machine (with its LM Announce enabled),
|
---|
460 | or a Samba server. Then don't disrupt the current browse list. */
|
---|
461 | goto done;
|
---|
462 | }
|
---|
463 |
|
---|
464 | /* Filter servertype to remove impossible bits. */
|
---|
465 | servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
|
---|
466 |
|
---|
467 | /* A LanMan host announcement must be sent to the name WORKGROUP<00>. */
|
---|
468 | if(dgram->dest_name.name_type != 0x00) {
|
---|
469 | DEBUG(2,("process_lm_host_announce: incorrect name type for destination from IP %s \
|
---|
470 | (was %02x) should be 0x00. Allowing packet anyway.\n",
|
---|
471 | inet_ntoa(p->ip), dgram->dest_name.name_type));
|
---|
472 | /* Change it so it was. */
|
---|
473 | dgram->dest_name.name_type = 0x00;
|
---|
474 | }
|
---|
475 |
|
---|
476 | /*
|
---|
477 | * Syntax servers version 5.1 send HostAnnounce packets to
|
---|
478 | * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
|
---|
479 | * instead of WORKGROUP<1d> name. So to fix this we check if
|
---|
480 | * the workgroup name is our own name, and if so change it
|
---|
481 | * to be our primary workgroup name. This code is probably
|
---|
482 | * not needed in the LanMan announce code, but it won't hurt.
|
---|
483 | */
|
---|
484 |
|
---|
485 | if(strequal(work_name, global_myname()))
|
---|
486 | unstrcpy(work_name,lp_workgroup());
|
---|
487 |
|
---|
488 | /*
|
---|
489 | * We are being very agressive here in adding a workgroup
|
---|
490 | * name on the basis of a host announcing itself as being
|
---|
491 | * in that workgroup. Maybe we should wait for the workgroup
|
---|
492 | * announce instead ? JRA.
|
---|
493 | */
|
---|
494 |
|
---|
495 | work = find_workgroup_on_subnet(subrec, work_name);
|
---|
496 |
|
---|
497 | if(servertype != 0) {
|
---|
498 | if (work == NULL) {
|
---|
499 | /* We have no record of this workgroup. Add it. */
|
---|
500 | if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
|
---|
501 | goto done;
|
---|
502 | }
|
---|
503 |
|
---|
504 | if((servrec = find_server_in_workgroup( work, announce_name))==NULL) {
|
---|
505 | /* If this server is not already in the workgroup, add it. */
|
---|
506 | create_server_on_workgroup(work, announce_name,
|
---|
507 | servertype|SV_TYPE_LOCAL_LIST_ONLY,
|
---|
508 | ttl, comment);
|
---|
509 | } else {
|
---|
510 | /* Update the record. */
|
---|
511 | servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
|
---|
512 | update_server_ttl( servrec, ttl);
|
---|
513 | fstrcpy(servrec->serv.comment,comment);
|
---|
514 | }
|
---|
515 | } else {
|
---|
516 | /*
|
---|
517 | * This server is announcing it is going down. Remove it from the
|
---|
518 | * workgroup.
|
---|
519 | */
|
---|
520 | if(!is_myname(announce_name) && (work != NULL) &&
|
---|
521 | ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) {
|
---|
522 | remove_server_from_workgroup( work, servrec);
|
---|
523 | }
|
---|
524 | }
|
---|
525 |
|
---|
526 | subrec->work_changed = True;
|
---|
527 | found_lm_clients = True;
|
---|
528 |
|
---|
529 | done:
|
---|
530 |
|
---|
531 | END_PROFILE(lm_host_announce);
|
---|
532 | }
|
---|
533 |
|
---|
534 | /****************************************************************************
|
---|
535 | Send a backup list response.
|
---|
536 | *****************************************************************************/
|
---|
537 |
|
---|
538 | static void send_backup_list_response(struct subnet_record *subrec,
|
---|
539 | struct work_record *work,
|
---|
540 | struct nmb_name *send_to_name,
|
---|
541 | unsigned char max_number_requested,
|
---|
542 | uint32 token, struct in_addr sendto_ip,
|
---|
543 | int port)
|
---|
544 | {
|
---|
545 | char outbuf[1024];
|
---|
546 | char *p, *countptr;
|
---|
547 | unsigned int count = 0;
|
---|
548 | unstring send_to_namestr;
|
---|
549 | #if 0
|
---|
550 | struct server_record *servrec;
|
---|
551 | #endif
|
---|
552 | unstring myname;
|
---|
553 |
|
---|
554 | memset(outbuf,'\0',sizeof(outbuf));
|
---|
555 |
|
---|
556 | DEBUG(3,("send_backup_list_response: sending backup list for workgroup %s to %s IP %s\n",
|
---|
557 | work->work_group, nmb_namestr(send_to_name), inet_ntoa(sendto_ip)));
|
---|
558 |
|
---|
559 | p = outbuf;
|
---|
560 |
|
---|
561 | SCVAL(p,0,ANN_GetBackupListResp); /* Backup list response opcode. */
|
---|
562 | p++;
|
---|
563 |
|
---|
564 | countptr = p;
|
---|
565 | p++;
|
---|
566 |
|
---|
567 | SIVAL(p,0,token); /* The sender's unique info. */
|
---|
568 | p += 4;
|
---|
569 |
|
---|
570 | /* We always return at least one name - our own. */
|
---|
571 | count = 1;
|
---|
572 | unstrcpy(myname, global_myname());
|
---|
573 | strupper_m(myname);
|
---|
574 | myname[15]='\0';
|
---|
575 | push_pstring_base(p, myname, outbuf);
|
---|
576 |
|
---|
577 | p = skip_string(outbuf,sizeof(outbuf),p);
|
---|
578 |
|
---|
579 | /* Look for backup browsers in this workgroup. */
|
---|
580 |
|
---|
581 | #if 0
|
---|
582 | /* we don't currently send become_backup requests so we should never
|
---|
583 | send any other servers names out as backups for our
|
---|
584 | workgroup. That's why this is commented out (tridge) */
|
---|
585 |
|
---|
586 | /*
|
---|
587 | * NB. Note that the struct work_record here is not neccessarily
|
---|
588 | * attached to the subnet *subrec.
|
---|
589 | */
|
---|
590 |
|
---|
591 | for (servrec = work->serverlist; servrec; servrec = servrec->next)
|
---|
592 | {
|
---|
593 | int len = PTR_DIFF(p, outbuf);
|
---|
594 | if((sizeof(outbuf) - len) < 16)
|
---|
595 | break;
|
---|
596 |
|
---|
597 | if(count >= (unsigned int)max_number_requested)
|
---|
598 | break;
|
---|
599 |
|
---|
600 | if(strnequal(servrec->serv.name, global_myname(),15))
|
---|
601 | continue;
|
---|
602 |
|
---|
603 | if(!(servrec->serv.type & SV_TYPE_BACKUP_BROWSER))
|
---|
604 | continue;
|
---|
605 |
|
---|
606 | StrnCpy(p, servrec->serv.name, 15);
|
---|
607 | strupper_m(p);
|
---|
608 | count++;
|
---|
609 |
|
---|
610 | DEBUG(5,("send_backup_list_response: Adding server %s number %d\n",
|
---|
611 | p, count));
|
---|
612 |
|
---|
613 | p = skip_string(outbuf,sizeof(outbuf),p);
|
---|
614 | }
|
---|
615 | #endif
|
---|
616 |
|
---|
617 | SCVAL(countptr, 0, count);
|
---|
618 |
|
---|
619 | pull_ascii_nstring(send_to_namestr, sizeof(send_to_namestr), send_to_name->name);
|
---|
620 |
|
---|
621 | DEBUG(4,("send_backup_list_response: sending response to %s<00> IP %s with %d servers.\n",
|
---|
622 | send_to_namestr, inet_ntoa(sendto_ip), count));
|
---|
623 |
|
---|
624 | send_mailslot(True, BROWSE_MAILSLOT,
|
---|
625 | outbuf,PTR_DIFF(p,outbuf),
|
---|
626 | global_myname(), 0,
|
---|
627 | send_to_namestr,0,
|
---|
628 | sendto_ip, subrec->myip, port);
|
---|
629 | }
|
---|
630 |
|
---|
631 | /*******************************************************************
|
---|
632 | Process a send backup list request packet.
|
---|
633 |
|
---|
634 | A client sends a backup list request to ask for a list of servers on
|
---|
635 | the net that maintain server lists for a domain. A server is then
|
---|
636 | chosen from this list to send NetServerEnum commands to to list
|
---|
637 | available servers.
|
---|
638 |
|
---|
639 | ********************************************************************/
|
---|
640 |
|
---|
641 | void process_get_backup_list_request(struct subnet_record *subrec,
|
---|
642 | struct packet_struct *p,char *buf)
|
---|
643 | {
|
---|
644 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
645 | struct work_record *work;
|
---|
646 | unsigned char max_number_requested = CVAL(buf,0);
|
---|
647 | uint32 token = IVAL(buf,1); /* Sender's key index for the workgroup. */
|
---|
648 | int name_type = dgram->dest_name.name_type;
|
---|
649 | unstring workgroup_name;
|
---|
650 | struct subnet_record *search_subrec = subrec;
|
---|
651 |
|
---|
652 | START_PROFILE(get_backup_list);
|
---|
653 | pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
|
---|
654 |
|
---|
655 | DEBUG(3,("process_get_backup_list_request: request from %s IP %s to %s.\n",
|
---|
656 | nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
|
---|
657 | nmb_namestr(&dgram->dest_name)));
|
---|
658 |
|
---|
659 | /* We have to be a master browser, or a domain master browser
|
---|
660 | for the requested workgroup. That means it must be our
|
---|
661 | workgroup. */
|
---|
662 |
|
---|
663 | if(strequal(workgroup_name, lp_workgroup()) == False) {
|
---|
664 | DEBUG(7,("process_get_backup_list_request: Ignoring announce request for workgroup %s.\n",
|
---|
665 | workgroup_name));
|
---|
666 | goto done;
|
---|
667 | }
|
---|
668 |
|
---|
669 | if((work = find_workgroup_on_subnet(search_subrec, workgroup_name)) == NULL) {
|
---|
670 | DEBUG(0,("process_get_backup_list_request: Cannot find workgroup %s on \
|
---|
671 | subnet %s.\n", workgroup_name, search_subrec->subnet_name));
|
---|
672 | goto done;
|
---|
673 | }
|
---|
674 |
|
---|
675 | /*
|
---|
676 | * If the packet was sent to WORKGROUP<1b> instead
|
---|
677 | * of WORKGROUP<1d> then it was unicast to us a domain master
|
---|
678 | * browser. Change search subrec to unicast.
|
---|
679 | */
|
---|
680 |
|
---|
681 | if(name_type == 0x1b) {
|
---|
682 | /* We must be a domain master browser in order to
|
---|
683 | process this packet. */
|
---|
684 |
|
---|
685 | if(!AM_DOMAIN_MASTER_BROWSER(work)) {
|
---|
686 | DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
|
---|
687 | and I am not a domain master browser.\n", workgroup_name));
|
---|
688 | goto done;
|
---|
689 | }
|
---|
690 |
|
---|
691 | search_subrec = unicast_subnet;
|
---|
692 | } else if (name_type == 0x1d) {
|
---|
693 | /* We must be a local master browser in order to process this packet. */
|
---|
694 |
|
---|
695 | if(!AM_LOCAL_MASTER_BROWSER(work)) {
|
---|
696 | DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
|
---|
697 | and I am not a local master browser.\n", workgroup_name));
|
---|
698 | goto done;
|
---|
699 | }
|
---|
700 | } else {
|
---|
701 | DEBUG(0,("process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d.\n",
|
---|
702 | name_type));
|
---|
703 | goto done;
|
---|
704 | }
|
---|
705 |
|
---|
706 | send_backup_list_response(subrec, work, &dgram->source_name,
|
---|
707 | max_number_requested, token, p->ip, p->port);
|
---|
708 |
|
---|
709 | done:
|
---|
710 |
|
---|
711 | END_PROFILE(get_backup_list);
|
---|
712 | }
|
---|
713 |
|
---|
714 | /*******************************************************************
|
---|
715 | Process a reset browser state packet.
|
---|
716 |
|
---|
717 | Diagnostic packet:
|
---|
718 | 0x1 - Stop being a master browser and become a backup browser.
|
---|
719 | 0x2 - Discard browse lists, stop being a master browser, try again.
|
---|
720 | 0x4 - Stop being a master browser forever.
|
---|
721 |
|
---|
722 | ******************************************************************/
|
---|
723 |
|
---|
724 | void process_reset_browser(struct subnet_record *subrec,
|
---|
725 | struct packet_struct *p,char *buf)
|
---|
726 | {
|
---|
727 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
728 | int state = CVAL(buf,0);
|
---|
729 | struct subnet_record *sr;
|
---|
730 |
|
---|
731 | START_PROFILE(reset_browser);
|
---|
732 |
|
---|
733 | DEBUG(1,("process_reset_browser: received diagnostic browser reset \
|
---|
734 | request from %s IP %s state=0x%X\n",
|
---|
735 | nmb_namestr(&dgram->source_name), inet_ntoa(p->ip), state));
|
---|
736 |
|
---|
737 | /* Stop being a local master browser on all our broadcast subnets. */
|
---|
738 | if (state & 0x1) {
|
---|
739 | for (sr = FIRST_SUBNET; sr; sr = NEXT_SUBNET_EXCLUDING_UNICAST(sr)) {
|
---|
740 | struct work_record *work;
|
---|
741 | for (work = sr->workgrouplist; work; work = work->next) {
|
---|
742 | if (AM_LOCAL_MASTER_BROWSER(work))
|
---|
743 | unbecome_local_master_browser(sr, work, True);
|
---|
744 | }
|
---|
745 | }
|
---|
746 | }
|
---|
747 |
|
---|
748 | /* Discard our browse lists. */
|
---|
749 | if (state & 0x2) {
|
---|
750 | /*
|
---|
751 | * Calling expire_workgroups_and_servers with a -1
|
---|
752 | * time causes all servers not marked with a PERMANENT_TTL
|
---|
753 | * on the workgroup lists to be discarded, and all
|
---|
754 | * workgroups with empty server lists to be discarded.
|
---|
755 | * This means we keep our own server names and workgroup
|
---|
756 | * as these have a PERMANENT_TTL.
|
---|
757 | */
|
---|
758 |
|
---|
759 | expire_workgroups_and_servers(-1);
|
---|
760 | }
|
---|
761 |
|
---|
762 | /* Request to stop browsing altogether. */
|
---|
763 | if (state & 0x4)
|
---|
764 | DEBUG(1,("process_reset_browser: ignoring request to stop being a browser.\n"));
|
---|
765 |
|
---|
766 | END_PROFILE(reset_browser);
|
---|
767 | }
|
---|
768 |
|
---|
769 | /*******************************************************************
|
---|
770 | Process an announcement request packet.
|
---|
771 | We don't respond immediately, we just check it's a request for
|
---|
772 | our workgroup and then set the flag telling the announce code
|
---|
773 | in nmbd_sendannounce.c:announce_my_server_names that an
|
---|
774 | announcement is needed soon.
|
---|
775 | ******************************************************************/
|
---|
776 |
|
---|
777 | void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf)
|
---|
778 | {
|
---|
779 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
780 | struct work_record *work;
|
---|
781 | unstring workgroup_name;
|
---|
782 |
|
---|
783 | START_PROFILE(announce_request);
|
---|
784 |
|
---|
785 | pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
|
---|
786 | DEBUG(3,("process_announce_request: Announce request from %s IP %s to %s.\n",
|
---|
787 | nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
|
---|
788 | nmb_namestr(&dgram->dest_name)));
|
---|
789 |
|
---|
790 | /* We only send announcement requests on our workgroup. */
|
---|
791 | if(strequal(workgroup_name, lp_workgroup()) == False) {
|
---|
792 | DEBUG(7,("process_announce_request: Ignoring announce request for workgroup %s.\n",
|
---|
793 | workgroup_name));
|
---|
794 | goto done;
|
---|
795 | }
|
---|
796 |
|
---|
797 | if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL) {
|
---|
798 | DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
|
---|
799 | workgroup_name));
|
---|
800 | goto done;
|
---|
801 | }
|
---|
802 |
|
---|
803 | work->needannounce = True;
|
---|
804 | done:
|
---|
805 |
|
---|
806 | END_PROFILE(announce_request);
|
---|
807 | }
|
---|
808 |
|
---|
809 | /*******************************************************************
|
---|
810 | Process a LanMan announcement request packet.
|
---|
811 | We don't respond immediately, we just check it's a request for
|
---|
812 | our workgroup and then set the flag telling that we have found
|
---|
813 | a LanMan client (DOS or OS/2) and that we will have to start
|
---|
814 | sending LanMan announcements (unless specifically disabled
|
---|
815 | through the "lm announce" parameter in smb.conf)
|
---|
816 | ******************************************************************/
|
---|
817 |
|
---|
818 | void process_lm_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf, int len)
|
---|
819 | {
|
---|
820 | struct dgram_packet *dgram = &p->packet.dgram;
|
---|
821 | unstring workgroup_name;
|
---|
822 |
|
---|
823 | START_PROFILE(lm_announce_request);
|
---|
824 |
|
---|
825 | pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
|
---|
826 | DEBUG(3,("process_lm_announce_request: Announce request from %s IP %s to %s.\n",
|
---|
827 | nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
|
---|
828 | nmb_namestr(&dgram->dest_name)));
|
---|
829 |
|
---|
830 | /* We only send announcement requests on our workgroup. */
|
---|
831 | if(strequal(workgroup_name, lp_workgroup()) == False) {
|
---|
832 | DEBUG(7,("process_lm_announce_request: Ignoring announce request for workgroup %s.\n",
|
---|
833 | workgroup_name));
|
---|
834 | goto done;
|
---|
835 | }
|
---|
836 |
|
---|
837 | if(find_workgroup_on_subnet(subrec, workgroup_name) == NULL) {
|
---|
838 | DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
|
---|
839 | workgroup_name));
|
---|
840 | goto done;
|
---|
841 | }
|
---|
842 |
|
---|
843 | found_lm_clients = True;
|
---|
844 |
|
---|
845 | done:
|
---|
846 |
|
---|
847 | END_PROFILE(lm_announce_request);
|
---|
848 | }
|
---|