~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/nmbd/nmbd_incomingdgrams.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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