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