make the echo'ed command match the actual command run.
[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(5,("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         struct BUFFER inbuf;
308         ssize_t len=0;
309         size_t total=0;  
310         ssize_t ret;
311         BOOL ok = False;
312
313         inbuf.buffer=NULL;
314         inbuf.length=0;
315         inbuf.offset=0;
316
317         if(!grow_buffer(&inbuf, 4))
318                 return NULL;
319
320         ok = (read(fd, inbuf.buffer,4) == 4);
321         if (!ok)
322                 return NULL;
323         len = smb_len(inbuf.buffer);
324
325         if (len<=0)
326                 return NULL;
327
328         if(!grow_buffer(&inbuf, len))
329                 return NULL;
330                 
331         while (total < len) {
332                 ret = read(fd, inbuf.buffer + total + 4, len - total);
333                 if (ret == 0) {
334                         DEBUG(10,("read_socket_data: recv of %d returned 0. Error = %s\n", (int)(len - total), strerror(errno) ));
335                         return NULL;
336                 }
337                 if (ret == -1) {
338                         DEBUG(0,("read_socket_data: recv failure for %d. Error = %s\n", (int)(len - total), strerror(errno) ));
339                         return NULL;
340                 }
341                 total += ret;
342         }
343
344         q = (GENERIC_PACKET *)talloc(mem_ctx, sizeof(GENERIC_PACKET));
345         p = (struct wins_packet_struct *)talloc(mem_ctx, sizeof(*p));
346         if (q==NULL || p==NULL)
347                 return NULL;
348
349         decode_generic_packet(&inbuf, q);
350
351         q->fd=fd;
352         
353         p->next = NULL;
354         p->prev = NULL;
355         p->stop_packet = False;
356         p->timestamp = time(NULL);
357         p->fd = fd;
358         p->packet=q;
359         
360         return p;
361 }
362
363 static struct wins_packet_struct *packet_queue = NULL;
364
365 /*******************************************************************
366   Queue a packet into a packet queue
367 ******************************************************************/
368 static void queue_packet(struct wins_packet_struct *packet)
369 {
370         struct wins_packet_struct *p;
371
372         if (!packet_queue) {
373                 packet->prev = NULL;
374                 packet->next = NULL;
375                 packet_queue = packet;
376                 return;
377         }
378   
379         /* find the bottom */
380         for (p=packet_queue;p->next;p=p->next) 
381                 ;
382
383         p->next = packet;
384         packet->next = NULL;
385         packet->prev = p;
386 }
387
388 /****************************************************************************
389   Listens for NMB or DGRAM packets, and queues them.
390   return True if the socket is dead
391 ***************************************************************************/
392 static BOOL listen_for_wins_packets(void)
393 {
394         int num_interfaces = iface_count();
395         fd_set fds;
396         int i, num, s, new_s;
397         struct timeval timeout;
398
399         if(listen_set == NULL) {
400                 if(!create_listen_fdset()) {
401                         DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
402                         return True;
403                 }
404         }
405
406         memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
407
408         timeout.tv_sec = NMBD_SELECT_LOOP;
409         timeout.tv_usec = 0;
410
411         /* Prepare for the select - allow certain signals. */
412
413         BlockSignals(False, SIGTERM);
414
415         num = sys_select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
416
417         /* We can only take signals when we are in the select - block them again here. */
418
419         BlockSignals(True, SIGTERM);
420
421         if(num == -1)
422                 return False;
423
424         for (; num > 0; num--) {
425                 s = -1;
426                 /* check the sockets we are only listening on, waiting to accept */             
427                 for (i=0; i<num_interfaces; i++) {
428                         struct sockaddr addr;
429                         socklen_t in_addrlen = sizeof(addr);
430                 
431                         if(FD_ISSET(sock_array[i], &fds)) {
432                                 s = sock_array[i];
433                                 /* Clear this so we don't look at it again. */
434                                 FD_CLR(sock_array[i], &fds);
435
436                                 /* accept and add the new socket to the listen set */
437                                 new_s=accept(s, &addr, &in_addrlen);
438
439                                 if (new_s < 0)
440                                         continue;
441         
442                                 DEBUG(5,("listen_for_wins_packets: new connection, old: %d, new : %d\n", s, new_s));
443                                 
444                                 set_socket_options(new_s, "SO_KEEPALIVE");
445                                 set_socket_options(new_s, user_socket_options);
446                                 FD_SET(new_s, listen_set);
447                                 add_fd_to_sock_array(new_s);
448                         }
449                 }
450
451                 /*
452                  * check for the sockets we are waiting data from
453                  * either client sending datas
454                  * or reply to our requests
455                  */
456                 for (i=num_interfaces; i<listen_number; i++) {
457                         if(FD_ISSET(sock_array[i], &fds)) {
458                                 struct wins_packet_struct *packet = read_wins_packet(sock_array[i], timeout.tv_sec);
459                                 if (packet) {
460                                         packet->fd = sock_array[i];
461                                         queue_packet(packet);
462                                 }
463                                 DEBUG(2,("listen_for_wins_packets: some data on fd %d\n", sock_array[i]));
464                                 FD_CLR(sock_array[i], &fds);
465                                 break;
466                         }
467         
468                 }
469
470         }
471
472         return False;
473 }
474
475
476 /*******************************************************************
477   Run elements off the packet queue till its empty
478 ******************************************************************/
479
480 static void run_wins_packet_queue(void)
481 {
482         struct wins_packet_struct *p;
483
484         while ((p = packet_queue)) {
485                 packet_queue = p->next;
486                 if (packet_queue)
487                         packet_queue->prev = NULL;
488                 p->next = p->prev = NULL;
489
490                 construct_reply(p);
491
492                 /* if it was a stop assoc, close the connection */
493                 if (p->stop_packet) {
494                         FD_CLR(p->fd, listen_set);
495                         remove_fd_from_sock_array(p->fd);
496                         close(p->fd);
497                 }
498         }
499
500
501 /**************************************************************************** **
502  The main select loop.
503  **************************************************************************** */
504 static void process(void)
505 {
506
507         while( True ) {
508                 time_t t = time(NULL);
509
510                 /* check for internal messages */
511                 message_dispatch();
512
513                 if(listen_for_wins_packets())
514                         return;
515
516                 run_wins_packet_queue();
517
518                 run_pull_replication(t);
519                 
520                 run_push_replication(t);
521                 
522                 /*
523                  * Reload the services file if we got a sighup.
524                  */
525
526                 if(reload_after_sighup) {
527                         reload_services( True );
528                         reopen_logs();
529                         reload_after_sighup = False;
530                 }
531
532                 /* free temp memory */
533                 talloc_destroy_pool(mem_ctx);
534
535                 /* free up temp memory */
536                 lp_talloc_free();
537         }
538 } /* process */
539
540 /****************************************************************************
541   main program
542 ****************************************************************************/
543  int main(int argc,char *argv[])
544 {
545         extern BOOL append_log;
546         extern char *optarg;
547         /* shall I run as a daemon */
548         BOOL is_daemon = False;
549         BOOL interactive = False;
550         BOOL specified_logfile = False;
551         int opt;
552         pstring logfile;
553
554 #ifdef HAVE_SET_AUTH_PARAMETERS
555         set_auth_parameters(argc,argv);
556 #endif
557
558         /* this is for people who can't start the program correctly */
559         while (argc > 1 && (*argv[1] != '-')) {
560                 argv++;
561                 argc--;
562         }
563
564         while ( EOF != (opt = getopt(argc, argv, "O:l:s:d:Dp:h?Vaiof:")) )
565                 switch (opt)  {
566                 case 'O':
567                         pstrcpy(user_socket_options,optarg);
568                         break;
569
570                 case 's':
571                         pstrcpy(dyn_CONFIGFILE,optarg);
572                         break;
573
574                 case 'l':
575                         specified_logfile = True;
576                         slprintf(logfile, sizeof(logfile)-1, "%s/log.wrepld", optarg);
577                         lp_set_logfile(logfile);
578                         break;
579
580                 case 'a':
581                         append_log = True;
582                         break;
583
584                 case 'i':
585                         interactive = True;
586                         break;
587
588                 case 'o':
589                         append_log = False;
590                         break;
591
592                 case 'D':
593                         is_daemon = True;
594                         break;
595
596                 case 'd':
597                         if (*optarg == 'A')
598                                 DEBUGLEVEL = 10000;
599                         else
600                                 DEBUGLEVEL = atoi(optarg);
601                         break;
602
603                 case 'p':
604                         wins_port = atoi(optarg);
605                         break;
606
607                 case 'h':
608                 case '?':
609                         usage(argv[0]);
610                         exit(0);
611                         break;
612
613                 case 'V':
614                         d_printf("Version %s\n",VERSION);
615                         exit(0);
616                         break;
617                 default:
618                         DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
619                         usage(argv[0]);
620                         exit(1);
621                 }
622
623 #ifdef HAVE_SETLUID
624         /* needed for SecureWare on SCO */
625         setluid(0);
626 #endif
627
628         sec_init();
629
630         load_case_tables();
631
632         append_log = True;
633
634         if(!specified_logfile) {
635                 slprintf(logfile, sizeof(logfile)-1, "%s/log.wrepld",
636                          dyn_LOGFILEBASE);
637                 lp_set_logfile(logfile);
638         }
639
640         pstrcpy(remote_machine, "wrepld");
641
642         setup_logging(argv[0],interactive);
643
644         /* we want to re-seed early to prevent time delays causing
645            client problems at a later date. (tridge) */
646         generate_random_buffer(NULL, 0, False);
647
648         /* make absolutely sure we run as root - to handle cases where people
649            are crazy enough to have it setuid */
650
651         gain_root_privilege();
652         gain_root_group_privilege();
653
654         fault_setup((void (*)(void *))exit_server);
655         CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig);
656
657         /* we are never interested in SIGPIPE */
658         BlockSignals(True,SIGPIPE);
659
660 #if defined(SIGFPE)
661         /* we are never interested in SIGFPE */
662         BlockSignals(True,SIGFPE);
663 #endif
664
665 #if defined(SIGUSR2)
666         /* We are no longer interested in USR2 */
667         BlockSignals(True,SIGUSR2);
668 #endif
669
670         /* POSIX demands that signals are inherited. If the invoking process has
671          * these signals masked, we will have problems, as we won't recieve them. */
672         BlockSignals(False, SIGHUP);
673         BlockSignals(False, SIGUSR1);
674
675         /* we want total control over the permissions on created files,
676            so set our umask to 0 */
677         umask(0);
678
679         reopen_logs();
680
681         DEBUG(1,( "wrepld version %s started.\n", VERSION));
682         DEBUGADD(1,( "Copyright Andrew Tridgell and the Samba Team 1992-2002\n"));
683
684         DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
685                  (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
686
687         if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
688                 DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
689                 exit(1);
690         }
691
692         /*
693          * Do this before reload_services.
694          */
695
696         if (!reload_services(False))
697                 return(-1);     
698
699         init_structs();
700         
701 #ifdef WITH_PROFILE
702         if (!profile_setup(False)) {
703                 DEBUG(0,("ERROR: failed to setup profiling\n"));
704                 return -1;
705         }
706 #endif
707
708         fstrcpy(global_myworkgroup, lp_workgroup());
709
710         CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
711         
712         DEBUG(3,( "loaded services\n"));
713
714         if (!is_daemon && !is_a_socket(0)) {
715                 DEBUG(0,("standard input is not a socket, assuming -D option\n"));
716                 is_daemon = True;
717         }
718
719         if (is_daemon && !interactive) {
720                 DEBUG( 3, ( "Becoming a daemon.\n" ) );
721                 become_daemon();
722         }
723
724 #if HAVE_SETPGID
725         /*
726          * If we're interactive we want to set our own process group for
727          * signal management.
728          */
729         if (interactive)
730                 setpgid( (pid_t)0, (pid_t)0);
731 #endif
732
733         if (!directory_exist(lp_lockdir(), NULL)) {
734                 mkdir(lp_lockdir(), 0755);
735         }
736
737         if (is_daemon) {
738                 pidfile_create("wrepld");
739         }
740
741         if (!message_init()) {
742                 exit(1);
743         }
744
745         /* Initialise the memory context */
746         mem_ctx=talloc_init_named("wins repl talloc ctx");
747
748         /* initialise the global partners table */
749         partner_count=init_wins_partner_table();
750
751         /* We can only take signals in the select. */
752         BlockSignals( True, SIGTERM );
753
754         process();
755
756         exit_server("normal exit");
757         return(0);
758 }