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