updating documentation to reflect code a little bit.
[Samba.git] / source / nmbd / nmbd.c
blobe2a4bdeb67ff62e8fd45eb930fc3d30a44794f81
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;
56 /****************************************************************************
57 catch a sigterm
58 ****************************************************************************/
59 static int sig_term()
61 BlockSignals(True);
63 DEBUG(0,("Got SIGTERM: going down...\n"));
65 /* write out wins.dat file if samba is a WINS server */
66 dump_names();
68 /* remove all samba names, with wins server if necessary. */
69 remove_my_names();
71 /* announce all server entries as 0 time-to-live, 0 type */
72 /* XXXX don't care if we never receive a response back... yet */
73 remove_my_servers();
75 /* XXXX other things: if we are a master browser, force an election? */
77 exit(0);
81 /****************************************************************************
82 catch a sighup
83 ****************************************************************************/
84 static int sig_hup(void)
86 BlockSignals(True);
88 DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
89 dump_names();
90 reload_services(True);
92 set_samba_nb_type();
94 BlockSignals(False);
95 #ifndef DONT_REINSTALL_SIG
96 signal(SIGHUP,SIGNAL_CAST sig_hup);
97 #endif
98 return(0);
101 /****************************************************************************
102 catch a sigpipe
103 ****************************************************************************/
104 static int sig_pipe(void)
106 BlockSignals(True);
108 DEBUG(0,("Got SIGPIPE\n"));
109 if (!is_daemon)
110 exit(1);
111 BlockSignals(False);
112 return(0);
115 #if DUMP_CORE
116 /*******************************************************************
117 prepare to dump a core file - carefully!
118 ********************************************************************/
119 static BOOL dump_core(void)
121 char *p;
122 pstring dname;
123 strcpy(dname,debugf);
124 if ((p=strrchr(dname,'/'))) *p=0;
125 strcat(dname,"/corefiles");
126 mkdir(dname,0700);
127 sys_chown(dname,getuid(),getgid());
128 chmod(dname,0700);
129 if (chdir(dname)) return(False);
130 umask(~(0700));
132 #ifndef NO_GETRLIMIT
133 #ifdef RLIMIT_CORE
135 struct rlimit rlp;
136 getrlimit(RLIMIT_CORE, &rlp);
137 rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
138 setrlimit(RLIMIT_CORE, &rlp);
139 getrlimit(RLIMIT_CORE, &rlp);
140 DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
142 #endif
143 #endif
146 DEBUG(0,("Dumping core in %s\n",dname));
147 return(True);
149 #endif
152 /****************************************************************************
153 possibly continue after a fault
154 ****************************************************************************/
155 static void fault_continue(void)
157 #if DUMP_CORE
158 dump_core();
159 #endif
162 /*******************************************************************
163 expire old names from the namelist and server list
164 ******************************************************************/
165 static void expire_names_and_servers(void)
167 static time_t lastrun = 0;
168 time_t t = time(NULL);
170 if (!lastrun) lastrun = t;
171 if (t < lastrun + 5) return;
172 lastrun = t;
174 expire_names(t);
175 expire_servers(t);
178 /*****************************************************************************
179 reload the services file
180 **************************************************************************/
181 BOOL reload_services(BOOL test)
183 BOOL ret;
184 extern fstring remote_machine;
186 strcpy(remote_machine,"nmbd");
188 if (lp_loaded())
190 pstring fname;
191 strcpy(fname,lp_configfile());
192 if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
194 strcpy(servicesf,fname);
195 test = False;
199 if (test && !lp_file_list_changed())
200 return(True);
202 ret = lp_load(servicesf,True);
204 /* perhaps the config filename is now set */
205 if (!test) {
206 DEBUG(3,("services not loaded\n"));
207 reload_services(True);
210 load_interfaces();
211 add_subnet_interfaces();
213 return(ret);
218 /****************************************************************************
219 load a netbios hosts file
220 ****************************************************************************/
221 static void load_hosts_file(char *fname)
223 FILE *f = fopen(fname,"r");
224 pstring line;
225 if (!f) {
226 DEBUG(2,("Can't open lmhosts file %s\n",fname));
227 return;
230 while (!feof(f))
232 if (!fgets_slash(line,sizeof(pstring),f)) continue;
234 if (*line == '#') continue;
237 BOOL group=False;
239 pstring ip,name,mask,flags,extra;
241 char *ptr;
242 int count = 0;
243 struct in_addr ipaddr;
244 struct in_addr ipmask;
245 enum name_source source = LMHOSTS;
247 strcpy(ip,"");
248 strcpy(name,"");
249 strcpy(mask,"");
250 strcpy(flags,"");
251 strcpy(extra,"");
253 ptr = line;
255 if (next_token(&ptr,ip ,NULL)) ++count;
256 if (next_token(&ptr,name ,NULL)) ++count;
257 if (next_token(&ptr,mask ,NULL)) ++count;
258 if (next_token(&ptr,flags,NULL)) ++count;
259 if (next_token(&ptr,extra,NULL)) ++count;
261 if (count <= 0) continue;
263 if (count > 0 && count < 2) {
264 DEBUG(0,("Ill formed hosts line [%s]\n",line));
265 continue;
268 /* work out if we need to shuffle the tokens along due to the
269 optional subnet mask argument */
271 if (strchr(mask, 'G') || strchr(mask, 'S') || strchr(mask, 'M')) {
272 strcpy(flags, mask );
273 /* default action for no subnet mask */
274 strcpy(mask, "");
277 DEBUG(4, ("lmhost entry: %s %s %s %s\n", ip, name, mask, flags));
279 if (strchr(flags,'G') || strchr(flags,'S'))
280 group = True;
282 if (strchr(flags,'M') && !group) {
283 source = SELF;
284 strcpy(myname,name);
287 ipaddr = *interpret_addr2(ip);
288 if (*mask)
289 ipmask = *interpret_addr2(mask);
290 else
291 ipmask = *iface_nmask(ipaddr);
293 if (group) {
294 add_subnet_entry(ipaddr, ipmask, name, True, True);
295 } else {
296 struct subnet_record *d = find_subnet(ipaddr);
297 if (d)
299 add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
305 fclose(f);
309 /****************************************************************************
310 The main select loop.
311 ***************************************************************************/
312 static void process(void)
314 BOOL run_election;
316 while (True)
318 time_t t = time(NULL);
319 run_election = check_elections();
320 listen_for_packets(run_election);
322 run_packet_queue();
323 run_elections();
325 announce_host();
327 #if 1
328 /* XXXX what was this stuff supposed to do? It sent
329 ANN_GetBackupListReq packets which I think should only be
330 sent when trying to find out who to browse with */
332 announce_backup();
333 #endif
335 announce_master();
337 query_refresh_names();
339 expire_names_and_servers();
340 expire_netbios_response_entries();
341 refresh_my_names(t);
343 write_browse_list();
344 do_browser_lists();
345 check_master_browser();
350 /****************************************************************************
351 open the socket communication
352 ****************************************************************************/
353 static BOOL open_sockets(BOOL isdaemon, int port)
355 struct hostent *hp;
357 /* get host info */
358 if ((hp = Get_Hostbyname(myhostname)) == 0) {
359 DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
360 return False;
363 if (isdaemon)
364 ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
365 else
366 ClientNMB = 0;
368 ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
370 if (ClientNMB == -1)
371 return(False);
373 signal(SIGPIPE, SIGNAL_CAST sig_pipe);
375 set_socket_options(ClientNMB,"SO_BROADCAST");
376 set_socket_options(ClientDGRAM,"SO_BROADCAST");
378 DEBUG(3,("Sockets opened.\n"));
379 return True;
383 /****************************************************************************
384 initialise connect, service and file structs
385 ****************************************************************************/
386 static BOOL init_structs()
388 if (!get_myname(myhostname,NULL))
389 return(False);
391 if (! *myname) {
392 char *p;
393 strcpy(myname,myhostname);
394 p = strchr(myname,'.');
395 if (p) *p = 0;
398 return True;
401 /****************************************************************************
402 usage on the program
403 ****************************************************************************/
404 static void usage(char *pname)
406 DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
408 printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
409 printf("Version %s\n",VERSION);
410 printf("\t-D become a daemon\n");
411 printf("\t-p port listen on the specified port\n");
412 printf("\t-d debuglevel set the debuglevel\n");
413 printf("\t-l log basename. Basename for log/debug files\n");
414 printf("\t-n netbiosname. the netbios name to advertise for this host\n");
415 printf("\t-B broadcast address the address to use for broadcasts\n");
416 printf("\t-N netmask the netmask to use for subnet determination\n");
417 printf("\t-H hosts file load a netbios hosts file\n");
418 printf("\t-G group name add a group name to be part of\n");
419 printf("\t-I ip-address override the IP address\n");
420 printf("\t-C comment sets the machine comment that appears in browse lists\n");
421 printf("\n");
425 /****************************************************************************
426 main program
427 **************************************************************************/
428 int main(int argc,char *argv[])
430 int port = NMB_PORT;
431 int opt;
432 extern FILE *dbf;
433 extern char *optarg;
434 fstring group;
436 *group = 0;
437 *host_file = 0;
439 StartupTime = time(NULL);
441 TimeInit();
443 strcpy(debugf,NMBLOGFILE);
445 setup_logging(argv[0],False);
447 charset_initialise();
449 #ifdef LMHOSTSFILE
450 strcpy(host_file,LMHOSTSFILE);
451 #endif
453 /* this is for people who can't start the program correctly */
454 while (argc > 1 && (*argv[1] != '-')) {
455 argv++;
456 argc--;
459 fault_setup(fault_continue);
461 signal(SIGHUP ,SIGNAL_CAST sig_hup);
462 signal(SIGTERM,SIGNAL_CAST sig_term);
464 while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
466 switch (opt)
468 case 's':
469 strcpy(servicesf,optarg);
470 break;
471 case 'C':
472 strcpy(ServerComment,optarg);
473 break;
474 case 'G':
475 strcpy(group,optarg);
476 break;
477 case 'H':
478 strcpy(host_file,optarg);
479 break;
480 case 'I':
481 iface_set_default(optarg,NULL,NULL);
482 break;
483 case 'B':
484 iface_set_default(NULL,optarg,NULL);
485 break;
486 case 'N':
487 iface_set_default(NULL,NULL,optarg);
488 break;
489 case 'n':
490 strcpy(myname,optarg);
491 break;
492 case 'l':
493 sprintf(debugf,"%s.nmb",optarg);
494 break;
495 case 'i':
496 strcpy(scope,optarg);
497 strupper(scope);
498 break;
499 case 'D':
500 is_daemon = True;
501 break;
502 case 'd':
503 DEBUGLEVEL = atoi(optarg);
504 break;
505 case 'p':
506 port = atoi(optarg);
507 break;
508 case 'h':
509 usage(argv[0]);
510 exit(0);
511 break;
512 default:
513 if (!is_a_socket(0)) {
514 usage(argv[0]);
516 break;
520 DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
521 DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
523 init_structs();
525 if (!reload_services(False))
526 return(-1);
528 set_samba_nb_type();
530 if (*group)
531 add_my_subnets(group);
533 if (!is_daemon && !is_a_socket(0)) {
534 DEBUG(0,("standard input is not a socket, assuming -D option\n"));
535 is_daemon = True;
538 if (is_daemon) {
539 DEBUG(2,("%s becoming a daemon\n",timestring()));
540 become_daemon();
543 DEBUG(3,("Opening sockets %d\n", port));
545 if (!open_sockets(is_daemon,port)) return 1;
547 if (*host_file) {
548 load_hosts_file(host_file);
549 DEBUG(3,("Loaded hosts file\n"));
554 if (!*ServerComment)
555 strcpy(ServerComment,"Samba %v");
556 string_sub(ServerComment,"%v",VERSION);
557 string_sub(ServerComment,"%h",myhostname);
559 add_my_names();
560 add_my_subnets(lp_workgroup());
562 DEBUG(3,("Checked names\n"));
564 load_netbios_names();
566 DEBUG(3,("Loaded names\n"));
568 write_browse_list();
570 DEBUG(3,("Dumped names\n"));
572 process();
573 close_sockets();
575 if (dbf)
576 fclose(dbf);
577 return(0);