Large changes from jra@cygnus.com. Mainly browser updates.
[Samba.git] / source / nmbd / nmbd.c
blobeefb4162f79cc371ed656587da5fbb86efee45ca
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 /* what server type are we currently */
49 time_t StartupTime =0;
51 extern struct in_addr ipzero;
53 /****************************************************************************
54 catch a sigterm
55 ****************************************************************************/
56 static int sig_term()
58 BlockSignals(True,SIGTERM);
60 DEBUG(0,("Got SIGTERM: going down...\n"));
62 /* write out wins.dat file if samba is a WINS server */
63 dump_names();
65 /* remove all samba names, with wins server if necessary. */
66 remove_my_names();
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();
72 /* XXXX other things: if we are a master browser, force an election? */
74 exit(0);
78 /****************************************************************************
79 catch a sighup
80 ****************************************************************************/
81 static int sig_hup(void)
83 BlockSignals(True,SIGHUP);
85 DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
86 dump_names();
87 reload_services(True);
89 set_samba_nb_type();
91 BlockSignals(False,SIGHUP);
92 #ifndef DONT_REINSTALL_SIG
93 signal(SIGHUP,SIGNAL_CAST sig_hup);
94 #endif
95 return(0);
98 /****************************************************************************
99 catch a sigpipe
100 ****************************************************************************/
101 static int sig_pipe(void)
103 BlockSignals(True,SIGPIPE);
105 DEBUG(0,("Got SIGPIPE\n"));
106 if (!is_daemon)
107 exit(1);
108 BlockSignals(False,SIGPIPE);
109 return(0);
112 #if DUMP_CORE
113 /*******************************************************************
114 prepare to dump a core file - carefully!
115 ********************************************************************/
116 static BOOL dump_core(void)
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));
129 #ifndef NO_GETRLIMIT
130 #ifdef RLIMIT_CORE
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));
139 #endif
140 #endif
143 DEBUG(0,("Dumping core in %s\n",dname));
144 return(True);
146 #endif
149 /****************************************************************************
150 possibly continue after a fault
151 ****************************************************************************/
152 static void fault_continue(void)
154 #if DUMP_CORE
155 dump_core();
156 #endif
159 /*******************************************************************
160 expire old names from the namelist and server list
161 ******************************************************************/
162 static void expire_names_and_servers(time_t t)
164 static time_t lastrun = 0;
166 if (!lastrun) lastrun = t;
167 if (t < lastrun + 5) return;
168 lastrun = t;
170 expire_names(t);
171 expire_servers(t);
174 /*****************************************************************************
175 reload the services file
176 **************************************************************************/
177 BOOL reload_services(BOOL test)
179 BOOL ret;
180 extern fstring remote_machine;
182 strcpy(remote_machine,"nmbd");
184 if (lp_loaded())
186 pstring fname;
187 strcpy(fname,lp_configfile());
188 if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
190 strcpy(servicesf,fname);
191 test = False;
195 if (test && !lp_file_list_changed())
196 return(True);
198 ret = lp_load(servicesf,True);
200 /* perhaps the config filename is now set */
201 if (!test) {
202 DEBUG(3,("services not loaded\n"));
203 reload_services(True);
206 load_interfaces();
207 add_subnet_interfaces();
209 return(ret);
214 /****************************************************************************
215 load a netbios hosts file
216 ****************************************************************************/
217 static void load_hosts_file(char *fname)
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;
226 while (!feof(f))
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;
235 if (!fgets_slash(line,sizeof(pstring),f)) continue;
237 if (*line == '#') continue;
239 strcpy(ip,"");
240 strcpy(name,"");
241 strcpy(flags,"");
243 ptr = line;
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;
250 if (count <= 0) continue;
252 if (count > 0 && count < 2) {
253 DEBUG(0,("Ill formed hosts line [%s]\n",line));
254 continue;
257 if (count >= 4) {
258 DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
259 continue;
262 DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
264 if (strchr(flags,'G') || strchr(flags,'S')) {
265 DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
266 continue;
269 if (strchr(flags,'M')) {
270 source = SELF;
271 strcpy(myname,name);
274 ipaddr = *interpret_addr2(ip);
275 d = find_subnet_all(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);
282 fclose(f);
286 /****************************************************************************
287 The main select loop.
288 ***************************************************************************/
289 static void process(void)
291 BOOL run_election;
293 while (True)
295 time_t t = time(NULL);
296 run_election = check_elections();
297 listen_for_packets(run_election);
299 run_packet_queue();
300 run_elections(t);
302 announce_host(t);
303 announce_master(t);
304 announce_remote(t);
306 query_refresh_names(t);
308 expire_names_and_servers(t);
309 expire_netbios_response_entries(t);
310 refresh_my_names(t);
312 write_browse_list(t);
313 do_browser_lists(t);
314 check_master_browser(t);
315 add_domain_names(t);
320 /****************************************************************************
321 open the socket communication
322 ****************************************************************************/
323 static BOOL open_sockets(BOOL isdaemon, int port)
325 struct hostent *hp;
327 /* get host info */
328 if ((hp = Get_Hostbyname(myhostname)) == 0) {
329 DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
330 return False;
333 if (isdaemon)
334 ClientNMB = open_socket_in(SOCK_DGRAM, port,0,interpret_addr(lp_socket_address()));
335 else
336 ClientNMB = 0;
338 ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,interpret_addr(lp_socket_address()));
340 if (ClientNMB == -1)
341 return(False);
343 signal(SIGPIPE, SIGNAL_CAST sig_pipe);
345 set_socket_options(ClientNMB,"SO_BROADCAST");
346 set_socket_options(ClientDGRAM,"SO_BROADCAST");
348 DEBUG(3,("Sockets opened.\n"));
349 return True;
353 /****************************************************************************
354 initialise connect, service and file structs
355 ****************************************************************************/
356 static BOOL init_structs()
358 extern fstring local_machine;
359 char *p;
361 if (! *myname) {
362 strcpy(myname,myhostname);
363 p = strchr(myname,'.');
364 if (p) *p = 0;
366 strupper(myname);
368 strcpy(local_machine,myname);
369 trim_string(local_machine," "," ");
370 p = strchr(local_machine,' ');
371 if (p) *p = 0;
372 strlower(local_machine);
374 return True;
377 /****************************************************************************
378 usage on the program
379 ****************************************************************************/
380 static void usage(char *pname)
382 DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
384 printf("Usage: %s [-n name] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
385 printf("Version %s\n",VERSION);
386 printf("\t-D become a daemon\n");
387 printf("\t-p port listen on the specified port\n");
388 printf("\t-d debuglevel set the debuglevel\n");
389 printf("\t-l log basename. Basename for log/debug files\n");
390 printf("\t-n netbiosname. the netbios name to advertise for this host\n");
391 printf("\t-H hosts file load a netbios hosts file\n");
392 printf("\n");
396 /****************************************************************************
397 main program
398 **************************************************************************/
399 int main(int argc,char *argv[])
401 int port = NMB_PORT;
402 int opt;
403 extern FILE *dbf;
404 extern char *optarg;
405 char pidFile[100] = { 0 };
407 *host_file = 0;
409 StartupTime = time(NULL);
411 TimeInit();
413 strcpy(debugf,NMBLOGFILE);
415 setup_logging(argv[0],False);
417 charset_initialise();
419 #ifdef LMHOSTSFILE
420 strcpy(host_file,LMHOSTSFILE);
421 #endif
423 /* this is for people who can't start the program correctly */
424 while (argc > 1 && (*argv[1] != '-')) {
425 argv++;
426 argc--;
429 fault_setup(fault_continue);
431 signal(SIGHUP ,SIGNAL_CAST sig_hup);
432 signal(SIGTERM,SIGNAL_CAST sig_term);
434 while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
436 switch (opt)
438 case 'f':
439 strncpy(pidFile, optarg, sizeof(pidFile));
440 break;
441 case 's':
442 strcpy(servicesf,optarg);
443 break;
444 case 'N':
445 case 'B':
446 case 'I':
447 case 'C':
448 case 'G':
449 DEBUG(0,("Obsolete option '%c' used\n",opt));
450 break;
451 case 'H':
452 strcpy(host_file,optarg);
453 break;
454 case 'n':
455 strcpy(myname,optarg);
456 strupper(myname);
457 break;
458 case 'l':
459 sprintf(debugf,"%s.nmb",optarg);
460 break;
461 case 'i':
462 strcpy(scope,optarg);
463 strupper(scope);
464 break;
465 case 'D':
466 is_daemon = True;
467 break;
468 case 'd':
469 DEBUGLEVEL = atoi(optarg);
470 break;
471 case 'p':
472 port = atoi(optarg);
473 break;
474 case 'h':
475 usage(argv[0]);
476 exit(0);
477 break;
478 default:
479 if (!is_a_socket(0)) {
480 usage(argv[0]);
482 break;
486 DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
487 DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
489 get_myname(myhostname,NULL);
491 if (!reload_services(False))
492 return(-1);
494 init_structs();
496 reload_services(True);
498 set_samba_nb_type();
500 if (!is_daemon && !is_a_socket(0)) {
501 DEBUG(0,("standard input is not a socket, assuming -D option\n"));
502 is_daemon = True;
505 if (is_daemon) {
506 DEBUG(2,("%s becoming a daemon\n",timestring()));
507 become_daemon();
510 if (*pidFile)
512 int fd;
513 char buf[20];
515 if ((fd = open(pidFile,
516 O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
518 DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
519 exit(1);
521 if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
523 DEBUG(0,("ERROR: nmbd is already running\n"));
524 exit(1);
526 sprintf(buf, "%u\n", (unsigned int) getpid());
527 if (write(fd, buf, strlen(buf)) < 0)
529 DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
530 exit(1);
532 /* Leave pid file open & locked for the duration... */
536 DEBUG(3,("Opening sockets %d\n", port));
538 if (!open_sockets(is_daemon,port)) return 1;
540 if (*host_file) {
541 load_hosts_file(host_file);
542 DEBUG(3,("Loaded hosts file\n"));
545 add_my_names();
547 if (strequal(lp_workgroup(),"*")) {
548 DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
551 add_my_subnets(lp_workgroup());
553 DEBUG(3,("Checked names\n"));
555 load_netbios_names();
557 DEBUG(3,("Loaded names\n"));
559 write_browse_list(time(NULL));
561 DEBUG(3,("Dumped names\n"));
563 process();
564 close_sockets();
566 if (dbf)
567 fclose(dbf);
568 return(0);