- added interface.c and removed all the references to myip, bcast_ip
[jra/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
31 extern int DEBUGLEVEL;
32
33 extern pstring debugf;
34 pstring servicesf = CONFIGFILE;
35
36 extern pstring scope;
37
38 int ClientNMB   = -1;
39 int ClientDGRAM = -1;
40
41 extern pstring myhostname;
42 static pstring host_file;
43 extern pstring myname;
44
45 /* are we running as a daemon ? */
46 static BOOL is_daemon = False;
47
48 /* machine comment for host announcements */
49 pstring ServerComment="";
50
51 /* what server type are we currently */
52
53 time_t StartupTime =0;
54
55 extern struct in_addr ipzero;
56
57
58 /****************************************************************************
59 catch a sighup
60 ****************************************************************************/
61 static int sig_hup(void)
62 {
63   BlockSignals(True);
64
65   DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
66   dump_names();
67   reload_services(True);
68
69   BlockSignals(False);
70 #ifndef DONT_REINSTALL_SIG
71   signal(SIGHUP,SIGNAL_CAST sig_hup);
72 #endif
73   return(0);
74 }
75
76 /****************************************************************************
77 catch a sigpipe
78 ****************************************************************************/
79 static int sig_pipe(void)
80 {
81   BlockSignals(True);
82
83   DEBUG(0,("Got SIGPIPE\n"));
84   if (!is_daemon)
85     exit(1);
86   BlockSignals(False);
87   return(0);
88 }
89
90 #if DUMP_CORE
91 /*******************************************************************
92 prepare to dump a core file - carefully!
93 ********************************************************************/
94 static BOOL dump_core(void)
95 {
96   char *p;
97   pstring dname;
98   strcpy(dname,debugf);
99   if ((p=strrchr(dname,'/'))) *p=0;
100   strcat(dname,"/corefiles");
101   mkdir(dname,0700);
102   sys_chown(dname,getuid(),getgid());
103   chmod(dname,0700);
104   if (chdir(dname)) return(False);
105   umask(~(0700));
106
107 #ifndef NO_GETRLIMIT
108 #ifdef RLIMIT_CORE
109   {
110     struct rlimit rlp;
111     getrlimit(RLIMIT_CORE, &rlp);
112     rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
113     setrlimit(RLIMIT_CORE, &rlp);
114     getrlimit(RLIMIT_CORE, &rlp);
115     DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
116   }
117 #endif
118 #endif
119
120
121   DEBUG(0,("Dumping core in %s\n",dname));
122   return(True);
123 }
124 #endif
125
126
127 /****************************************************************************
128 possibly continue after a fault
129 ****************************************************************************/
130 static void fault_continue(void)
131 {
132 #if DUMP_CORE
133   dump_core();
134 #endif
135 }
136
137 /*******************************************************************
138   expire old names from the namelist and server list
139   ******************************************************************/
140 static void expire_names_and_servers(void)
141 {
142   static time_t lastrun = 0;
143   time_t t = time(NULL);
144   
145   if (!lastrun) lastrun = t;
146   if (t < lastrun + 5) return;
147   lastrun = t;
148   
149   expire_names(t);
150   expire_servers(t);
151 }
152
153 /*****************************************************************************
154   reload the services file
155   **************************************************************************/
156 BOOL reload_services(BOOL test)
157 {
158   BOOL ret;
159   extern fstring remote_machine;
160
161   strcpy(remote_machine,"nmbd");
162
163   if (lp_loaded())
164     {
165       pstring fname;
166       strcpy(fname,lp_configfile());
167       if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
168         {
169           strcpy(servicesf,fname);
170           test = False;
171         }
172     }
173
174   if (test && !lp_file_list_changed())
175     return(True);
176
177   ret = lp_load(servicesf,True);
178
179   /* perhaps the config filename is now set */
180   if (!test) {
181     DEBUG(3,("services not loaded\n"));
182     reload_services(True);
183   }
184
185   load_interfaces();
186
187   return(ret);
188 }
189
190
191
192 /****************************************************************************
193 load a netbios hosts file
194 ****************************************************************************/
195 static void load_hosts_file(char *fname)
196 {
197   FILE *f = fopen(fname,"r");
198   pstring line;
199   if (!f) {
200     DEBUG(2,("Can't open lmhosts file %s\n",fname));
201     return;
202   }
203
204   while (!feof(f))
205     {
206       if (!fgets_slash(line,sizeof(pstring),f)) continue;
207
208       if (*line == '#') continue;
209
210       {
211         BOOL group=False;
212
213         pstring ip,name,mask,flags,extra;
214
215         char *ptr;
216         int count = 0;
217         struct in_addr ipaddr;
218         struct in_addr ipmask;
219         enum name_source source = LMHOSTS;
220
221         strcpy(ip,"");
222         strcpy(name,"");
223         strcpy(mask,"");
224         strcpy(flags,"");
225         strcpy(extra,"");
226         
227         ptr = line;
228
229         if (next_token(&ptr,ip   ,NULL)) ++count;
230         if (next_token(&ptr,name ,NULL)) ++count;
231         if (next_token(&ptr,mask ,NULL)) ++count;
232         if (next_token(&ptr,flags,NULL)) ++count;
233         if (next_token(&ptr,extra,NULL)) ++count;
234
235         if (count <= 0) continue;
236
237         if (count > 0 && count < 2) {
238           DEBUG(0,("Ill formed hosts line [%s]\n",line));           
239           continue;
240         }
241
242         /* work out if we need to shuffle the tokens along due to the
243            optional subnet mask argument */
244
245         if (strchr(mask, 'G') || strchr(mask, 'S') || strchr(mask, 'M')) {
246           strcpy(flags, mask );
247           /* default action for no subnet mask */
248           strcpy(mask, "");
249         }
250
251         DEBUG(4, ("lmhost entry: %s %s %s %s\n", ip, name, mask, flags));
252
253         if (strchr(flags,'G') || strchr(flags,'S'))
254           group = True;
255
256         if (strchr(flags,'M') && !group) {
257           source = SELF;
258           strcpy(myname,name);
259         }
260
261         ipaddr = *interpret_addr2(ip);
262         if (*mask)
263           ipmask = *interpret_addr2(mask);
264         else 
265           ipmask = *iface_nmask(ipaddr);
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,False);
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   initialise connect, service and file structs
352 ****************************************************************************/
353 static BOOL init_structs()
354 {
355   if (!get_myname(myhostname,NULL))
356     return(False);
357
358   if (! *myname) {
359     char *p;
360     strcpy(myname,myhostname);
361     p = strchr(myname,'.');
362     if (p) *p = 0;
363   }
364
365   return True;
366 }
367
368 /****************************************************************************
369 usage on the program
370 ****************************************************************************/
371 static void usage(char *pname)
372 {
373   DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
374
375   printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
376   printf("Version %s\n",VERSION);
377   printf("\t-D                    become a daemon\n");
378   printf("\t-p port               listen on the specified port\n");
379   printf("\t-d debuglevel         set the debuglevel\n");
380   printf("\t-l log basename.      Basename for log/debug files\n");
381   printf("\t-n netbiosname.       the netbios name to advertise for this host\n");
382   printf("\t-B broadcast address  the address to use for broadcasts\n");
383   printf("\t-N netmask           the netmask to use for subnet determination\n");
384   printf("\t-H hosts file        load a netbios hosts file\n");
385   printf("\t-G group name        add a group name to be part of\n");
386   printf("\t-I ip-address        override the IP address\n");
387   printf("\t-C comment           sets the machine comment that appears in browse lists\n");
388   printf("\n");
389 }
390
391
392 /****************************************************************************
393   main program
394   **************************************************************************/
395  int main(int argc,char *argv[])
396 {
397   int port = NMB_PORT;
398   int opt;
399   extern FILE *dbf;
400   extern char *optarg;
401   fstring group;
402
403   *group = 0;
404   *host_file = 0;
405
406   StartupTime = time(NULL);
407
408   TimeInit();
409
410   strcpy(debugf,NMBLOGFILE);
411
412   setup_logging(argv[0],False);
413
414   charset_initialise();
415
416 #ifdef LMHOSTSFILE
417   strcpy(host_file,LMHOSTSFILE);
418 #endif
419
420   /* this is for people who can't start the program correctly */
421   while (argc > 1 && (*argv[1] != '-')) {
422     argv++;
423     argc--;
424   }
425
426   fault_setup(fault_continue);
427
428   signal(SIGHUP,SIGNAL_CAST sig_hup);
429
430   while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
431     {
432       switch (opt)
433         {
434         case 's':
435           strcpy(servicesf,optarg);
436           break;
437         case 'C':
438           strcpy(ServerComment,optarg);
439           break;
440         case 'G':
441           strcpy(group,optarg);
442           break;
443         case 'H':
444           strcpy(host_file,optarg);
445           break;
446         case 'I':
447           iface_set_default(optarg,NULL,NULL);
448           break;
449         case 'B':
450           iface_set_default(NULL,optarg,NULL);
451           break;
452         case 'N':
453           iface_set_default(NULL,NULL,optarg);
454           break;
455         case 'n':
456           strcpy(myname,optarg);
457           break;
458         case 'l':
459           sprintf(debugf,"%s.nmb",optarg);
460           break;
461         case 'i':
462           strcpy(scope,optarg);
463           strupper(scope);
464           break;
465         case 'D':
466           is_daemon = True;
467           break;
468         case 'd':
469           DEBUGLEVEL = atoi(optarg);
470           break;
471         case 'p':
472           port = atoi(optarg);
473           break;
474         case 'h':
475           usage(argv[0]);
476           exit(0);
477           break;
478         default:
479           if (!is_a_socket(0)) {
480             usage(argv[0]);
481           }
482           break;
483         }
484     }
485
486   DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
487   DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
488
489   init_structs();
490
491   if (!reload_services(False))
492     return(-1); 
493
494   if (*group)
495     add_domain_entry(*iface_bcast(ipzero),*iface_nmask(ipzero),group, True);
496
497   if (!is_daemon && !is_a_socket(0)) {
498     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
499     is_daemon = True;
500   }
501   
502   if (is_daemon) {
503     DEBUG(2,("%s becoming a daemon\n",timestring()));
504     become_daemon();
505   }
506
507   DEBUG(3,("Opening sockets %d\n", port));
508
509   if (!open_sockets(is_daemon,port)) return 1;
510
511   if (*host_file) {
512     load_hosts_file(host_file);
513     DEBUG(3,("Loaded hosts file\n"));
514   }
515
516   if (!*ServerComment)
517     strcpy(ServerComment,"Samba %v");
518   string_sub(ServerComment,"%v",VERSION);
519   string_sub(ServerComment,"%h",myhostname);
520
521   add_my_names();
522   add_my_domains();
523
524   DEBUG(3,("Checked names\n"));
525   
526   write_browse_list();
527
528   DEBUG(3,("Dumped names\n"));
529
530   process();
531   close_sockets();
532
533   if (dbf)
534     fclose(dbf);
535   return(0);
536 }