first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[kai/samba.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-1998
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 int global_nmb_port = -1;
40
41 static pstring host_file;
42 extern pstring global_myname;
43 extern fstring global_myworkgroup;
44 extern char **my_netbios_names;
45
46 extern BOOL global_in_nmbd;
47
48 /* are we running as a daemon ? */
49 static BOOL is_daemon = False;
50
51 /* have we found LanMan clients yet? */
52 BOOL found_lm_clients = False;
53
54 /* what server type are we currently */
55
56 time_t StartupTime = 0;
57
58 extern struct in_addr ipzero;
59
60 /**************************************************************************** **
61   catch a sigterm
62  **************************************************************************** */
63 static void sig_term(int sig)
64 {
65   BlockSignals(True,SIGTERM);
66   
67   DEBUG(0,("Got SIGTERM: going down...\n"));
68   
69   /* Write out wins.dat file if samba is a WINS server */
70   wins_write_database(False);
71   
72   /* Remove all SELF registered names. */
73   release_my_names();
74   
75   /* Announce all server entries as 0 time-to-live, 0 type. */
76   announce_my_servers_removed();
77
78   /* If there was an async dns child - kill it. */
79   kill_async_dns_child();
80
81   exit(0);
82
83 } /* sig_term */
84
85 /**************************************************************************** **
86  catch a sighup
87  **************************************************************************** */
88 static VOLATILE SIG_ATOMIC_T reload_after_sighup = False;
89
90 static void sig_hup(int sig)
91 {
92   BlockSignals( True, SIGHUP );
93
94   DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) );
95
96   write_browse_list( 0, True );
97
98   dump_all_namelists();
99
100   reload_after_sighup = True;
101
102   BlockSignals(False,SIGHUP);
103
104 } /* sig_hup */
105
106
107 #if DUMP_CORE
108 /**************************************************************************** **
109  prepare to dump a core file - carefully!
110  **************************************************************************** */
111 static BOOL dump_core(void)
112 {
113   char *p;
114   pstring dname;
115   pstrcpy( dname, debugf );
116   if ((p=strrchr(dname,'/')))
117     *p=0;
118   pstrcat( dname, "/corefiles" );
119   mkdir( dname, 0700 );
120   sys_chown( dname, getuid(), getgid() );
121   chmod( dname, 0700 );
122   if ( chdir(dname) )
123     return( False );
124   umask( ~(0700) );
125
126 #ifdef HAVE_GETRLIMIT
127 #ifdef RLIMIT_CORE
128   {
129     struct rlimit rlp;
130     getrlimit( RLIMIT_CORE, &rlp );
131     rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
132     setrlimit( RLIMIT_CORE, &rlp );
133     getrlimit( RLIMIT_CORE, &rlp );
134     DEBUG( 3, ( "Core limits now %d %d\n", (int)rlp.rlim_cur, (int)rlp.rlim_max ) );
135   }
136 #endif
137 #endif
138
139
140   DEBUG(0,("Dumping core in %s\n",dname));
141   abort();
142   return( True );
143 } /* dump_core */
144 #endif
145
146
147 /**************************************************************************** **
148  possibly continue after a fault
149  **************************************************************************** */
150 static void fault_continue(void)
151 {
152 #if DUMP_CORE
153   dump_core();
154 #endif
155 } /* fault_continue */
156
157 /**************************************************************************** **
158  expire old names from the namelist and server list
159  **************************************************************************** */
160 static void expire_names_and_servers(time_t t)
161 {
162   static time_t lastrun = 0;
163   
164   if ( !lastrun )
165     lastrun = t;
166   if ( t < (lastrun + 5) )
167     return;
168   lastrun = t;
169
170   /*
171    * Expire any timed out names on all the broadcast
172    * subnets and those registered with the WINS server.
173    * (nmbd_namelistdb.c)
174    */
175   expire_names(t);
176
177   /*
178    * Go through all the broadcast subnets and for each
179    * workgroup known on that subnet remove any expired
180    * server names. If a workgroup has an empty serverlist
181    * and has itself timed out then remove the workgroup.
182    * (nmbd_workgroupdb.c)
183    */
184   expire_workgroups_and_servers(t);
185 } /* expire_names_and_servers */
186
187
188 /************************************************************************** **
189 reload the list of network interfaces
190  ************************************************************************** */
191 static void reload_interfaces(time_t t)
192 {
193         static time_t lastt;
194         int n;
195         struct subnet_record *subrec;
196         extern BOOL rescan_listen_set;
197
198         if (t && ((t - lastt) < NMBD_INTERFACES_RELOAD)) return;
199         lastt = t;
200
201         if (!interfaces_changed()) return;
202
203         /* the list of probed interfaces has changed, we may need to add/remove
204            some subnets */
205         load_interfaces();
206
207         /* find any interfaces that need adding */
208         for (n=iface_count() - 1; n >= 0; n--) {
209                 struct interface *iface = get_interface(n);
210                 for (subrec=subnetlist; subrec; subrec=subrec->next) {
211                         if (ip_equal(iface->ip, subrec->myip) &&
212                             ip_equal(iface->nmask, subrec->mask_ip)) break;
213                 }
214                 if (!subrec) {
215                         /* it wasn't found! add it */
216                         DEBUG(2,("Found new interface %s\n", 
217                                  inet_ntoa(iface->ip)));
218                         subrec = make_normal_subnet(iface);
219                         if (subrec) register_my_workgroup_one_subnet(subrec);
220                 }
221         }
222
223         /* find any interfaces that need deleting */
224         for (subrec=subnetlist; subrec; subrec=subrec->next) {
225                 for (n=iface_count() - 1; n >= 0; n--) {
226                         struct interface *iface = get_interface(n);
227                         if (ip_equal(iface->ip, subrec->myip) &&
228                             ip_equal(iface->nmask, subrec->mask_ip)) break;
229                 }
230                 if (n == -1) {
231                         /* oops, an interface has disapeared. This is
232                          tricky, we don't dare actually free the
233                          interface as it could be being used, so
234                          instead we just wear the memory leak and
235                          remove it from the list of interfaces without
236                          freeing it */
237                         DEBUG(2,("Deleting dead interface %s\n", 
238                                  inet_ntoa(subrec->myip)));
239                         close_subnet(subrec);
240                 }
241         }
242         
243         rescan_listen_set = True;
244 }
245
246
247
248 /**************************************************************************** **
249   reload the services file
250  **************************************************************************** */
251 BOOL reload_services(BOOL test)
252 {
253   BOOL ret;
254   extern fstring remote_machine;
255
256   fstrcpy( remote_machine, "nmb" );
257
258   if ( lp_loaded() )
259   {
260     pstring fname;
261     pstrcpy( fname,lp_configfile());
262     if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
263     {
264       pstrcpy(servicesf,fname);
265       test = False;
266     }
267   }
268
269   if ( test && !lp_file_list_changed() )
270     return(True);
271
272   ret = lp_load( servicesf, True , False, False);
273
274   /* perhaps the config filename is now set */
275   if ( !test )
276   {
277     DEBUG( 3, ( "services not loaded\n" ) );
278     reload_services( True );
279   }
280
281   /* Do a sanity check for a misconfigured nmbd */
282   if( lp_wins_support() && *lp_wins_server() )
283   {
284     DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
285 cannot be set in the smb.conf file. nmbd aborting.\n"));
286     exit(10);
287   }
288
289   return(ret);
290 } /* reload_services */
291
292 /**************************************************************************** **
293  The main select loop.
294  **************************************************************************** */
295 static void process(void)
296 {
297   BOOL run_election;
298
299   while( True )
300   {
301     time_t t = time(NULL);
302
303     /*
304      * Check all broadcast subnets to see if
305      * we need to run an election on any of them.
306      * (nmbd_elections.c)
307      */
308     run_election = check_elections();
309
310     /*
311      * Read incoming UDP packets.
312      * (nmbd_packets.c)
313      */
314     if(listen_for_packets(run_election))
315       return;
316
317     /*
318      * Process all incoming packets
319      * read above. This calls the success and
320      * failure functions registered when response
321      * packets arrrive, and also deals with request
322      * packets from other sources.
323      * (nmbd_packets.c)
324      */
325     run_packet_queue();
326
327     /*
328      * Run any elections - initiate becoming
329      * a local master browser if we have won.
330      * (nmbd_elections.c)
331      */
332     run_elections(t);
333
334     /*
335      * Send out any broadcast announcements
336      * of our server names. This also announces
337      * the workgroup name if we are a local
338      * master browser.
339      * (nmbd_sendannounce.c)
340      */
341     announce_my_server_names(t);
342
343     /*
344      * Send out any LanMan broadcast announcements
345      * of our server names.
346      * (nmbd_sendannounce.c)
347      */
348     announce_my_lm_server_names(t);
349
350     /*
351      * If we are a local master browser, periodically
352      * announce ourselves to the domain master browser.
353      * This also deals with syncronising the domain master
354      * browser server lists with ourselves as a local
355      * master browser.
356      * (nmbd_sendannounce.c)
357      */
358     announce_myself_to_domain_master_browser(t);
359
360     /*
361      * Fullfill any remote announce requests.
362      * (nmbd_sendannounce.c)
363      */
364     announce_remote(t);
365
366     /*
367      * Fullfill any remote browse sync announce requests.
368      * (nmbd_sendannounce.c)
369      */
370     browse_sync_remote(t);
371
372     /*
373      * Scan the broadcast subnets, and WINS client
374      * namelists and refresh any that need refreshing.
375      * (nmbd_mynames.c)
376      */
377     refresh_my_names(t);
378
379     /*
380      * Scan the subnet namelists and server lists and
381      * expire thos that have timed out.
382      * (nmbd.c)
383      */
384     expire_names_and_servers(t);
385
386     /*
387      * Write out a snapshot of our current browse list into
388      * the browse.dat file. This is used by smbd to service
389      * incoming NetServerEnum calls - used to synchronise
390      * browse lists over subnets.
391      * (nmbd_serverlistdb.c)
392      */
393     write_browse_list(t, False);
394
395     /*
396      * If we are a domain master browser, we have a list of
397      * local master browsers we should synchronise browse
398      * lists with (these are added by an incoming local
399      * master browser announcement packet). Expire any of
400      * these that are no longer current, and pull the server
401      * lists from each of these known local master browsers.
402      * (nmbd_browsesync.c)
403      */
404     dmb_expire_and_sync_browser_lists(t);
405
406     /*
407      * Check that there is a local master browser for our
408      * workgroup for all our broadcast subnets. If one
409      * is not found, start an election (which we ourselves
410      * may or may not participate in, depending on the
411      * setting of the 'local master' parameter.
412      * (nmbd_elections.c)
413      */
414     check_master_browser_exists(t);
415
416     /*
417      * If we are configured as a logon server, attempt to
418      * register the special NetBIOS names to become such
419      * (WORKGROUP<1c> name) on all broadcast subnets and
420      * with the WINS server (if used). If we are configured
421      * to become a domain master browser, attempt to register
422      * the special NetBIOS name (WORKGROUP<1b> name) to
423      * become such.
424      * (nmbd_become_dmb.c)
425      */
426     add_domain_names(t);
427
428     /*
429      * If we are a WINS server, do any timer dependent
430      * processing required.
431      * (nmbd_winsserver.c)
432      */
433     initiate_wins_processing(t);
434
435     /*
436      * If we are a domain master browser, attempt to contact the
437      * WINS server to get a list of all known WORKGROUPS/DOMAINS.
438      * This will only work to a Samba WINS server.
439      * (nmbd_browsesync.c)
440      */
441     collect_all_workgroup_names_from_wins_server(t);
442
443     /*
444      * Go through the response record queue and time out or re-transmit
445      * and expired entries.
446      * (nmbd_packets.c)
447      */
448     retransmit_or_expire_response_records(t);
449
450     /*
451      * check to see if any remote browse sync child processes have completed
452      */
453     sync_check_completion();
454
455     /*
456      * regularly sync with any other DMBs we know about 
457      */
458     sync_all_dmbs(t);
459
460     /*
461      * Reload the services file if we got a sighup.
462      */
463
464     if(reload_after_sighup) {
465             reload_services( True );
466             reopen_logs();
467             reload_interfaces(0);
468             reload_after_sighup = False;
469     }
470
471     /* check for new network interfaces */
472     reload_interfaces(t);
473   }
474 } /* process */
475
476
477 /**************************************************************************** **
478  open the socket communication
479  **************************************************************************** */
480 static BOOL open_sockets(BOOL isdaemon, int port)
481 {
482   /* The sockets opened here will be used to receive broadcast
483      packets *only*. Interface specific sockets are opened in
484      make_subnet() in namedbsubnet.c. Thus we bind to the
485      address "0.0.0.0". The parameter 'socket address' is
486      now deprecated.
487    */
488
489   if ( isdaemon )
490     ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0,True);
491   else
492     ClientNMB = 0;
493   
494   ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0,True);
495
496   if ( ClientNMB == -1 )
497     return( False );
498
499   /* we are never interested in SIGPIPE */
500   BlockSignals(True,SIGPIPE);
501
502   set_socket_options( ClientNMB,   "SO_BROADCAST" );
503   set_socket_options( ClientDGRAM, "SO_BROADCAST" );
504
505   DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) );
506   return( True );
507 } /* open_sockets */
508
509
510 /**************************************************************************** **
511  initialise connect, service and file structs
512  **************************************************************************** */
513 static BOOL init_structs(void)
514 {
515   extern fstring local_machine;
516   char *p, *ptr;
517   int namecount;
518   int n;
519   int nodup;
520   pstring nbname;
521
522   if (! *global_myname)
523   {
524     fstrcpy( global_myname, myhostname() );
525     p = strchr( global_myname, '.' );
526     if (p)
527       *p = 0;
528   }
529   strupper( global_myname );
530
531   /* Add any NETBIOS name aliases. Ensure that the first entry
532      is equal to global_myname.
533    */
534   /* Work out the max number of netbios aliases that we have */
535   ptr = lp_netbios_aliases();
536   for( namecount=0; next_token(&ptr,nbname,NULL, sizeof(nbname)); namecount++ )
537     ;
538   if ( *global_myname )
539     namecount++;
540
541   /* Allocate space for the netbios aliases */
542   my_netbios_names = (char **)malloc( sizeof(char *) * (namecount+1) );
543   if( NULL == my_netbios_names )
544   {
545      DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
546      return( False );
547   }
548  
549   /* Use the global_myname string first */
550   namecount=0;
551   if ( *global_myname )
552     my_netbios_names[namecount++] = global_myname;
553   
554   ptr = lp_netbios_aliases();
555   while ( next_token( &ptr, nbname, NULL, sizeof(nbname) ) )
556   {
557     strupper( nbname );
558     /* Look for duplicates */
559     nodup=1;
560     for( n=0; n<namecount; n++ )
561     {
562       if( 0 == strcmp( nbname, my_netbios_names[n] ) )
563         nodup=0;
564     }
565     if (nodup)
566       my_netbios_names[namecount++] = strdup( nbname );
567   }
568   
569   /* Check the strdups succeeded. */
570   for( n = 0; n < namecount; n++ )
571     if( NULL == my_netbios_names[n] )
572     {
573       DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
574       return False;
575     }
576   
577   /* Terminate name list */
578   my_netbios_names[namecount++] = NULL;
579   
580   fstrcpy( local_machine, global_myname );
581   trim_string( local_machine, " ", " " );
582   p = strchr( local_machine, ' ' );
583   if (p)
584     *p = 0;
585   strlower( local_machine );
586
587   DEBUG( 5, ("Netbios name list:-\n") );
588   for( n=0; my_netbios_names[n]; n++ )
589     DEBUGADD( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n] ) );
590
591   return( True );
592 } /* init_structs */
593
594 /**************************************************************************** **
595  usage on the program
596  **************************************************************************** */
597 static void usage(char *pname)
598 {
599
600   printf( "Usage: %s [-DaohV] [-H lmhosts file] [-d debuglevel] [-l log basename]\n", pname );
601   printf( "       [-n name] [-p port] [-s configuration file] [-i scope]\n" );
602   printf( "\t-D                    Become a daemon\n" );
603   printf( "\t-a                    Append to log file (default)\n" );
604   printf( "\t-o                    Overwrite log file, don't append\n" );
605   printf( "\t-h                    Print usage\n" );
606   printf( "\t-V                    Print version\n" );
607   printf( "\t-H hosts file         Load a netbios hosts file\n" );
608   printf( "\t-d debuglevel         Set the debuglevel\n" );
609   printf( "\t-l log basename.      Basename for log/debug files\n" );
610   printf( "\t-n netbiosname.       Primary netbios name\n" );
611   printf( "\t-p port               Listen on the specified port\n" );
612   printf( "\t-s configuration file Configuration file name\n" );
613   printf( "\t-i scope              NetBIOS scope\n" );
614   printf( "\n");
615 } /* usage */
616
617
618 /**************************************************************************** **
619  main program
620  **************************************************************************** */
621  int main(int argc,char *argv[])
622 {
623   int opt;
624   extern FILE *dbf;
625   extern char *optarg;
626   extern BOOL  append_log;
627
628   append_log = True;  /* Default, override with '-o' option. */
629
630   global_nmb_port = NMB_PORT;
631   *host_file = 0;
632   global_in_nmbd = True;
633
634   StartupTime = time(NULL);
635
636   sys_srandom(time(NULL) ^ getpid());
637
638   TimeInit();
639
640   pstrcpy( debugf, NMBLOGFILE );
641
642   setup_logging( argv[0], False );
643
644   charset_initialise();
645
646 #ifdef LMHOSTSFILE
647   pstrcpy( host_file, LMHOSTSFILE );
648 #endif
649
650   /* this is for people who can't start the program correctly */
651   while (argc > 1 && (*argv[1] != '-'))
652   {
653     argv++;
654     argc--;
655   }
656
657   fault_setup((void (*)(void *))fault_continue );
658
659   CatchSignal( SIGHUP,  SIGNAL_CAST sig_hup );
660   CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
661
662 #if defined(SIGFPE)
663   /* we are never interested in SIGFPE */
664   BlockSignals(True,SIGFPE);
665 #endif
666
667   /* Setup the signals that allow the debug log level
668      to by dynamically changed. */
669
670   /* If we are using the malloc debug code we can't use
671      SIGUSR1 and SIGUSR2 to do debug level changes. */
672 #ifndef MEM_MAN
673 #if defined(SIGUSR1)
674   CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 );
675 #endif /* SIGUSR1 */
676
677 #if defined(SIGUSR2)
678   CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 );
679 #endif /* SIGUSR2 */
680 #endif /* MEM_MAN */
681
682   while( EOF != 
683          (opt = getopt( argc, argv, "Vaos:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:" )) )
684     {
685       switch (opt)
686         {
687         case 's':
688           pstrcpy(servicesf,optarg);
689           break;          
690         case 'N':
691         case 'B':
692         case 'I':
693         case 'C':
694         case 'G':
695           DEBUG(0,("Obsolete option '%c' used\n",opt));
696           break;
697         case 'H':
698           pstrcpy(host_file,optarg);
699           break;
700         case 'n':
701           pstrcpy(global_myname,optarg);
702           strupper(global_myname);
703           break;
704         case 'l':
705           slprintf(debugf,sizeof(debugf)-1, "%s.nmb",optarg);
706           break;
707         case 'i':
708           pstrcpy(scope,optarg);
709           strupper(scope);
710           break;
711         case 'a':
712           append_log = True;
713           break;
714         case 'o':
715           append_log = False;
716           break;
717         case 'D':
718           is_daemon = True;
719           break;
720         case 'd':
721           DEBUGLEVEL = atoi(optarg);
722           break;
723         case 'p':
724           global_nmb_port = atoi(optarg);
725           break;
726         case 'h':
727           usage(argv[0]);
728           exit(0);
729           break;
730         case 'V':
731           printf( "Version %s\n", VERSION );
732           exit(0);
733           break;
734         default:
735           if( !is_a_socket(0) )
736           {
737             DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
738             usage(argv[0]);
739             exit(0);
740           }
741           break;
742         }
743     }
744
745   reopen_logs();
746
747   DEBUG( 1, ( "Netbios nameserver version %s started.\n", VERSION ) );
748   DEBUGADD( 1, ( "Copyright Andrew Tridgell 1994-1998\n" ) );
749
750   if ( !reload_services(False) )
751     return(-1);
752
753   codepage_initialise(lp_client_code_page());
754
755   if(!init_structs())
756     return -1;
757
758   reload_services( True );
759
760   fstrcpy( global_myworkgroup, lp_workgroup() );
761
762   if (strequal(global_myworkgroup,"*"))
763   {
764     DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
765     exit(1);
766   }
767
768   set_samba_nb_type();
769
770   if (!is_daemon && !is_a_socket(0))
771   {
772     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
773     is_daemon = True;
774   }
775   
776   if (is_daemon)
777   {
778     DEBUG( 2, ( "Becoming a daemon.\n" ) );
779     become_daemon();
780   }
781
782 #ifndef SYNC_DNS
783   /* Setup the async dns. We do it here so it doesn't have all the other
784      stuff initialised and thus chewing memory and sockets */
785   if(lp_we_are_a_wins_server()) {
786           start_async_dns();
787   }
788 #endif
789
790   if (!directory_exist(lp_lockdir(), NULL)) {
791           mkdir(lp_lockdir(), 0755);
792   }
793
794   pidfile_create("nmbd");
795
796   DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
797
798   if ( !open_sockets( is_daemon, global_nmb_port ) )
799     return 1;
800
801   /* Determine all the IP addresses we have. */
802   load_interfaces();
803
804   /* Create an nmbd subnet record for each of the above. */
805   if( False == create_subnets() )
806   {
807     DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
808     exit(1);
809   }
810
811   /* Load in any static local names. */ 
812   if ( *host_file )
813   {
814     load_lmhosts_file(host_file);
815     DEBUG(3,("Loaded hosts file\n"));
816   }
817
818   /* If we are acting as a WINS server, initialise data structures. */
819   if( !initialise_wins() )
820   {
821     DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
822     exit(1);
823   }
824
825   /* 
826    * Register nmbd primary workgroup and nmbd names on all
827    * the broadcast subnets, and on the WINS server (if specified).
828    * Also initiate the startup of our primary workgroup (start
829    * elections if we are setup as being able to be a local
830    * master browser.
831    */
832
833   if( False == register_my_workgroup_and_names() )
834   {
835     DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
836     exit(1);
837   }
838
839   /* We can only take signals in the select. */
840   BlockSignals( True, SIGTERM );
841 #if defined(SIGUSR1)
842   BlockSignals( True, SIGUSR1);
843 #endif /* SIGUSR1 */
844 #if defined(SIGUSR2)
845   BlockSignals( True, SIGUSR2);
846 #endif /* SIGUSR2 */
847
848   process();
849   close_sockets();
850
851   if (dbf)
852     fclose(dbf);
853   return(0);
854 } /* main */
855