dir.c: Fixed double slash issue.
[samba.git] / source / 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 }
77
78
79 /****************************************************************************
80 catch a sighup
81 ****************************************************************************/
82 static int sig_hup(void)
83 {
84   BlockSignals(True,SIGHUP);
85
86   DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
87   dump_names();
88   reload_services(True);
89
90   set_samba_nb_type();
91
92   BlockSignals(False,SIGHUP);
93 #ifndef DONT_REINSTALL_SIG
94   signal(SIGHUP,SIGNAL_CAST sig_hup);
95 #endif
96   return(0);
97 }
98
99 /****************************************************************************
100 catch a sigpipe
101 ****************************************************************************/
102 static int sig_pipe(void)
103 {
104   BlockSignals(True,SIGPIPE);
105
106   DEBUG(0,("Got SIGPIPE\n"));
107   if (!is_daemon)
108     exit(1);
109   BlockSignals(False,SIGPIPE);
110   return(0);
111 }
112
113 #if DUMP_CORE
114 /*******************************************************************
115 prepare to dump a core file - carefully!
116 ********************************************************************/
117 static BOOL dump_core(void)
118 {
119   char *p;
120   pstring dname;
121   strcpy(dname,debugf);
122   if ((p=strrchr(dname,'/'))) *p=0;
123   strcat(dname,"/corefiles");
124   mkdir(dname,0700);
125   sys_chown(dname,getuid(),getgid());
126   chmod(dname,0700);
127   if (chdir(dname)) return(False);
128   umask(~(0700));
129
130 #ifndef NO_GETRLIMIT
131 #ifdef RLIMIT_CORE
132   {
133     struct rlimit rlp;
134     getrlimit(RLIMIT_CORE, &rlp);
135     rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
136     setrlimit(RLIMIT_CORE, &rlp);
137     getrlimit(RLIMIT_CORE, &rlp);
138     DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
139   }
140 #endif
141 #endif
142
143
144   DEBUG(0,("Dumping core in %s\n",dname));
145   return(True);
146 }
147 #endif
148
149
150 /****************************************************************************
151 possibly continue after a fault
152 ****************************************************************************/
153 static void fault_continue(void)
154 {
155 #if DUMP_CORE
156   dump_core();
157 #endif
158 }
159
160 /*******************************************************************
161   expire old names from the namelist and server list
162   ******************************************************************/
163 static void expire_names_and_servers(time_t t)
164 {
165   static time_t lastrun = 0;
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   /* Do a sanity check for a misconfigured nmbd */
208   if(lp_wins_support() && *lp_wins_server()) {
209     DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
210 cannot be set in the smb.conf file. nmbd aborting.\n"));
211     exit(10);
212   }
213
214   return(ret);
215 }
216
217
218
219 /****************************************************************************
220 load a netbios hosts file
221 ****************************************************************************/
222 static void load_hosts_file(char *fname)
223 {
224   FILE *f = fopen(fname,"r");
225   pstring line;
226   if (!f) {
227     DEBUG(2,("Can't open lmhosts file %s\n",fname));
228     return;
229   }
230
231   while (!feof(f))
232     {
233       pstring ip,name,flags,extra;
234       struct subnet_record *d;
235       char *ptr;
236       int count = 0;
237       struct in_addr ipaddr;
238       enum name_source source = LMHOSTS;
239
240       if (!fgets_slash(line,sizeof(pstring),f)) continue;
241
242       if (*line == '#') continue;
243
244       strcpy(ip,"");
245       strcpy(name,"");
246       strcpy(flags,"");
247       
248       ptr = line;
249       
250       if (next_token(&ptr,ip   ,NULL)) ++count;
251       if (next_token(&ptr,name ,NULL)) ++count;
252       if (next_token(&ptr,flags,NULL)) ++count;
253       if (next_token(&ptr,extra,NULL)) ++count;
254       
255       if (count <= 0) continue;
256       
257       if (count > 0 && count < 2) {
258         DEBUG(0,("Ill formed hosts line [%s]\n",line));     
259         continue;
260       }
261       
262       if (count >= 4) {
263         DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
264         continue;
265       }
266       
267       DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
268       
269       if (strchr(flags,'G') || strchr(flags,'S')) {
270         DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
271         continue;
272       }
273       
274       if (strchr(flags,'M')) {
275         source = SELF;
276         strcpy(myname,name);
277       }
278       
279       ipaddr = *interpret_addr2(ip);
280       d = find_subnet_all(ipaddr);
281       if (d) {
282         add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True);
283         add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
284       } 
285     }
286   
287   fclose(f);
288 }
289
290
291 /****************************************************************************
292   The main select loop.
293   ***************************************************************************/
294 static void process(void)
295 {
296   BOOL run_election;
297
298   while (True)
299     {
300       time_t t = time(NULL);
301       run_election = check_elections();
302       listen_for_packets(run_election);
303
304       run_packet_queue();
305       run_elections(t);
306
307       announce_host(t);
308       announce_master(t);
309       announce_remote(t);
310
311       query_refresh_names(t);
312
313       expire_names_and_servers(t);
314       expire_netbios_response_entries(t);
315       refresh_my_names(t);
316
317       write_browse_list(t);
318       do_browser_lists(t);
319       check_master_browser(t);
320       add_domain_names(t);
321     }
322 }
323
324
325 /****************************************************************************
326   open the socket communication
327 ****************************************************************************/
328 static BOOL open_sockets(BOOL isdaemon, int port)
329 {
330   struct hostent *hp;
331  
332   /* get host info */
333   if ((hp = Get_Hostbyname(myhostname)) == 0) {
334     DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
335     return False;
336   }   
337
338   if (isdaemon)
339     ClientNMB = open_socket_in(SOCK_DGRAM, port,0,interpret_addr(lp_socket_address()));
340   else
341     ClientNMB = 0;
342   
343   ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,interpret_addr(lp_socket_address()));
344
345   if (ClientNMB == -1)
346     return(False);
347
348   signal(SIGPIPE, SIGNAL_CAST sig_pipe);
349
350   set_socket_options(ClientNMB,"SO_BROADCAST");
351   set_socket_options(ClientDGRAM,"SO_BROADCAST");
352
353   DEBUG(3,("Sockets opened.\n"));
354   return True;
355 }
356
357
358 /****************************************************************************
359   initialise connect, service and file structs
360 ****************************************************************************/
361 static BOOL init_structs()
362 {
363   extern fstring local_machine;
364   char *p;
365
366   if (! *myname) {
367     strcpy(myname,myhostname);
368     p = strchr(myname,'.');
369     if (p) *p = 0;
370   }
371   strupper(myname);
372
373   strcpy(local_machine,myname);
374   trim_string(local_machine," "," ");
375   p = strchr(local_machine,' ');
376   if (p) *p = 0;
377   strlower(local_machine);
378
379   return True;
380 }
381
382 /****************************************************************************
383 usage on the program
384 ****************************************************************************/
385 static void usage(char *pname)
386 {
387   DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
388
389   printf("Usage: %s [-n name] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
390   printf("Version %s\n",VERSION);
391   printf("\t-D                    become a daemon\n");
392   printf("\t-p port               listen on the specified port\n");
393   printf("\t-d debuglevel         set the debuglevel\n");
394   printf("\t-l log basename.      Basename for log/debug files\n");
395   printf("\t-n netbiosname.       the netbios name to advertise for this host\n");
396   printf("\t-H hosts file        load a netbios hosts file\n");
397   printf("\n");
398 }
399
400
401 /****************************************************************************
402   main program
403   **************************************************************************/
404  int main(int argc,char *argv[])
405 {
406   int port = NMB_PORT;
407   int opt;
408   extern FILE *dbf;
409   extern char *optarg;
410   char pidFile[100] = { 0 };
411
412   *host_file = 0;
413
414   StartupTime = time(NULL);
415
416   TimeInit();
417
418   strcpy(debugf,NMBLOGFILE);
419
420   setup_logging(argv[0],False);
421
422   charset_initialise();
423
424 #ifdef LMHOSTSFILE
425   strcpy(host_file,LMHOSTSFILE);
426 #endif
427
428   /* this is for people who can't start the program correctly */
429   while (argc > 1 && (*argv[1] != '-')) {
430     argv++;
431     argc--;
432   }
433
434   fault_setup(fault_continue);
435
436   signal(SIGHUP ,SIGNAL_CAST sig_hup);
437   signal(SIGTERM,SIGNAL_CAST sig_term);
438
439   while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
440     {
441       switch (opt)
442         {
443         case 'f':
444           strncpy(pidFile, optarg, sizeof(pidFile));
445           break;
446         case 's':
447           strcpy(servicesf,optarg);
448           break;          
449         case 'N':
450         case 'B':
451         case 'I':
452         case 'C':
453         case 'G':
454           DEBUG(0,("Obsolete option '%c' used\n",opt));
455           break;
456         case 'H':
457           strcpy(host_file,optarg);
458           break;
459         case 'n':
460           strcpy(myname,optarg);
461           strupper(myname);
462           break;
463         case 'l':
464           sprintf(debugf,"%s.nmb",optarg);
465           break;
466         case 'i':
467           strcpy(scope,optarg);
468           strupper(scope);
469           break;
470         case 'D':
471           is_daemon = True;
472           break;
473         case 'd':
474           DEBUGLEVEL = atoi(optarg);
475           break;
476         case 'p':
477           port = atoi(optarg);
478           break;
479         case 'h':
480           usage(argv[0]);
481           exit(0);
482           break;
483         default:
484           if (!is_a_socket(0)) {
485             usage(argv[0]);
486           }
487           break;
488         }
489     }
490
491   DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
492   DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
493
494   get_myname(myhostname,NULL);
495
496   if (!reload_services(False))
497     return(-1); 
498
499   init_structs();
500
501   reload_services(True);
502
503   strcpy(myworkgroup, lp_workgroup());
504
505   set_samba_nb_type();
506
507   if (!is_daemon && !is_a_socket(0)) {
508     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
509     is_daemon = True;
510   }
511   
512   if (is_daemon) {
513     DEBUG(2,("%s becoming a daemon\n",timestring()));
514     become_daemon();
515   }
516
517   if (*pidFile)
518     {
519       int     fd;
520       char    buf[20];
521
522       if ((fd = open(pidFile,
523         O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
524         {
525           DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
526           exit(1);
527         }
528       if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
529         {
530           DEBUG(0,("ERROR: nmbd is already running\n"));
531           exit(1);
532         }
533       sprintf(buf, "%u\n", (unsigned int) getpid());
534       if (write(fd, buf, strlen(buf)) < 0)
535         {
536           DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
537           exit(1);
538         }
539       /* Leave pid file open & locked for the duration... */
540     }
541
542
543   DEBUG(3,("Opening sockets %d\n", port));
544
545   if (!open_sockets(is_daemon,port)) return 1;
546
547   if (*host_file) {
548     load_hosts_file(host_file);
549     DEBUG(3,("Loaded hosts file\n"));
550   }
551
552   load_interfaces();
553   add_my_subnets(myworkgroup);
554
555   add_my_names();
556
557   if (strequal(myworkgroup,"*")) {
558     DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
559     exit(1);
560   }
561
562   DEBUG(3,("Checked names\n"));
563   
564   load_netbios_names();
565
566   DEBUG(3,("Loaded names\n"));
567
568   write_browse_list(time(NULL));
569
570   DEBUG(3,("Dumped names\n"));
571
572   process();
573   close_sockets();
574
575   if (dbf)
576     fclose(dbf);
577   return(0);
578 }