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