- changed some debug levels in clientutil.c
[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 #include "loadparm.h"
30 #include "localnet.h"
31
32 extern int DEBUGLEVEL;
33
34 extern pstring debugf;
35 pstring servicesf = CONFIGFILE;
36
37 extern pstring scope;
38
39 int ClientNMB   = -1;
40 int ClientDGRAM = -1;
41
42 extern pstring myhostname;
43 static pstring host_file;
44 extern pstring myname;
45
46 /* are we running as a daemon ? */
47 static BOOL is_daemon = False;
48
49 /* machine comment for host announcements */
50 pstring ServerComment="";
51
52 static BOOL got_bcast = False;
53 static BOOL got_myip = False;
54 static BOOL got_nmask = False;
55
56 /* what server type are we currently */
57
58 time_t StartupTime =0;
59
60 struct in_addr ipzero;
61
62
63 /****************************************************************************
64 catch a sighup
65 ****************************************************************************/
66 static int sig_hup(void)
67 {
68   BlockSignals(True);
69
70   DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
71   dump_names();
72   reload_services(True);
73
74   BlockSignals(False);
75 #ifndef DONT_REINSTALL_SIG
76   signal(SIGHUP,SIGNAL_CAST sig_hup);
77 #endif
78   return(0);
79 }
80
81 /****************************************************************************
82 catch a sigpipe
83 ****************************************************************************/
84 static int sig_pipe(void)
85 {
86   BlockSignals(True);
87
88   DEBUG(0,("Got SIGPIPE\n"));
89   if (!is_daemon)
90     exit(1);
91   BlockSignals(False);
92   return(0);
93 }
94
95 #if DUMP_CORE
96 /*******************************************************************
97 prepare to dump a core file - carefully!
98 ********************************************************************/
99 static BOOL dump_core(void)
100 {
101   char *p;
102   pstring dname;
103   strcpy(dname,debugf);
104   if ((p=strrchr(dname,'/'))) *p=0;
105   strcat(dname,"/corefiles");
106   mkdir(dname,0700);
107   sys_chown(dname,getuid(),getgid());
108   chmod(dname,0700);
109   if (chdir(dname)) return(False);
110   umask(~(0700));
111
112 #ifndef NO_GETRLIMIT
113 #ifdef RLIMIT_CORE
114   {
115     struct rlimit rlp;
116     getrlimit(RLIMIT_CORE, &rlp);
117     rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
118     setrlimit(RLIMIT_CORE, &rlp);
119     getrlimit(RLIMIT_CORE, &rlp);
120     DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
121   }
122 #endif
123 #endif
124
125
126   DEBUG(0,("Dumping core in %s\n",dname));
127   return(True);
128 }
129 #endif
130
131
132 /****************************************************************************
133 possibly continue after a fault
134 ****************************************************************************/
135 static void fault_continue(void)
136 {
137 #if DUMP_CORE
138   dump_core();
139 #endif
140 }
141
142 /*******************************************************************
143   expire old names from the namelist and server list
144   ******************************************************************/
145 static void expire_names_and_servers(void)
146 {
147   static time_t lastrun = 0;
148   time_t t = time(NULL);
149   
150   if (!lastrun) lastrun = t;
151   if (t < lastrun + 5) return;
152   lastrun = t;
153   
154   expire_names(t);
155   expire_servers(t);
156 }
157
158 /*****************************************************************************
159   reload the services file
160   **************************************************************************/
161 BOOL reload_services(BOOL test)
162 {
163   BOOL ret;
164   extern fstring remote_machine;
165
166   strcpy(remote_machine,"nmbd");
167
168   if (lp_loaded())
169     {
170       pstring fname;
171       strcpy(fname,lp_configfile());
172       if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
173         {
174           strcpy(servicesf,fname);
175           test = False;
176         }
177     }
178
179   if (test && !lp_file_list_changed())
180     return(True);
181
182   ret = lp_load(servicesf,True);
183
184   /* perhaps the config filename is now set */
185   if (!test) {
186     DEBUG(3,("services not loaded\n"));
187     reload_services(True);
188   }
189
190   return(ret);
191 }
192
193
194
195 /****************************************************************************
196 load a netbios hosts file
197 ****************************************************************************/
198 static void load_hosts_file(char *fname)
199 {
200   FILE *f = fopen(fname,"r");
201   pstring line;
202   if (!f) {
203     DEBUG(2,("Can't open lmhosts file %s\n",fname));
204     return;
205   }
206
207   while (!feof(f))
208     {
209       if (!fgets_slash(line,sizeof(pstring),f)) continue;
210
211       if (*line == '#') continue;
212
213       {
214         BOOL group=False;
215
216         pstring ip,name,mask,flags,extra;
217
218         char *ptr;
219         int count = 0;
220         struct in_addr ipaddr;
221         struct in_addr ipmask;
222         enum name_source source = LMHOSTS;
223
224         strcpy(ip,"");
225         strcpy(name,"");
226         strcpy(mask,"");
227         strcpy(flags,"");
228         strcpy(extra,"");
229         
230         ptr = line;
231
232         if (next_token(&ptr,ip   ,NULL)) ++count;
233         if (next_token(&ptr,name ,NULL)) ++count;
234         if (next_token(&ptr,mask ,NULL)) ++count;
235         if (next_token(&ptr,flags,NULL)) ++count;
236         if (next_token(&ptr,extra,NULL)) ++count;
237
238         if (count <= 0) continue;
239
240         if (count > 0 && count < 2) {
241           DEBUG(0,("Ill formed hosts line [%s]\n",line));           
242           continue;
243         }
244
245         /* work out if we need to shuffle the tokens along due to the
246            optional subnet mask argument */
247
248         if (strchr(mask, 'G') || strchr(mask, 'S') || strchr(mask, 'M')) {
249           strcpy(flags, mask );
250           /* default action for no subnet mask */
251           strcpy(mask, inet_ntoa(Netmask));
252         }
253
254         DEBUG(4, ("lmhost entry: %s %s %s %s\n", ip, name, mask, flags));
255
256         if (strchr(flags,'G') || strchr(flags,'S'))
257           group = True;
258
259         if (strchr(flags,'M') && !group) {
260           source = SELF;
261           strcpy(myname,name);
262         }
263
264         ipaddr = *interpret_addr2(ip);
265         ipmask = *interpret_addr2(mask);
266
267         if (group) {
268           add_domain_entry(ipaddr, ipmask, name, True);
269         } else {
270           add_netbios_entry(name,0x20,NB_ACTIVE,0,source,ipaddr);
271         }
272       }
273     }
274
275   fclose(f);
276 }
277
278
279 /****************************************************************************
280   The main select loop.
281   ***************************************************************************/
282 static void process(void)
283 {
284   BOOL run_election;
285
286   while (True)
287     {
288       time_t t = time(NULL);
289       run_election = check_elections();
290       listen_for_packets(run_election);
291
292       run_packet_queue();
293       run_elections();
294
295       announce_host();
296
297 #if 0
298       /* what was this stuff supposed to do? It sent
299          ANN_GetBackupListReq packets which I think should only be
300          sent when trying to find out who to browse with */      
301       announce_backup();
302 #endif
303
304       announce_master();
305
306       expire_names_and_servers();
307       expire_netbios_response_entries(t-10);
308       refresh_my_names(t);
309
310       write_browse_list();
311       do_browser_lists();
312       check_master_browser();
313     }
314 }
315
316
317 /****************************************************************************
318   open the socket communication
319 ****************************************************************************/
320 static BOOL open_sockets(BOOL isdaemon, int port)
321 {
322   struct hostent *hp;
323  
324   /* get host info */
325   if ((hp = Get_Hostbyname(myhostname)) == 0) {
326     DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
327     return False;
328   }   
329
330   if (isdaemon)
331     ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
332   else
333     ClientNMB = 0;
334   
335   ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
336
337   if (ClientNMB == -1)
338     return(False);
339
340   signal(SIGPIPE, SIGNAL_CAST sig_pipe);
341
342   set_socket_options(ClientNMB,"SO_BROADCAST");
343   set_socket_options(ClientDGRAM,"SO_BROADCAST");
344
345   DEBUG(3,("Sockets opened.\n"));
346   return True;
347 }
348
349
350 /*******************************************************************
351   check that a IP, bcast and netmask and consistent. Must be a 1s
352   broadcast
353   ******************************************************************/
354 static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast, struct in_addr nmask)
355 {
356   unsigned long a_ip,a_bcast,a_nmask;
357
358   a_ip = ntohl(ip.s_addr);
359   a_bcast = ntohl(bcast.s_addr);
360   a_nmask = ntohl(nmask.s_addr);
361
362   /* check the netmask is sane */
363   if (((a_nmask>>24)&0xFF) != 0xFF) {
364     DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask)));
365     return(False);
366   }
367
368   /* check the IP and bcast are on the same net */
369   if ((a_ip&a_nmask) != (a_bcast&a_nmask)) {
370     DEBUG(0,("IP and broadcast are on different nets!\n"));
371     return(False);
372   }
373
374   /* check the IP and bcast are on the same net */
375   if ((a_bcast|a_nmask) != 0xFFFFFFFF) {
376     DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast)));
377     return(False);
378   }
379
380   return(True);
381 }
382
383
384 /****************************************************************************
385   initialise connect, service and file structs
386 ****************************************************************************/
387 static BOOL init_structs()
388 {
389   if (!get_myname(myhostname,got_myip?NULL:&myip))
390     return(False);
391
392   /* Read the broadcast address from the interface */
393   {
394     struct in_addr ip0,ip1,ip2;
395
396     ip0 = myip;
397
398     if (!(got_bcast && got_nmask))
399       {
400         get_broadcast(&ip0,&ip1,&ip2);
401
402         if (!got_myip)
403           myip = ip0;
404     
405         if (!got_bcast)
406           bcast_ip = ip1;
407     
408         if (!got_nmask)
409           Netmask = ip2;   
410       } 
411
412     DEBUG(1,("Using IP %s  ",inet_ntoa(myip))); 
413     DEBUG(1,("broadcast %s  ",inet_ntoa(bcast_ip)));
414     DEBUG(1,("netmask %s\n",inet_ntoa(Netmask)));    
415
416     if (!ip_consistent(myip,bcast_ip,Netmask)) {
417       DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n"));
418       DEBUG(0,("You are likely to experience problems with this setup!\n"));
419     }
420   }
421
422   if (! *myname) {
423     char *p;
424     strcpy(myname,myhostname);
425     p = strchr(myname,'.');
426     if (p) *p = 0;
427   }
428
429   return True;
430 }
431
432 /****************************************************************************
433 usage on the program
434 ****************************************************************************/
435 static void usage(char *pname)
436 {
437   DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
438
439   printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
440   printf("Version %s\n",VERSION);
441   printf("\t-D                    become a daemon\n");
442   printf("\t-p port               listen on the specified port\n");
443   printf("\t-d debuglevel         set the debuglevel\n");
444   printf("\t-l log basename.      Basename for log/debug files\n");
445   printf("\t-n netbiosname.       the netbios name to advertise for this host\n");
446   printf("\t-B broadcast address  the address to use for broadcasts\n");
447   printf("\t-N netmask           the netmask to use for subnet determination\n");
448   printf("\t-H hosts file        load a netbios hosts file\n");
449   printf("\t-G group name        add a group name to be part of\n");
450   printf("\t-I ip-address        override the IP address\n");
451   printf("\t-C comment           sets the machine comment that appears in browse lists\n");
452   printf("\n");
453 }
454
455
456 /****************************************************************************
457   main program
458   **************************************************************************/
459  int main(int argc,char *argv[])
460 {
461   int port = NMB_PORT;
462   int opt;
463   extern FILE *dbf;
464   extern char *optarg;
465
466   *host_file = 0;
467
468   StartupTime = time(NULL);
469
470   TimeInit();
471
472   strcpy(debugf,NMBLOGFILE);
473
474   setup_logging(argv[0],False);
475
476   charset_initialise();
477
478   ipzero = *interpret_addr2("0.0.0.0");
479
480 #ifdef LMHOSTSFILE
481   strcpy(host_file,LMHOSTSFILE);
482 #endif
483
484   /* this is for people who can't start the program correctly */
485   while (argc > 1 && (*argv[1] != '-')) {
486     argv++;
487     argc--;
488   }
489
490   fault_setup(fault_continue);
491
492   signal(SIGHUP,SIGNAL_CAST sig_hup);
493
494   bcast_ip = ipzero;
495   myip = ipzero;
496
497   while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
498     {
499       switch (opt)
500         {
501         case 's':
502           strcpy(servicesf,optarg);
503           break;
504         case 'C':
505           strcpy(ServerComment,optarg);
506           break;
507         case 'G':
508           if (got_bcast && got_nmask) {
509             add_domain_entry(bcast_ip,Netmask,optarg, True);
510           } else {
511             DEBUG(0, ("Warning: option -G %s added before broadcast and netmask.\n",
512                       optarg));
513             DEBUG(0, ("Assuming default values: bcast %s netmask %s\n",
514                       inet_ntoa(bcast_ip), inet_ntoa(Netmask))); /* (i hope) */
515           }
516           break;
517         case 'H':
518           strcpy(host_file,optarg);
519           break;
520         case 'I':
521           myip = *interpret_addr2(optarg);
522           got_myip = True;
523           break;
524         case 'B':
525           bcast_ip = *interpret_addr2(optarg);
526           got_bcast = True;
527           break;
528         case 'N':
529           Netmask = *interpret_addr2(optarg);
530           got_nmask = True;
531           break;
532         case 'n':
533           strcpy(myname,optarg);
534           break;
535         case 'l':
536           sprintf(debugf,"%s.nmb",optarg);
537           break;
538         case 'i':
539           strcpy(scope,optarg);
540           strupper(scope);
541           break;
542         case 'D':
543           is_daemon = True;
544           break;
545         case 'd':
546           DEBUGLEVEL = atoi(optarg);
547           break;
548         case 'p':
549           port = atoi(optarg);
550           break;
551         case 'h':
552           usage(argv[0]);
553           exit(0);
554           break;
555         default:
556           if (!is_a_socket(0)) {
557             usage(argv[0]);
558           }
559           break;
560         }
561     }
562
563   DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
564   DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
565
566   init_structs();
567
568   if (!reload_services(False))
569     return(-1); 
570
571   if (!is_daemon && !is_a_socket(0)) {
572     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
573     is_daemon = True;
574   }
575   
576   if (is_daemon) {
577     DEBUG(2,("%s becoming a daemon\n",timestring()));
578     become_daemon();
579   }
580
581   DEBUG(3,("Opening sockets %d\n", port));
582
583   if (!open_sockets(is_daemon,port)) return 1;
584
585   if (*host_file) {
586     load_hosts_file(host_file);
587     DEBUG(3,("Loaded hosts file\n"));
588   }
589
590   if (!*ServerComment)
591     strcpy(ServerComment,"Samba %v");
592   string_sub(ServerComment,"%v",VERSION);
593   string_sub(ServerComment,"%h",myhostname);
594
595   add_my_names();
596   add_my_domains();
597
598   DEBUG(3,("Checked names\n"));
599   
600   write_browse_list();
601
602   DEBUG(3,("Dumped names\n"));
603
604   process();
605   close_sockets();
606
607   if (dbf)
608     fclose(dbf);
609   return(0);
610 }