- added the "remote announce" option
[kai/samba.git] / source3 / nmbd / nmbd.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NBT netbios routines and daemon - version 2
5    Copyright (C) Andrew Tridgell 1994-1995
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21    Revision History:
22
23    14 jan 96: lkcl@pires.co.uk
24    added multiple workgroup domain master support
25
26 */
27
28 #include "includes.h"
29
30 extern int DEBUGLEVEL;
31
32 extern pstring debugf;
33 pstring servicesf = CONFIGFILE;
34
35 extern pstring scope;
36
37 int ClientNMB   = -1;
38 int ClientDGRAM = -1;
39
40 extern pstring myhostname;
41 static pstring host_file;
42 extern pstring myname;
43
44 /* are we running as a daemon ? */
45 static BOOL is_daemon = False;
46
47 /* machine comment for host announcements */
48 pstring ServerComment="";
49
50 /* what server type are we currently */
51
52 time_t StartupTime =0;
53
54 extern struct in_addr ipzero;
55
56  /****************************************************************************
57   catch a sigterm
58   ****************************************************************************/
59 static int sig_term()
60 {
61   BlockSignals(True,SIGTERM);
62   
63   DEBUG(0,("Got SIGTERM: going down...\n"));
64   
65   /* write out wins.dat file if samba is a WINS server */
66   dump_names();
67   
68   /* remove all samba names, with wins server if necessary. */
69   remove_my_names();
70   
71   /* announce all server entries as 0 time-to-live, 0 type */
72   /* XXXX don't care if we never receive a response back... yet */
73   remove_my_servers();
74
75   /* XXXX other things: if we are a master browser, force an election? */
76   
77   exit(0);
78 }
79
80
81 /****************************************************************************
82 catch a sighup
83 ****************************************************************************/
84 static int sig_hup(void)
85 {
86   BlockSignals(True,SIGHUP);
87
88   DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
89   dump_names();
90   reload_services(True);
91
92   set_samba_nb_type();
93
94   BlockSignals(False,SIGHUP);
95 #ifndef DONT_REINSTALL_SIG
96   signal(SIGHUP,SIGNAL_CAST sig_hup);
97 #endif
98   return(0);
99 }
100
101 /****************************************************************************
102 catch a sigpipe
103 ****************************************************************************/
104 static int sig_pipe(void)
105 {
106   BlockSignals(True,SIGPIPE);
107
108   DEBUG(0,("Got SIGPIPE\n"));
109   if (!is_daemon)
110     exit(1);
111   BlockSignals(False,SIGPIPE);
112   return(0);
113 }
114
115 #if DUMP_CORE
116 /*******************************************************************
117 prepare to dump a core file - carefully!
118 ********************************************************************/
119 static BOOL dump_core(void)
120 {
121   char *p;
122   pstring dname;
123   strcpy(dname,debugf);
124   if ((p=strrchr(dname,'/'))) *p=0;
125   strcat(dname,"/corefiles");
126   mkdir(dname,0700);
127   sys_chown(dname,getuid(),getgid());
128   chmod(dname,0700);
129   if (chdir(dname)) return(False);
130   umask(~(0700));
131
132 #ifndef NO_GETRLIMIT
133 #ifdef RLIMIT_CORE
134   {
135     struct rlimit rlp;
136     getrlimit(RLIMIT_CORE, &rlp);
137     rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
138     setrlimit(RLIMIT_CORE, &rlp);
139     getrlimit(RLIMIT_CORE, &rlp);
140     DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
141   }
142 #endif
143 #endif
144
145
146   DEBUG(0,("Dumping core in %s\n",dname));
147   return(True);
148 }
149 #endif
150
151
152 /****************************************************************************
153 possibly continue after a fault
154 ****************************************************************************/
155 static void fault_continue(void)
156 {
157 #if DUMP_CORE
158   dump_core();
159 #endif
160 }
161
162 /*******************************************************************
163   expire old names from the namelist and server list
164   ******************************************************************/
165 static void expire_names_and_servers(void)
166 {
167   static time_t lastrun = 0;
168   time_t t = time(NULL);
169   
170   if (!lastrun) lastrun = t;
171   if (t < lastrun + 5) return;
172   lastrun = t;
173   
174   expire_names(t);
175   expire_servers(t);
176 }
177
178 /*****************************************************************************
179   reload the services file
180   **************************************************************************/
181 BOOL reload_services(BOOL test)
182 {
183   BOOL ret;
184   extern fstring remote_machine;
185
186   strcpy(remote_machine,"nmbd");
187
188   if (lp_loaded())
189     {
190       pstring fname;
191       strcpy(fname,lp_configfile());
192       if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
193         {
194           strcpy(servicesf,fname);
195           test = False;
196         }
197     }
198
199   if (test && !lp_file_list_changed())
200     return(True);
201
202   ret = lp_load(servicesf,True);
203
204   /* perhaps the config filename is now set */
205   if (!test) {
206     DEBUG(3,("services not loaded\n"));
207     reload_services(True);
208   }
209
210   load_interfaces();
211   add_subnet_interfaces();
212
213   return(ret);
214 }
215
216
217
218 /****************************************************************************
219 load a netbios hosts file
220 ****************************************************************************/
221 static void load_hosts_file(char *fname)
222 {
223   FILE *f = fopen(fname,"r");
224   pstring line;
225   if (!f) {
226     DEBUG(2,("Can't open lmhosts file %s\n",fname));
227     return;
228   }
229
230   while (!feof(f))
231     {
232       pstring ip,name,flags,extra;
233       struct subnet_record *d;
234       char *ptr;
235       int count = 0;
236       struct in_addr ipaddr;
237       enum name_source source = LMHOSTS;
238
239       if (!fgets_slash(line,sizeof(pstring),f)) continue;
240
241       if (*line == '#') continue;
242
243       strcpy(ip,"");
244       strcpy(name,"");
245       strcpy(flags,"");
246       
247       ptr = line;
248       
249       if (next_token(&ptr,ip   ,NULL)) ++count;
250       if (next_token(&ptr,name ,NULL)) ++count;
251       if (next_token(&ptr,flags,NULL)) ++count;
252       if (next_token(&ptr,extra,NULL)) ++count;
253       
254       if (count <= 0) continue;
255       
256       if (count > 0 && count < 2) {
257         DEBUG(0,("Ill formed hosts line [%s]\n",line));     
258         continue;
259       }
260       
261       if (count >= 4) {
262         DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
263         continue;
264       }
265       
266       DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
267       
268       if (strchr(flags,'G') || strchr(flags,'S')) {
269         DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
270         continue;
271       }
272       
273       if (strchr(flags,'M')) {
274         source = SELF;
275         strcpy(myname,name);
276       }
277       
278       ipaddr = *interpret_addr2(ip);
279       d = find_subnet(ipaddr);
280       if (d) {
281         add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True);
282         add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
283       } 
284     }
285   
286   fclose(f);
287 }
288
289
290 /****************************************************************************
291   The main select loop.
292   ***************************************************************************/
293 static void process(void)
294 {
295   BOOL run_election;
296
297   while (True)
298     {
299       time_t t = time(NULL);
300       run_election = check_elections();
301       listen_for_packets(run_election);
302
303       run_packet_queue();
304       run_elections();
305
306       announce_host();
307
308 #if 0
309       /* XXXX what was this stuff supposed to do? It sent
310          ANN_GetBackupListReq packets which I think should only be
311          sent when trying to find out who to browse with */      
312
313       announce_backup();
314 #endif
315
316       announce_master();
317
318       announce_remote();
319
320       query_refresh_names();
321
322       expire_names_and_servers();
323       expire_netbios_response_entries();
324       refresh_my_names(t);
325
326       write_browse_list();
327       do_browser_lists();
328       check_master_browser();
329     }
330 }
331
332
333 /****************************************************************************
334   open the socket communication
335 ****************************************************************************/
336 static BOOL open_sockets(BOOL isdaemon, int port)
337 {
338   struct hostent *hp;
339  
340   /* get host info */
341   if ((hp = Get_Hostbyname(myhostname)) == 0) {
342     DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
343     return False;
344   }   
345
346   if (isdaemon)
347     ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
348   else
349     ClientNMB = 0;
350   
351   ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
352
353   if (ClientNMB == -1)
354     return(False);
355
356   signal(SIGPIPE, SIGNAL_CAST sig_pipe);
357
358   set_socket_options(ClientNMB,"SO_BROADCAST");
359   set_socket_options(ClientDGRAM,"SO_BROADCAST");
360
361   DEBUG(3,("Sockets opened.\n"));
362   return True;
363 }
364
365
366 /****************************************************************************
367   initialise connect, service and file structs
368 ****************************************************************************/
369 static BOOL init_structs()
370 {
371   if (!get_myname(myhostname,NULL))
372     return(False);
373
374   if (! *myname) {
375     char *p;
376     strcpy(myname,myhostname);
377     p = strchr(myname,'.');
378     if (p) *p = 0;
379   }
380
381   return True;
382 }
383
384 /****************************************************************************
385 usage on the program
386 ****************************************************************************/
387 static void usage(char *pname)
388 {
389   DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
390
391   printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
392   printf("Version %s\n",VERSION);
393   printf("\t-D                    become a daemon\n");
394   printf("\t-p port               listen on the specified port\n");
395   printf("\t-d debuglevel         set the debuglevel\n");
396   printf("\t-l log basename.      Basename for log/debug files\n");
397   printf("\t-n netbiosname.       the netbios name to advertise for this host\n");
398   printf("\t-B broadcast address  the address to use for broadcasts\n");
399   printf("\t-N netmask           the netmask to use for subnet determination\n");
400   printf("\t-H hosts file        load a netbios hosts file\n");
401   printf("\t-G group name        add a group name to be part of\n");
402   printf("\t-I ip-address        override the IP address\n");
403   printf("\t-C comment           sets the machine comment that appears in browse lists\n");
404   printf("\n");
405 }
406
407
408 /****************************************************************************
409   main program
410   **************************************************************************/
411  int main(int argc,char *argv[])
412 {
413   int port = NMB_PORT;
414   int opt;
415   extern FILE *dbf;
416   extern char *optarg;
417   fstring group;
418
419   *group = 0;
420   *host_file = 0;
421
422   StartupTime = time(NULL);
423
424   TimeInit();
425
426   strcpy(debugf,NMBLOGFILE);
427
428   setup_logging(argv[0],False);
429
430   charset_initialise();
431
432 #ifdef LMHOSTSFILE
433   strcpy(host_file,LMHOSTSFILE);
434 #endif
435
436   /* this is for people who can't start the program correctly */
437   while (argc > 1 && (*argv[1] != '-')) {
438     argv++;
439     argc--;
440   }
441
442   fault_setup(fault_continue);
443
444   signal(SIGHUP ,SIGNAL_CAST sig_hup);
445   signal(SIGTERM,SIGNAL_CAST sig_term);
446
447   while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
448     {
449       switch (opt)
450         {
451         case 's':
452           strcpy(servicesf,optarg);
453           break;          
454         case 'C':
455           strcpy(ServerComment,optarg);
456           break;
457         case 'G':
458           strcpy(group,optarg);
459           break;
460         case 'H':
461           strcpy(host_file,optarg);
462           break;
463         case 'I':
464           iface_set_default(optarg,NULL,NULL);
465           break;
466         case 'B':
467           iface_set_default(NULL,optarg,NULL);
468           break;
469         case 'N':
470           iface_set_default(NULL,NULL,optarg);
471           break;
472         case 'n':
473           strcpy(myname,optarg);
474           break;
475         case 'l':
476           sprintf(debugf,"%s.nmb",optarg);
477           break;
478         case 'i':
479           strcpy(scope,optarg);
480           strupper(scope);
481           break;
482         case 'D':
483           is_daemon = True;
484           break;
485         case 'd':
486           DEBUGLEVEL = atoi(optarg);
487           break;
488         case 'p':
489           port = atoi(optarg);
490           break;
491         case 'h':
492           usage(argv[0]);
493           exit(0);
494           break;
495         default:
496           if (!is_a_socket(0)) {
497             usage(argv[0]);
498           }
499           break;
500         }
501     }
502
503   DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
504   DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
505
506   init_structs();
507
508   if (!reload_services(False))
509     return(-1); 
510
511   set_samba_nb_type();
512
513   if (*group)
514     add_my_subnets(group);
515
516   if (!is_daemon && !is_a_socket(0)) {
517     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
518     is_daemon = True;
519   }
520   
521   if (is_daemon) {
522     DEBUG(2,("%s becoming a daemon\n",timestring()));
523     become_daemon();
524   }
525
526   DEBUG(3,("Opening sockets %d\n", port));
527
528   if (!open_sockets(is_daemon,port)) return 1;
529
530   if (*host_file) {
531     load_hosts_file(host_file);
532     DEBUG(3,("Loaded hosts file\n"));
533   }
534
535
536
537   if (!*ServerComment)
538     strcpy(ServerComment,"Samba %v");
539   string_sub(ServerComment,"%v",VERSION);
540   string_sub(ServerComment,"%h",myhostname);
541
542   add_my_names();
543   add_my_subnets(lp_workgroup());
544
545   DEBUG(3,("Checked names\n"));
546   
547   load_netbios_names();
548
549   DEBUG(3,("Loaded names\n"));
550
551   write_browse_list();
552
553   DEBUG(3,("Dumped names\n"));
554
555   process();
556   close_sockets();
557
558   if (dbf)
559     fclose(dbf);
560   return(0);
561 }