modified become_master() to a state-based system. becoming a master
[Samba.git] / source / nmbd / nmbd.c
blob187ef8e7b720c9efd87ce2e3eecb1cd6b4d86694
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
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.
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.
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.
21 Revision History:
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
28 #include "includes.h"
30 extern int DEBUGLEVEL;
32 extern pstring debugf;
33 pstring servicesf = CONFIGFILE;
35 extern pstring scope;
37 int ClientNMB = -1;
38 int ClientDGRAM = -1;
40 extern pstring myhostname;
41 static pstring host_file;
42 extern pstring myname;
44 /* are we running as a daemon ? */
45 static BOOL is_daemon = False;
47 /* machine comment for host announcements */
48 pstring ServerComment="";
50 /* what server type are we currently */
52 time_t StartupTime =0;
54 extern struct in_addr ipzero;
57 /****************************************************************************
58 catch a sigterm
59 ****************************************************************************/
60 static int sig_term()
62 BlockSignals(True);
64 DEBUG(0,("Got SIGTERM: going down...\n"));
66 dump_names();
67 reload_services(True);
69 /* remove all samba names, with wins server if necessary. */
70 remove_my_names();
72 /* announce all server entries as 0 time-to-live, 0 type */
73 remove_my_servers();
75 /* XXXX don't care if we never receive a response back... yet */
76 /* XXXX other things: if we are a master browser, force an election? */
78 exit(0);
82 /****************************************************************************
83 catch a sighup
84 ****************************************************************************/
85 static int sig_hup(void)
87 BlockSignals(True);
89 DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
90 dump_names();
91 reload_services(True);
93 BlockSignals(False);
94 #ifndef DONT_REINSTALL_SIG
95 signal(SIGHUP,SIGNAL_CAST sig_hup);
96 #endif
97 return(0);
100 /****************************************************************************
101 catch a sigpipe
102 ****************************************************************************/
103 static int sig_pipe(void)
105 BlockSignals(True);
107 DEBUG(0,("Got SIGPIPE\n"));
108 if (!is_daemon)
109 exit(1);
110 BlockSignals(False);
111 return(0);
114 #if DUMP_CORE
115 /*******************************************************************
116 prepare to dump a core file - carefully!
117 ********************************************************************/
118 static BOOL dump_core(void)
120 char *p;
121 pstring dname;
122 strcpy(dname,debugf);
123 if ((p=strrchr(dname,'/'))) *p=0;
124 strcat(dname,"/corefiles");
125 mkdir(dname,0700);
126 sys_chown(dname,getuid(),getgid());
127 chmod(dname,0700);
128 if (chdir(dname)) return(False);
129 umask(~(0700));
131 #ifndef NO_GETRLIMIT
132 #ifdef RLIMIT_CORE
134 struct rlimit rlp;
135 getrlimit(RLIMIT_CORE, &rlp);
136 rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
137 setrlimit(RLIMIT_CORE, &rlp);
138 getrlimit(RLIMIT_CORE, &rlp);
139 DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
141 #endif
142 #endif
145 DEBUG(0,("Dumping core in %s\n",dname));
146 return(True);
148 #endif
151 /****************************************************************************
152 possibly continue after a fault
153 ****************************************************************************/
154 static void fault_continue(void)
156 #if DUMP_CORE
157 dump_core();
158 #endif
161 /*******************************************************************
162 expire old names from the namelist and server list
163 ******************************************************************/
164 static void expire_names_and_servers(void)
166 static time_t lastrun = 0;
167 time_t t = time(NULL);
169 if (!lastrun) lastrun = t;
170 if (t < lastrun + 5) return;
171 lastrun = t;
173 expire_names(t);
174 expire_servers(t);
177 /*****************************************************************************
178 reload the services file
179 **************************************************************************/
180 BOOL reload_services(BOOL test)
182 BOOL ret;
183 extern fstring remote_machine;
185 strcpy(remote_machine,"nmbd");
187 if (lp_loaded())
189 pstring fname;
190 strcpy(fname,lp_configfile());
191 if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
193 strcpy(servicesf,fname);
194 test = False;
198 if (test && !lp_file_list_changed())
199 return(True);
201 ret = lp_load(servicesf,True);
203 /* perhaps the config filename is now set */
204 if (!test) {
205 DEBUG(3,("services not loaded\n"));
206 reload_services(True);
209 load_interfaces();
210 add_subnet_interfaces();
212 return(ret);
217 /****************************************************************************
218 load a netbios hosts file
219 ****************************************************************************/
220 static void load_hosts_file(char *fname)
222 FILE *f = fopen(fname,"r");
223 pstring line;
224 if (!f) {
225 DEBUG(2,("Can't open lmhosts file %s\n",fname));
226 return;
229 while (!feof(f))
231 if (!fgets_slash(line,sizeof(pstring),f)) continue;
233 if (*line == '#') continue;
236 BOOL group=False;
238 pstring ip,name,mask,flags,extra;
240 char *ptr;
241 int count = 0;
242 struct in_addr ipaddr;
243 struct in_addr ipmask;
244 enum name_source source = LMHOSTS;
246 strcpy(ip,"");
247 strcpy(name,"");
248 strcpy(mask,"");
249 strcpy(flags,"");
250 strcpy(extra,"");
252 ptr = line;
254 if (next_token(&ptr,ip ,NULL)) ++count;
255 if (next_token(&ptr,name ,NULL)) ++count;
256 if (next_token(&ptr,mask ,NULL)) ++count;
257 if (next_token(&ptr,flags,NULL)) ++count;
258 if (next_token(&ptr,extra,NULL)) ++count;
260 if (count <= 0) continue;
262 if (count > 0 && count < 2) {
263 DEBUG(0,("Ill formed hosts line [%s]\n",line));
264 continue;
267 /* work out if we need to shuffle the tokens along due to the
268 optional subnet mask argument */
270 if (strchr(mask, 'G') || strchr(mask, 'S') || strchr(mask, 'M')) {
271 strcpy(flags, mask );
272 /* default action for no subnet mask */
273 strcpy(mask, "");
276 DEBUG(4, ("lmhost entry: %s %s %s %s\n", ip, name, mask, flags));
278 if (strchr(flags,'G') || strchr(flags,'S'))
279 group = True;
281 if (strchr(flags,'M') && !group) {
282 source = SELF;
283 strcpy(myname,name);
286 ipaddr = *interpret_addr2(ip);
287 if (*mask)
288 ipmask = *interpret_addr2(mask);
289 else
290 ipmask = *iface_nmask(ipaddr);
292 if (group) {
293 add_subnet_entry(ipaddr, ipmask, name, True, True);
294 } else {
295 struct subnet_record *d = find_subnet(ipaddr);
296 if (d)
298 add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
304 fclose(f);
308 /****************************************************************************
309 The main select loop.
310 ***************************************************************************/
311 static void process(void)
313 BOOL run_election;
315 while (True)
317 time_t t = time(NULL);
318 run_election = check_elections();
319 listen_for_packets(run_election);
321 run_packet_queue();
322 run_elections();
324 announce_host();
326 #if 0
327 /* XXXX what was this stuff supposed to do? It sent
328 ANN_GetBackupListReq packets which I think should only be
329 sent when trying to find out who to browse with */
331 announce_backup();
332 #endif
334 announce_master();
336 query_refresh_names();
338 expire_names_and_servers();
339 expire_netbios_response_entries();
340 refresh_my_names(t);
342 write_browse_list();
343 do_browser_lists();
344 check_master_browser();
349 /****************************************************************************
350 open the socket communication
351 ****************************************************************************/
352 static BOOL open_sockets(BOOL isdaemon, int port)
354 struct hostent *hp;
356 /* get host info */
357 if ((hp = Get_Hostbyname(myhostname)) == 0) {
358 DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
359 return False;
362 if (isdaemon)
363 ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
364 else
365 ClientNMB = 0;
367 ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
369 if (ClientNMB == -1)
370 return(False);
372 signal(SIGPIPE, SIGNAL_CAST sig_pipe);
374 set_socket_options(ClientNMB,"SO_BROADCAST");
375 set_socket_options(ClientDGRAM,"SO_BROADCAST");
377 DEBUG(3,("Sockets opened.\n"));
378 return True;
382 /****************************************************************************
383 initialise connect, service and file structs
384 ****************************************************************************/
385 static BOOL init_structs()
387 if (!get_myname(myhostname,NULL))
388 return(False);
390 if (! *myname) {
391 char *p;
392 strcpy(myname,myhostname);
393 p = strchr(myname,'.');
394 if (p) *p = 0;
397 return True;
400 /****************************************************************************
401 usage on the program
402 ****************************************************************************/
403 static void usage(char *pname)
405 DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
407 printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
408 printf("Version %s\n",VERSION);
409 printf("\t-D become a daemon\n");
410 printf("\t-p port listen on the specified port\n");
411 printf("\t-d debuglevel set the debuglevel\n");
412 printf("\t-l log basename. Basename for log/debug files\n");
413 printf("\t-n netbiosname. the netbios name to advertise for this host\n");
414 printf("\t-B broadcast address the address to use for broadcasts\n");
415 printf("\t-N netmask the netmask to use for subnet determination\n");
416 printf("\t-H hosts file load a netbios hosts file\n");
417 printf("\t-G group name add a group name to be part of\n");
418 printf("\t-I ip-address override the IP address\n");
419 printf("\t-C comment sets the machine comment that appears in browse lists\n");
420 printf("\n");
424 /****************************************************************************
425 main program
426 **************************************************************************/
427 int main(int argc,char *argv[])
429 int port = NMB_PORT;
430 int opt;
431 extern FILE *dbf;
432 extern char *optarg;
433 fstring group;
435 *group = 0;
436 *host_file = 0;
438 StartupTime = time(NULL);
440 TimeInit();
442 strcpy(debugf,NMBLOGFILE);
444 setup_logging(argv[0],False);
446 charset_initialise();
448 #ifdef LMHOSTSFILE
449 strcpy(host_file,LMHOSTSFILE);
450 #endif
452 /* this is for people who can't start the program correctly */
453 while (argc > 1 && (*argv[1] != '-')) {
454 argv++;
455 argc--;
458 fault_setup(fault_continue);
460 signal(SIGHUP ,SIGNAL_CAST sig_hup);
461 signal(SIGTERM,SIGNAL_CAST sig_term);
463 while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
465 switch (opt)
467 case 's':
468 strcpy(servicesf,optarg);
469 break;
470 case 'C':
471 strcpy(ServerComment,optarg);
472 break;
473 case 'G':
474 strcpy(group,optarg);
475 break;
476 case 'H':
477 strcpy(host_file,optarg);
478 break;
479 case 'I':
480 iface_set_default(optarg,NULL,NULL);
481 break;
482 case 'B':
483 iface_set_default(NULL,optarg,NULL);
484 break;
485 case 'N':
486 iface_set_default(NULL,NULL,optarg);
487 break;
488 case 'n':
489 strcpy(myname,optarg);
490 break;
491 case 'l':
492 sprintf(debugf,"%s.nmb",optarg);
493 break;
494 case 'i':
495 strcpy(scope,optarg);
496 strupper(scope);
497 break;
498 case 'D':
499 is_daemon = True;
500 break;
501 case 'd':
502 DEBUGLEVEL = atoi(optarg);
503 break;
504 case 'p':
505 port = atoi(optarg);
506 break;
507 case 'h':
508 usage(argv[0]);
509 exit(0);
510 break;
511 default:
512 if (!is_a_socket(0)) {
513 usage(argv[0]);
515 break;
519 DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
520 DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
522 init_structs();
524 if (!reload_services(False))
525 return(-1);
527 if (*group)
528 add_my_subnets(group);
530 if (!is_daemon && !is_a_socket(0)) {
531 DEBUG(0,("standard input is not a socket, assuming -D option\n"));
532 is_daemon = True;
535 if (is_daemon) {
536 DEBUG(2,("%s becoming a daemon\n",timestring()));
537 become_daemon();
540 DEBUG(3,("Opening sockets %d\n", port));
542 if (!open_sockets(is_daemon,port)) return 1;
544 if (*host_file) {
545 load_hosts_file(host_file);
546 DEBUG(3,("Loaded hosts file\n"));
551 if (!*ServerComment)
552 strcpy(ServerComment,"Samba %v");
553 string_sub(ServerComment,"%v",VERSION);
554 string_sub(ServerComment,"%h",myhostname);
556 add_my_names();
557 add_my_subnets(lp_workgroup());
559 DEBUG(3,("Checked names\n"));
561 load_netbios_names();
563 DEBUG(3,("Loaded names\n"));
565 write_browse_list();
567 DEBUG(3,("Dumped names\n"));
569 process();
570 close_sockets();
572 if (dbf)
573 fclose(dbf);
574 return(0);