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