Adding Andrews buffer overflow fixes into the main branch.
[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 extern char **my_netbios_names;
45
46 /* are we running as a daemon ? */
47 static BOOL is_daemon = False;
48
49 /* what server type are we currently */
50
51 time_t StartupTime =0;
52
53 extern struct in_addr ipzero;
54
55  /****************************************************************************
56   catch a sigterm
57   ****************************************************************************/
58 static int sig_term()
59 {
60   BlockSignals(True,SIGTERM);
61   
62   DEBUG(0,("Got SIGTERM: going down...\n"));
63   
64   /* write out wins.dat file if samba is a WINS server */
65   dump_names();
66   
67   /* remove all samba names, with wins server if necessary. */
68   remove_my_names();
69   
70   /* announce all server entries as 0 time-to-live, 0 type */
71   /* XXXX don't care if we never receive a response back... yet */
72   announce_my_servers_removed();
73
74   /* XXXX other things: if we are a master browser, force an election? */
75   
76   exit(0);
77   /* Keep compiler happy.. */
78   return 0;
79 }
80
81
82 /****************************************************************************
83 catch a sighup
84 ****************************************************************************/
85 static int sig_hup(void)
86 {
87   BlockSignals(True,SIGHUP);
88
89   DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
90   dump_names();
91   reload_services(True);
92
93   set_samba_nb_type();
94
95   BlockSignals(False,SIGHUP);
96 #ifndef DONT_REINSTALL_SIG
97   signal(SIGHUP,SIGNAL_CAST sig_hup);
98 #endif
99   return(0);
100 }
101
102 /****************************************************************************
103 catch a sigpipe
104 ****************************************************************************/
105 static int sig_pipe(void)
106 {
107   BlockSignals(True,SIGPIPE);
108
109   DEBUG(0,("Got SIGPIPE\n"));
110   if (!is_daemon)
111     exit(1);
112   BlockSignals(False,SIGPIPE);
113   return(0);
114 }
115
116 #if DUMP_CORE
117 /*******************************************************************
118 prepare to dump a core file - carefully!
119 ********************************************************************/
120 static BOOL dump_core(void)
121 {
122   char *p;
123   pstring dname;
124   pstrcpy(dname,debugf);
125   if ((p=strrchr(dname,'/'))) *p=0;
126   strcat(dname,"/corefiles");
127   mkdir(dname,0700);
128   sys_chown(dname,getuid(),getgid());
129   chmod(dname,0700);
130   if (chdir(dname)) return(False);
131   umask(~(0700));
132
133 #ifndef NO_GETRLIMIT
134 #ifdef RLIMIT_CORE
135   {
136     struct rlimit rlp;
137     getrlimit(RLIMIT_CORE, &rlp);
138     rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
139     setrlimit(RLIMIT_CORE, &rlp);
140     getrlimit(RLIMIT_CORE, &rlp);
141     DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
142   }
143 #endif
144 #endif
145
146
147   DEBUG(0,("Dumping core in %s\n",dname));
148   return(True);
149 }
150 #endif
151
152
153 /****************************************************************************
154 possibly continue after a fault
155 ****************************************************************************/
156 static void fault_continue(void)
157 {
158 #if DUMP_CORE
159   dump_core();
160 #endif
161 }
162
163 /*******************************************************************
164   expire old names from the namelist and server list
165   ******************************************************************/
166 static void expire_names_and_servers(time_t t)
167 {
168   static time_t lastrun = 0;
169   
170   if (!lastrun) lastrun = t;
171   if (t < lastrun + 5) return;
172   lastrun = t;
173   
174   expire_names(t);
175   expire_servers(t);
176 }
177
178 /*****************************************************************************
179   reload the services file
180   **************************************************************************/
181 BOOL reload_services(BOOL test)
182 {
183   BOOL ret;
184   extern fstring remote_machine;
185
186   strcpy(remote_machine,"nmbd");
187
188   if (lp_loaded())
189     {
190       pstring fname;
191       pstrcpy(fname,lp_configfile());
192       if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
193         {
194           pstrcpy(servicesf,fname);
195           test = False;
196         }
197     }
198
199   if (test && !lp_file_list_changed())
200     return(True);
201
202   ret = lp_load(servicesf,True);
203
204   /* perhaps the config filename is now set */
205   if (!test) {
206     DEBUG(3,("services not loaded\n"));
207     reload_services(True);
208   }
209
210   /* Do a sanity check for a misconfigured nmbd */
211   if(lp_wins_support() && *lp_wins_server()) {
212     DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
213 cannot be set in the smb.conf file. nmbd aborting.\n"));
214     exit(10);
215   }
216
217   return(ret);
218 }
219
220
221
222 /****************************************************************************
223 load a netbios hosts file
224 ****************************************************************************/
225 static void load_hosts_file(char *fname)
226 {
227   FILE *f = fopen(fname,"r");
228   pstring line;
229   if (!f) {
230     DEBUG(2,("Can't open lmhosts file %s\n",fname));
231     return;
232   }
233
234   while (!feof(f))
235     {
236       pstring ip,name,flags,extra;
237       struct subnet_record *d;
238       char *ptr;
239       int count = 0;
240       struct in_addr ipaddr;
241       enum name_source source = LMHOSTS;
242
243       if (!fgets_slash(line,sizeof(pstring),f)) continue;
244
245       if (*line == '#') continue;
246
247       strcpy(ip,"");
248       strcpy(name,"");
249       strcpy(flags,"");
250       
251       ptr = line;
252       
253       if (next_token(&ptr,ip   ,NULL)) ++count;
254       if (next_token(&ptr,name ,NULL)) ++count;
255       if (next_token(&ptr,flags,NULL)) ++count;
256       if (next_token(&ptr,extra,NULL)) ++count;
257       
258       if (count <= 0) continue;
259       
260       if (count > 0 && count < 2) {
261         DEBUG(0,("Ill formed hosts line [%s]\n",line));     
262         continue;
263       }
264       
265       if (count >= 4) {
266         DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
267         continue;
268       }
269       
270       DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
271       
272       if (strchr(flags,'G') || strchr(flags,'S')) {
273         DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
274         continue;
275       }
276       
277       if (strchr(flags,'M')) {
278         source = SELF;
279         pstrcpy(myname,name);
280       }
281       
282       ipaddr = *interpret_addr2(ip);
283       d = find_subnet_all(ipaddr);
284       if (d) {
285         add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True);
286         add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
287       } 
288     }
289   
290   fclose(f);
291 }
292
293
294 /****************************************************************************
295   The main select loop.
296   ***************************************************************************/
297 static void process(void)
298 {
299   BOOL run_election;
300
301   while (True)
302     {
303       time_t t = time(NULL);
304       run_election = check_elections();
305       listen_for_packets(run_election);
306
307       run_packet_queue();
308       run_elections(t);
309
310       announce_host(t);
311       announce_master(t);
312       announce_remote(t);
313
314       query_refresh_names(t);
315
316       expire_names_and_servers(t);
317       expire_netbios_response_entries(t);
318       refresh_my_names(t);
319
320       write_browse_list(t);
321       do_browser_lists(t);
322       check_master_browser(t);
323       add_domain_names(t);
324     }
325 }
326
327
328 /****************************************************************************
329   open the socket communication
330 ****************************************************************************/
331 static BOOL open_sockets(BOOL isdaemon, int port)
332 {
333   struct hostent *hp;
334  
335   /* get host info */
336   if ((hp = Get_Hostbyname(myhostname)) == 0) {
337     DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
338     return False;
339   }   
340
341   if (isdaemon)
342     ClientNMB = open_socket_in(SOCK_DGRAM, port,0,interpret_addr(lp_socket_address()));
343   else
344     ClientNMB = 0;
345   
346   ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,interpret_addr(lp_socket_address()));
347
348   if (ClientNMB == -1)
349     return(False);
350
351   signal(SIGPIPE, SIGNAL_CAST sig_pipe);
352
353   set_socket_options(ClientNMB,"SO_BROADCAST");
354   set_socket_options(ClientDGRAM,"SO_BROADCAST");
355
356   DEBUG(3,("Sockets opened.\n"));
357   return True;
358 }
359
360
361 /****************************************************************************
362   initialise connect, service and file structs
363 ****************************************************************************/
364 static BOOL init_structs()
365 {
366   extern fstring local_machine;
367   char *p, *ptr;
368   int namecount;
369   int n;
370   int nodup;
371   pstring nbname;
372
373   if (! *myname) {
374     fstrcpy(myname,myhostname);
375     p = strchr(myname,'.');
376     if (p) *p = 0;
377   }
378   strupper(myname);
379
380   /* Add any NETBIOS name aliases. Ensure that the first entry
381      is equal to myname. */
382   /* Work out the max number of netbios aliases that we have */
383   ptr=lp_netbios_aliases();
384   for (namecount=0; next_token(&ptr,nbname,NULL); namecount++)
385     ;
386   if (*myname)
387       namecount++;
388
389   /* Allocate space for the netbios aliases */
390   if((my_netbios_names=(char **)malloc(sizeof(char *)*(namecount+1))) == NULL)
391   {
392      DEBUG(0,("init_structs: malloc fail.\n"));
393      return False;
394   }
395  
396   /* Use the myname string first */
397   namecount=0;
398   if (*myname)
399     my_netbios_names[namecount++] = myname;
400   
401   ptr=lp_netbios_aliases();
402   while (next_token(&ptr,nbname,NULL)) {
403     strupper(nbname);
404     /* Look for duplicates */
405     nodup=1;
406     for(n=0; n<namecount; n++) {
407       if (strcmp(nbname, my_netbios_names[n])==0)
408         nodup=0;
409     }
410     if (nodup)
411       my_netbios_names[namecount++]=strdup(nbname);
412   }
413   
414   /* Check the strdups succeeded. */
415   for(n = 0; n < namecount; n++)
416     if(my_netbios_names[n]==NULL)
417     {
418       DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
419       return False;
420     }
421   
422   /* Terminate name list */
423   my_netbios_names[namecount++]=NULL;
424   
425   fstrcpy(local_machine,myname);
426   trim_string(local_machine," "," ");
427   p = strchr(local_machine,' ');
428   if (p) 
429     *p = 0;
430   strlower(local_machine);
431
432   DEBUG(5, ("Netbios name list:-\n"));
433   for (n=0; my_netbios_names[n]; n++)
434     DEBUG(5, ("my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n]));
435
436   return True;
437 }
438
439 /****************************************************************************
440 usage on the program
441 ****************************************************************************/
442 static void usage(char *pname)
443 {
444   DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
445
446   printf("Usage: %s [-n name] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
447   printf("Version %s\n",VERSION);
448   printf("\t-D                    become a daemon\n");
449   printf("\t-p port               listen on the specified port\n");
450   printf("\t-d debuglevel         set the debuglevel\n");
451   printf("\t-l log basename.      Basename for log/debug files\n");
452   printf("\t-n netbiosname.       the netbios name to advertise for this host\n");
453   printf("\t-H hosts file        load a netbios hosts file\n");
454   printf("\n");
455 }
456
457
458 /****************************************************************************
459   main program
460   **************************************************************************/
461  int main(int argc,char *argv[])
462 {
463   int port = NMB_PORT;
464   int opt;
465   extern FILE *dbf;
466   extern char *optarg;
467   char pidFile[100] = { 0 };
468
469   *host_file = 0;
470
471   StartupTime = time(NULL);
472
473   TimeInit();
474
475   strcpy(debugf,NMBLOGFILE);
476
477   setup_logging(argv[0],False);
478
479   charset_initialise();
480
481 #ifdef LMHOSTSFILE
482   strcpy(host_file,LMHOSTSFILE);
483 #endif
484
485   /* this is for people who can't start the program correctly */
486   while (argc > 1 && (*argv[1] != '-')) {
487     argv++;
488     argc--;
489   }
490
491   fault_setup(fault_continue);
492
493   signal(SIGHUP ,SIGNAL_CAST sig_hup);
494   signal(SIGTERM,SIGNAL_CAST sig_term);
495
496   while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
497     {
498       switch (opt)
499         {
500         case 'f':
501           strncpy(pidFile, optarg, sizeof(pidFile));
502           break;
503         case 's':
504           pstrcpy(servicesf,optarg);
505           break;          
506         case 'N':
507         case 'B':
508         case 'I':
509         case 'C':
510         case 'G':
511           DEBUG(0,("Obsolete option '%c' used\n",opt));
512           break;
513         case 'H':
514           pstrcpy(host_file,optarg);
515           break;
516         case 'n':
517           pstrcpy(myname,optarg);
518           strupper(myname);
519           break;
520         case 'l':
521           sprintf(debugf,"%s.nmb",optarg);
522           break;
523         case 'i':
524           pstrcpy(scope,optarg);
525           strupper(scope);
526           break;
527         case 'D':
528           is_daemon = True;
529           break;
530         case 'd':
531           DEBUGLEVEL = atoi(optarg);
532           break;
533         case 'p':
534           port = atoi(optarg);
535           break;
536         case 'h':
537           usage(argv[0]);
538           exit(0);
539           break;
540         default:
541           if (!is_a_socket(0)) {
542             usage(argv[0]);
543           }
544           break;
545         }
546     }
547
548   DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
549   DEBUG(1,("Copyright Andrew Tridgell 1994-1997\n"));
550
551   if(!get_myname(myhostname,NULL))
552   {
553     DEBUG(0,("Unable to get my hostname - exiting.\n"));
554     return -1;
555   }
556
557   if (!reload_services(False))
558     return(-1); 
559
560   codepage_initialise(lp_client_code_page());
561
562   if(!init_structs())
563     return -1;
564
565   reload_services(True);
566
567   pstrcpy(myworkgroup, lp_workgroup());
568
569   if (strequal(myworkgroup,"*")) {
570     DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
571     exit(1);
572   }
573
574   set_samba_nb_type();
575
576   if (!is_daemon && !is_a_socket(0)) {
577     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
578     is_daemon = True;
579   }
580   
581   if (is_daemon) {
582     DEBUG(2,("%s becoming a daemon\n",timestring()));
583     become_daemon();
584   }
585
586   if (*pidFile)
587     {
588       int     fd;
589       char    buf[20];
590
591       if ((fd = open(pidFile,
592 #ifdef O_NONBLOCK
593         O_NONBLOCK | 
594 #endif
595         O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
596         {
597           DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
598           exit(1);
599         }
600       if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
601         {
602           DEBUG(0,("ERROR: nmbd is already running\n"));
603           exit(1);
604         }
605       sprintf(buf, "%u\n", (unsigned int) getpid());
606       if (write(fd, buf, strlen(buf)) < 0)
607         {
608           DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
609           exit(1);
610         }
611       /* Leave pid file open & locked for the duration... */
612     }
613
614
615   DEBUG(3,("Opening sockets %d\n", port));
616
617   if (!open_sockets(is_daemon,port)) return 1;
618
619   load_interfaces();
620   add_my_subnets(myworkgroup);
621
622   add_my_names();
623
624   DEBUG(3,("Checked names\n"));
625   
626   load_netbios_names();
627
628   DEBUG(3,("Loaded names\n"));
629
630   if (*host_file) {
631     load_hosts_file(host_file);
632     DEBUG(3,("Loaded hosts file\n"));
633   }
634
635   write_browse_list(time(NULL));
636
637   DEBUG(3,("Dumped names\n"));
638
639   /* We can only take sigterm signals in the select. */
640   BlockSignals(True,SIGTERM);
641   process();
642   close_sockets();
643
644   if (dbf)
645     fclose(dbf);
646   return(0);
647 }