bf298293178f38f98a1fd855fb79ec9f519e55de
[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-1997
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 extern fstring myworkgroup;
44
45 /* are we running as a daemon ? */
46 static BOOL is_daemon = False;
47
48 /* what server type are we currently */
49
50 time_t StartupTime =0;
51
52 extern struct in_addr ipzero;
53
54  /****************************************************************************
55   catch a sigterm
56   ****************************************************************************/
57 static int sig_term()
58 {
59   BlockSignals(True,SIGTERM);
60   
61   DEBUG(0,("Got SIGTERM: going down...\n"));
62   
63   /* write out wins.dat file if samba is a WINS server */
64   dump_names();
65   
66   /* remove all samba names, with wins server if necessary. */
67   remove_my_names();
68   
69   /* announce all server entries as 0 time-to-live, 0 type */
70   /* XXXX don't care if we never receive a response back... yet */
71   announce_my_servers_removed();
72
73   /* XXXX other things: if we are a master browser, force an election? */
74   
75   exit(0);
76   /* Keep compiler happy.. */
77   return 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(time_t t)
166 {
167   static time_t lastrun = 0;
168   
169   if (!lastrun) lastrun = t;
170   if (t < lastrun + 5) return;
171   lastrun = t;
172   
173   expire_names(t);
174   expire_servers(t);
175 }
176
177 /*****************************************************************************
178   reload the services file
179   **************************************************************************/
180 BOOL reload_services(BOOL test)
181 {
182   BOOL ret;
183   extern fstring remote_machine;
184
185   strcpy(remote_machine,"nmbd");
186
187   if (lp_loaded())
188     {
189       pstring fname;
190       strcpy(fname,lp_configfile());
191       if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
192         {
193           strcpy(servicesf,fname);
194           test = False;
195         }
196     }
197
198   if (test && !lp_file_list_changed())
199     return(True);
200
201   ret = lp_load(servicesf,True);
202
203   /* perhaps the config filename is now set */
204   if (!test) {
205     DEBUG(3,("services not loaded\n"));
206     reload_services(True);
207   }
208
209   /* Do a sanity check for a misconfigured nmbd */
210   if(lp_wins_support() && *lp_wins_server()) {
211     DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
212 cannot be set in the smb.conf file. nmbd aborting.\n"));
213     exit(10);
214   }
215
216   return(ret);
217 }
218
219
220
221 /****************************************************************************
222 load a netbios hosts file
223 ****************************************************************************/
224 static void load_hosts_file(char *fname)
225 {
226   FILE *f = fopen(fname,"r");
227   pstring line;
228   if (!f) {
229     DEBUG(2,("Can't open lmhosts file %s\n",fname));
230     return;
231   }
232
233   while (!feof(f))
234     {
235       pstring ip,name,flags,extra;
236       struct subnet_record *d;
237       char *ptr;
238       int count = 0;
239       struct in_addr ipaddr;
240       enum name_source source = LMHOSTS;
241
242       if (!fgets_slash(line,sizeof(pstring),f)) continue;
243
244       if (*line == '#') continue;
245
246       strcpy(ip,"");
247       strcpy(name,"");
248       strcpy(flags,"");
249       
250       ptr = line;
251       
252       if (next_token(&ptr,ip   ,NULL)) ++count;
253       if (next_token(&ptr,name ,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       if (count >= 4) {
265         DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
266         continue;
267       }
268       
269       DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
270       
271       if (strchr(flags,'G') || strchr(flags,'S')) {
272         DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
273         continue;
274       }
275       
276       if (strchr(flags,'M')) {
277         source = SELF;
278         strcpy(myname,name);
279       }
280       
281       ipaddr = *interpret_addr2(ip);
282       d = find_subnet_all(ipaddr);
283       if (d) {
284         add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True);
285         add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
286       } 
287     }
288   
289   fclose(f);
290 }
291
292
293 /****************************************************************************
294   The main select loop.
295   ***************************************************************************/
296 static void process(void)
297 {
298   BOOL run_election;
299
300   while (True)
301     {
302       time_t t = time(NULL);
303       run_election = check_elections();
304       listen_for_packets(run_election);
305
306       run_packet_queue();
307       run_elections(t);
308
309       announce_host(t);
310       announce_master(t);
311       announce_remote(t);
312
313       query_refresh_names(t);
314
315       expire_names_and_servers(t);
316       expire_netbios_response_entries(t);
317       refresh_my_names(t);
318
319       write_browse_list(t);
320       do_browser_lists(t);
321       check_master_browser(t);
322       add_domain_names(t);
323     }
324 }
325
326
327 /****************************************************************************
328   open the socket communication
329 ****************************************************************************/
330 static BOOL open_sockets(BOOL isdaemon, int port)
331 {
332   struct hostent *hp;
333  
334   /* get host info */
335   if ((hp = Get_Hostbyname(myhostname)) == 0) {
336     DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
337     return False;
338   }   
339
340   if (isdaemon)
341     ClientNMB = open_socket_in(SOCK_DGRAM, port,0,interpret_addr(lp_socket_address()));
342   else
343     ClientNMB = 0;
344   
345   ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,interpret_addr(lp_socket_address()));
346
347   if (ClientNMB == -1)
348     return(False);
349
350   signal(SIGPIPE, SIGNAL_CAST sig_pipe);
351
352   set_socket_options(ClientNMB,"SO_BROADCAST");
353   set_socket_options(ClientDGRAM,"SO_BROADCAST");
354
355   DEBUG(3,("Sockets opened.\n"));
356   return True;
357 }
358
359
360 /****************************************************************************
361   initialise connect, service and file structs
362 ****************************************************************************/
363 static BOOL init_structs()
364 {
365   extern fstring local_machine;
366   char *p;
367
368   if (! *myname) {
369     strcpy(myname,myhostname);
370     p = strchr(myname,'.');
371     if (p) *p = 0;
372   }
373   strupper(myname);
374
375   strcpy(local_machine,myname);
376   trim_string(local_machine," "," ");
377   p = strchr(local_machine,' ');
378   if (p) *p = 0;
379   strlower(local_machine);
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] [-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-H hosts file        load a netbios hosts file\n");
399   printf("\n");
400 }
401
402
403 /****************************************************************************
404   main program
405   **************************************************************************/
406  int main(int argc,char *argv[])
407 {
408   int port = NMB_PORT;
409   int opt;
410   extern FILE *dbf;
411   extern char *optarg;
412   char pidFile[100] = { 0 };
413
414   *host_file = 0;
415
416   StartupTime = time(NULL);
417
418   TimeInit();
419
420   strcpy(debugf,NMBLOGFILE);
421
422   setup_logging(argv[0],False);
423
424   charset_initialise(-1);
425
426 #ifdef LMHOSTSFILE
427   strcpy(host_file,LMHOSTSFILE);
428 #endif
429
430   /* this is for people who can't start the program correctly */
431   while (argc > 1 && (*argv[1] != '-')) {
432     argv++;
433     argc--;
434   }
435
436   fault_setup(fault_continue);
437
438   signal(SIGHUP ,SIGNAL_CAST sig_hup);
439   signal(SIGTERM,SIGNAL_CAST sig_term);
440
441   while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
442     {
443       switch (opt)
444         {
445         case 'f':
446           strncpy(pidFile, optarg, sizeof(pidFile));
447           break;
448         case 's':
449           strcpy(servicesf,optarg);
450           break;          
451         case 'N':
452         case 'B':
453         case 'I':
454         case 'C':
455         case 'G':
456           DEBUG(0,("Obsolete option '%c' used\n",opt));
457           break;
458         case 'H':
459           strcpy(host_file,optarg);
460           break;
461         case 'n':
462           strcpy(myname,optarg);
463           strupper(myname);
464           break;
465         case 'l':
466           sprintf(debugf,"%s.nmb",optarg);
467           break;
468         case 'i':
469           strcpy(scope,optarg);
470           strupper(scope);
471           break;
472         case 'D':
473           is_daemon = True;
474           break;
475         case 'd':
476           DEBUGLEVEL = atoi(optarg);
477           break;
478         case 'p':
479           port = atoi(optarg);
480           break;
481         case 'h':
482           usage(argv[0]);
483           exit(0);
484           break;
485         default:
486           if (!is_a_socket(0)) {
487             usage(argv[0]);
488           }
489           break;
490         }
491     }
492
493   DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
494   DEBUG(1,("Copyright Andrew Tridgell 1994-1997\n"));
495
496   get_myname(myhostname,NULL);
497
498   if (!reload_services(False))
499     return(-1); 
500
501   charset_initialise(lp_client_code_page());
502
503   init_structs();
504
505   reload_services(True);
506
507   strcpy(myworkgroup, lp_workgroup());
508
509   if (strequal(myworkgroup,"*")) {
510     DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
511     exit(1);
512   }
513
514   set_samba_nb_type();
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   if (*pidFile)
527     {
528       int     fd;
529       char    buf[20];
530
531       if ((fd = open(pidFile,
532         O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
533         {
534           DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
535           exit(1);
536         }
537       if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
538         {
539           DEBUG(0,("ERROR: nmbd is already running\n"));
540           exit(1);
541         }
542       sprintf(buf, "%u\n", (unsigned int) getpid());
543       if (write(fd, buf, strlen(buf)) < 0)
544         {
545           DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
546           exit(1);
547         }
548       /* Leave pid file open & locked for the duration... */
549     }
550
551
552   DEBUG(3,("Opening sockets %d\n", port));
553
554   if (!open_sockets(is_daemon,port)) return 1;
555
556   load_interfaces();
557   add_my_subnets(myworkgroup);
558
559   add_my_names();
560
561   DEBUG(3,("Checked names\n"));
562   
563   load_netbios_names();
564
565   DEBUG(3,("Loaded names\n"));
566
567   if (*host_file) {
568     load_hosts_file(host_file);
569     DEBUG(3,("Loaded hosts file\n"));
570   }
571
572   write_browse_list(time(NULL));
573
574   DEBUG(3,("Dumped names\n"));
575
576   /* We can only take sigterm signals in the select. */
577   BlockSignals(True,SIGTERM);
578   process();
579   close_sockets();
580
581   if (dbf)
582     fclose(dbf);
583   return(0);
584 }