Removed version number from file header.
[ira/wip.git] / source3 / wrepld / server.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main SMB server routines
4    Copyright (C) Jean François Micouleau      1998-2002.
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "wins_repl.h"
23
24 extern fstring global_myworkgroup;
25 extern pstring global_myname;
26
27 extern pstring user_socket_options;
28
29 extern fstring remote_machine;
30 extern WINS_OWNER *global_wins_table;
31 extern int partner_count;
32
33 extern fd_set *listen_set;
34 extern int listen_number;
35 extern int *sock_array;
36
37 extern TALLOC_CTX *mem_ctx;
38
39 int wins_port = 42;
40
41 /****************************************************************************
42   when exiting, take the whole family
43 ****************************************************************************/
44 static void *dflt_sig(void)
45 {
46         exit_server("caught signal");
47         return NULL;
48 }
49
50 /****************************************************************************
51   reload the services file
52   **************************************************************************/
53 BOOL reload_services(BOOL test)
54 {
55         BOOL ret;
56         
57         if (lp_loaded()) {
58                 pstring fname;
59                 pstrcpy(fname,lp_configfile());
60                 if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE)) {
61                         pstrcpy(dyn_CONFIGFILE,fname);
62                         test = False;
63                 }
64         }
65
66         reopen_logs();
67
68         if (test && !lp_file_list_changed())
69                 return(True);
70
71         ret = lp_load(dyn_CONFIGFILE,False,False,True);
72
73
74         /* perhaps the config filename is now set */
75         if (!test)
76                 reload_services(True);
77
78         reopen_logs();
79
80         load_interfaces();
81
82         return(ret);
83 }
84
85 /****************************************************************************
86  Catch a sighup.
87 ****************************************************************************/
88
89 VOLATILE sig_atomic_t reload_after_sighup = False;
90
91 static void sig_hup(int sig)
92 {
93         BlockSignals(True,SIGHUP);
94         DEBUG(0,("Got SIGHUP\n"));
95
96         sys_select_signal();
97         reload_after_sighup = True;
98         BlockSignals(False,SIGHUP);
99 }
100
101 #if DUMP_CORE
102 /*******************************************************************
103 prepare to dump a core file - carefully!
104 ********************************************************************/
105 static BOOL dump_core(void)
106 {
107         char *p;
108         pstring dname;
109         pstrcpy(dname,lp_logfile());
110         if ((p=strrchr_m(dname,'/'))) *p=0;
111         pstrcat(dname,"/corefiles");
112         mkdir(dname,0700);
113         sys_chown(dname,getuid(),getgid());
114         chmod(dname,0700);
115         if (chdir(dname)) return(False);
116         umask(~(0700));
117
118 #ifdef HAVE_GETRLIMIT
119 #ifdef RLIMIT_CORE
120         {
121                 struct rlimit rlp;
122                 getrlimit(RLIMIT_CORE, &rlp);
123                 rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
124                 setrlimit(RLIMIT_CORE, &rlp);
125                 getrlimit(RLIMIT_CORE, &rlp);
126                 DEBUG(3,("Core limits now %d %d\n",
127                          (int)rlp.rlim_cur,(int)rlp.rlim_max));
128         }
129 #endif
130 #endif
131
132
133         DEBUG(0,("Dumping core in %s\n",dname));
134         abort();
135         return(True);
136 }
137 #endif
138
139 /****************************************************************************
140 exit the server
141 ****************************************************************************/
142 void exit_server(char *reason)
143 {
144         static int firsttime=1;
145
146         if (!firsttime)
147                 exit(0);
148         firsttime = 0;
149
150         DEBUG(2,("Closing connections\n"));
151
152         if (!reason) {   
153                 int oldlevel = DEBUGLEVEL;
154                 DEBUGLEVEL = 10;
155                 DEBUGLEVEL = oldlevel;
156                 DEBUG(0,("===============================================================\n"));
157 #if DUMP_CORE
158                 if (dump_core()) return;
159 #endif
160         }
161
162         DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
163         exit(0);
164 }
165
166 /****************************************************************************
167   initialise connect, service and file structs
168 ****************************************************************************/
169 static void init_structs(void )
170 {
171         /*
172          * Set the machine NETBIOS name if not already
173          * set from the config file.
174          */
175
176         if (!*global_myname) {
177                 char *p;
178                 fstrcpy( global_myname, myhostname() );
179                 p = strchr_m( global_myname, '.' );
180                 if (p) 
181                         *p = 0;
182         }
183
184         strupper( global_myname );
185 }
186
187 /****************************************************************************
188 usage on the program
189 ****************************************************************************/
190 static void usage(char *pname)
191 {
192
193         d_printf("Usage: %s [-DaioPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname);
194         d_printf("       [-O socket options] [-s services file]\n");
195         d_printf("\t-D                    Become a daemon (default)\n");
196         d_printf("\t-a                    Append to log file (default)\n");
197         d_printf("\t-i                    Run interactive (not a daemon)\n" );
198         d_printf("\t-o                    Overwrite log file, don't append\n");
199         d_printf("\t-h                    Print usage\n");
200         d_printf("\t-?                    Print usage\n");
201         d_printf("\t-V                    Print version\n");
202         d_printf("\t-d debuglevel         Set the debuglevel\n");
203         d_printf("\t-l log basename.      Basename for log/debug files\n");
204         d_printf("\t-p port               Listen on the specified port\n");
205         d_printf("\t-O socket options     Socket options\n");
206         d_printf("\t-s services file.     Filename of services file\n");
207         d_printf("\n");
208 }
209
210 /****************************************************************************
211   Create an fd_set containing all the sockets in the subnet structures,
212   plus the broadcast sockets.
213 ***************************************************************************/
214
215 static BOOL create_listen_fdset(void)
216 {
217         int i;
218         int num_interfaces = iface_count();
219         int s;
220
221         listen_set = (fd_set *)malloc(sizeof(fd_set));
222         if(listen_set == NULL) {
223                 DEBUG(0,("create_listen_fdset: malloc fail !\n"));
224                 return True;
225         }
226
227 #ifdef HAVE_ATEXIT
228         {
229                 static int atexit_set;
230                 if(atexit_set == 0) {
231                         atexit_set=1;
232                 }
233         }
234 #endif
235
236         FD_ZERO(listen_set);
237
238         if(lp_interfaces() && lp_bind_interfaces_only()) {
239                 /* We have been given an interfaces line, and been 
240                    told to only bind to those interfaces. Create a
241                    socket per interface and bind to only these.
242                 */
243                 
244                 if(num_interfaces > FD_SETSIZE) {
245                         DEBUG(0,("create_listen_fdset: Too many interfaces specified to bind to. Number was %d max can be %d\n", num_interfaces, FD_SETSIZE));
246                         return False;
247                 }
248
249                 /* Now open a listen socket for each of the interfaces. */
250                 for(i = 0; i < num_interfaces; i++) {
251                         struct in_addr *ifip = iface_n_ip(i);
252                         
253                         if(ifip == NULL) {
254                                 DEBUG(0,("create_listen_fdset: interface %d has NULL IP address !\n", i));
255                                 continue;
256                         }
257                         s = open_socket_in(SOCK_STREAM, wins_port, 0, ifip->s_addr, True);
258                         if(s == -1)
259                                 return False;
260
261                         /* ready to listen */
262                         set_socket_options(s,"SO_KEEPALIVE"); 
263                         set_socket_options(s,user_socket_options);
264       
265                         if (listen(s, 5) == -1) {
266                                 DEBUG(0,("listen: %s\n",strerror(errno)));
267                                 close(s);
268                                 return False;
269                         }
270                         add_fd_to_sock_array(s);
271                         FD_SET(s, listen_set);
272                 }
273         } else {
274                 /* Just bind to 0.0.0.0 - accept connections from anywhere. */
275                 num_interfaces = 1;
276                 
277                 /* open an incoming socket */
278                 s = open_socket_in(SOCK_STREAM, wins_port, 0, interpret_addr(lp_socket_address()),True);
279                 if (s == -1)
280                         return(False);
281                 
282                 /* ready to listen */
283                 set_socket_options(s,"SO_KEEPALIVE"); 
284                 set_socket_options(s,user_socket_options);
285
286                 if (listen(s, 5) == -1) {
287                         DEBUG(0,("create_listen_fdset: listen: %s\n", strerror(errno)));
288                         close(s);
289                         return False;
290                 }
291                 
292                 add_fd_to_sock_array(s);
293                 FD_SET(s, listen_set);
294         } 
295
296         return True;
297 }
298
299 /*******************************************************************
300   read a packet from a socket and parse it, returning a packet ready
301   to be used or put on the queue. This assumes a UDP socket
302   ******************************************************************/
303 static struct wins_packet_struct *read_wins_packet(int fd, int timeout)
304 {
305         struct wins_packet_struct *p;
306         GENERIC_PACKET *q;
307         char buf[4096];
308
309         if (!receive_smb(fd, buf, timeout))
310                 return NULL;
311
312         q = (GENERIC_PACKET *)talloc(mem_ctx, sizeof(GENERIC_PACKET));
313         p = (struct wins_packet_struct *)talloc(mem_ctx, sizeof(*p));
314         if (q==NULL || p==NULL)
315                 return NULL;
316
317         decode_generic_packet(buf, q);
318
319         q->fd=fd;
320         
321         p->next = NULL;
322         p->prev = NULL;
323         p->stop_packet = False;
324         p->timestamp = time(NULL);
325         p->fd = fd;
326         p->packet=q;
327         
328         return p;
329 }
330
331 static struct wins_packet_struct *packet_queue = NULL;
332
333 /*******************************************************************
334   Queue a packet into a packet queue
335 ******************************************************************/
336 static void queue_packet(struct wins_packet_struct *packet)
337 {
338         struct wins_packet_struct *p;
339
340         if (!packet_queue) {
341                 packet->prev = NULL;
342                 packet->next = NULL;
343                 packet_queue = packet;
344                 return;
345         }
346   
347         /* find the bottom */
348         for (p=packet_queue;p->next;p=p->next) 
349                 ;
350
351         p->next = packet;
352         packet->next = NULL;
353         packet->prev = p;
354 }
355
356 /****************************************************************************
357   Listens for NMB or DGRAM packets, and queues them.
358   return True if the socket is dead
359 ***************************************************************************/
360 static BOOL listen_for_wins_packets(void)
361 {
362         int num_interfaces = iface_count();
363         fd_set fds;
364         int i, num, s, new_s;
365         struct timeval timeout;
366
367         if(listen_set == NULL) {
368                 if(!create_listen_fdset()) {
369                         DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
370                         return True;
371                 }
372         }
373
374         memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
375
376         timeout.tv_sec = NMBD_SELECT_LOOP;
377         timeout.tv_usec = 0;
378
379         /* Prepare for the select - allow certain signals. */
380
381         BlockSignals(False, SIGTERM);
382
383         num = sys_select(FD_SETSIZE, &fds, &timeout);
384
385         /* We can only take signals when we are in the select - block them again here. */
386
387         BlockSignals(True, SIGTERM);
388
389         if(num == -1)
390                 return False;
391
392         for (; num > 0; num--) {
393                 s = -1;
394                 /* check the sockets we are only listening on, waiting to accept */             
395                 for (i=0; i<num_interfaces; i++) {
396                         struct sockaddr addr;
397                         socklen_t in_addrlen = sizeof(addr);
398                 
399                         if(FD_ISSET(sock_array[i], &fds)) {
400                                 s = sock_array[i];
401                                 /* Clear this so we don't look at it again. */
402                                 FD_CLR(sock_array[i], &fds);
403
404                                 /* accept and add the new socket to the listen set */
405                                 new_s=accept(s, &addr, &in_addrlen);
406                                         
407                                 DEBUG(5,("listen_for_wins_packets: new connection, old: %d, new : %d\n", s, new_s));
408                                 
409                                 set_socket_options(new_s, "SO_KEEPALIVE");
410                                 set_socket_options(new_s, user_socket_options);
411                                 FD_SET(new_s, listen_set);
412                                 add_fd_to_sock_array(new_s);
413                         }
414                 }
415
416                 /*
417                  * check for the sockets we are waiting data from
418                  * either client sending datas
419                  * or reply to our requests
420                  */
421                 for (i=num_interfaces; i<listen_number; i++) {
422                         if(FD_ISSET(sock_array[i], &fds)) {
423                                 struct wins_packet_struct *packet = read_wins_packet(sock_array[i], timeout.tv_sec);
424                                 if (packet) {
425                                         packet->fd = sock_array[i];
426                                         queue_packet(packet);
427                                 }
428                                 DEBUG(2,("listen_for_wins_packets: some data on fd %d\n", sock_array[i]));
429                                 FD_CLR(sock_array[i], &fds);
430                                 break;
431                         }
432         
433                 }
434
435         }
436
437         return False;
438 }
439
440
441 /*******************************************************************
442   Run elements off the packet queue till its empty
443 ******************************************************************/
444
445 static void run_wins_packet_queue(void)
446 {
447         struct wins_packet_struct *p;
448
449         while ((p = packet_queue)) {
450                 packet_queue = p->next;
451                 if (packet_queue)
452                         packet_queue->prev = NULL;
453                 p->next = p->prev = NULL;
454
455                 construct_reply(p);
456
457                 /* if it was a stop assoc, close the connection */
458                 if (p->stop_packet) {
459                         FD_CLR(p->fd, listen_set);
460                         remove_fd_from_sock_array(p->fd);
461                         close(p->fd);
462                 }
463         }
464
465
466 /**************************************************************************** **
467  The main select loop.
468  **************************************************************************** */
469 static void process(void)
470 {
471
472         while( True ) {
473                 time_t t = time(NULL);
474
475                 /* check for internal messages */
476                 message_dispatch();
477
478                 if(listen_for_wins_packets())
479                         return;
480
481                 run_wins_packet_queue();
482
483                 run_pull_replication(t);
484                 
485                 run_push_replication(t);
486                 
487                 /*
488                  * Reload the services file if we got a sighup.
489                  */
490
491                 if(reload_after_sighup) {
492                         reload_services( True );
493                         reopen_logs();
494                         reload_after_sighup = False;
495                 }
496
497                 /* free temp memory */
498                 talloc_destroy_pool(mem_ctx);
499
500                 /* free up temp memory */
501                 lp_talloc_free();
502         }
503 } /* process */
504
505 /****************************************************************************
506   main program
507 ****************************************************************************/
508  int main(int argc,char *argv[])
509 {
510         extern BOOL append_log;
511         extern char *optarg;
512         /* shall I run as a daemon */
513         BOOL is_daemon = False;
514         BOOL interactive = False;
515         BOOL specified_logfile = False;
516         int opt;
517         pstring logfile;
518
519 #ifdef HAVE_SET_AUTH_PARAMETERS
520         set_auth_parameters(argc,argv);
521 #endif
522
523         /* this is for people who can't start the program correctly */
524         while (argc > 1 && (*argv[1] != '-')) {
525                 argv++;
526                 argc--;
527         }
528
529         while ( EOF != (opt = getopt(argc, argv, "O:l:s:d:Dp:h?Vaiof:")) )
530                 switch (opt)  {
531                 case 'O':
532                         pstrcpy(user_socket_options,optarg);
533                         break;
534
535                 case 's':
536                         pstrcpy(dyn_CONFIGFILE,optarg);
537                         break;
538
539                 case 'l':
540                         specified_logfile = True;
541                         slprintf(logfile, sizeof(logfile)-1, "%s/log.wrepld", optarg);
542                         lp_set_logfile(logfile);
543                         break;
544
545                 case 'a':
546                         append_log = True;
547                         break;
548
549                 case 'i':
550                         interactive = True;
551                         break;
552
553                 case 'o':
554                         append_log = False;
555                         break;
556
557                 case 'D':
558                         is_daemon = True;
559                         break;
560
561                 case 'd':
562                         if (*optarg == 'A')
563                                 DEBUGLEVEL = 10000;
564                         else
565                                 DEBUGLEVEL = atoi(optarg);
566                         break;
567
568                 case 'p':
569                         wins_port = atoi(optarg);
570                         break;
571
572                 case 'h':
573                 case '?':
574                         usage(argv[0]);
575                         exit(0);
576                         break;
577
578                 case 'V':
579                         d_printf("Version %s\n",VERSION);
580                         exit(0);
581                         break;
582                 default:
583                         DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
584                         usage(argv[0]);
585                         exit(1);
586                 }
587
588 #ifdef HAVE_SETLUID
589         /* needed for SecureWare on SCO */
590         setluid(0);
591 #endif
592
593         sec_init();
594
595         load_case_tables();
596
597         append_log = True;
598
599         if(!specified_logfile) {
600                 slprintf(logfile, sizeof(logfile)-1, "%s/log.wrepld",
601                          dyn_LOGFILEBASE);
602                 lp_set_logfile(logfile);
603         }
604
605         pstrcpy(remote_machine, "wrepld");
606
607         setup_logging(argv[0],interactive);
608
609         /* we want to re-seed early to prevent time delays causing
610            client problems at a later date. (tridge) */
611         generate_random_buffer(NULL, 0, False);
612
613         /* make absolutely sure we run as root - to handle cases where people
614            are crazy enough to have it setuid */
615
616         gain_root_privilege();
617         gain_root_group_privilege();
618
619         fault_setup((void (*)(void *))exit_server);
620         CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig);
621
622         /* we are never interested in SIGPIPE */
623         BlockSignals(True,SIGPIPE);
624
625 #if defined(SIGFPE)
626         /* we are never interested in SIGFPE */
627         BlockSignals(True,SIGFPE);
628 #endif
629
630 #if defined(SIGUSR2)
631         /* We are no longer interested in USR2 */
632         BlockSignals(True,SIGUSR2);
633 #endif
634
635         /* POSIX demands that signals are inherited. If the invoking process has
636          * these signals masked, we will have problems, as we won't recieve them. */
637         BlockSignals(False, SIGHUP);
638         BlockSignals(False, SIGUSR1);
639
640         /* we want total control over the permissions on created files,
641            so set our umask to 0 */
642         umask(0);
643
644         reopen_logs();
645
646         DEBUG(1,( "wrepld version %s started.\n", VERSION));
647         DEBUGADD(1,( "Copyright Andrew Tridgell and the Samba Team 1992-2002\n"));
648
649         DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
650                  (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
651
652         if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
653                 DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
654                 exit(1);
655         }
656
657         /*
658          * Do this before reload_services.
659          */
660
661         if (!reload_services(False))
662                 return(-1);     
663
664         init_structs();
665         
666 #ifdef WITH_PROFILE
667         if (!profile_setup(False)) {
668                 DEBUG(0,("ERROR: failed to setup profiling\n"));
669                 return -1;
670         }
671 #endif
672
673         fstrcpy(global_myworkgroup, lp_workgroup());
674
675         CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
676         
677         DEBUG(3,( "loaded services\n"));
678
679         if (!is_daemon && !is_a_socket(0)) {
680                 DEBUG(0,("standard input is not a socket, assuming -D option\n"));
681                 is_daemon = True;
682         }
683
684         if (is_daemon && !interactive) {
685                 DEBUG( 3, ( "Becoming a daemon.\n" ) );
686                 become_daemon();
687         }
688
689 #if HAVE_SETPGID
690         /*
691          * If we're interactive we want to set our own process group for
692          * signal management.
693          */
694         if (interactive)
695                 setpgid( (pid_t)0, (pid_t)0);
696 #endif
697
698         if (!directory_exist(lp_lockdir(), NULL)) {
699                 mkdir(lp_lockdir(), 0755);
700         }
701
702         if (is_daemon) {
703                 pidfile_create("wrepld");
704         }
705
706         if (!message_init()) {
707                 exit(1);
708         }
709
710         /* Initialise the memory context */
711         mem_ctx=talloc_init_named("wins repl talloc ctx");
712
713         /* initialise the global partners table */
714         partner_count=init_wins_partner_table();
715
716         /* We can only take signals in the select. */
717         BlockSignals( True, SIGTERM );
718
719         process();
720
721         exit_server("normal exit");
722         return(0);
723 }