~noskcaj/ubuntu/saucy/xinetd/2.3.15

« back to all changes in this revision

Viewing changes to xinetd/reconfig.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Seyrat
  • Date: 2004-04-18 13:33:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040418133357-czeqeju37433xvdd
Tags: upstream-2.3.13
ImportĀ upstreamĀ versionĀ 2.3.13

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (c) Copyright 1992 by Panagiotis Tsirigotis
 
3
 * (c) Sections Copyright 1998-2001 by Rob Braun
 
4
 * All rights reserved.  The file named COPYRIGHT specifies the terms 
 
5
 * and conditions for redistribution.
 
6
 */
 
7
 
 
8
 
 
9
#include "config.h"
 
10
#include <sys/types.h>
 
11
#include <sys/socket.h>
 
12
#include <syslog.h>
 
13
#include <signal.h>
 
14
#include <memory.h>
 
15
#include <stdlib.h>
 
16
#include <unistd.h>
 
17
#include <netinet/in.h>
 
18
#ifndef NO_RPC
 
19
 #ifdef HAVE_RPC_PMAP_CLNT_H
 
20
  #ifdef __sun
 
21
   #include <rpc/types.h>
 
22
   #include <rpc/auth.h>
 
23
  #endif
 
24
  #include <rpc/types.h>
 
25
  #include <rpc/xdr.h>
 
26
  #include <rpc/auth.h>
 
27
  #include <rpc/clnt.h>
 
28
  #include <rpc/pmap_clnt.h>
 
29
 #endif
 
30
 #include <rpc/rpc.h>
 
31
#endif
 
32
 
 
33
#include "reconfig.h"
 
34
#include "msg.h"
 
35
#include "sconf.h"
 
36
#include "conf.h"
 
37
#include "confparse.h"
 
38
#include "state.h"
 
39
#include "main.h"
 
40
#include "retry.h"
 
41
#include "logctl.h"
 
42
#include "options.h"
 
43
 
 
44
 
 
45
static status_e readjust(struct service *sp, 
 
46
                struct service_config **new_conf_ptr) ;
 
47
static void swap_defaults(struct configuration *new_conf) ;
 
48
static void close_default_log(struct configuration *confp, xlog_h def_log);
 
49
 
 
50
#define SWAP( x, y, temp )         (temp) = (x), (x) = (y), (y) = (temp)
 
51
 
 
52
 
 
53
/*
 
54
 * Reconfigure the server by rereading the configuration file.
 
55
 * Services may be added, deleted or have their attributes changed.
 
56
 * All syslog output uses the LOG_NOTICE priority level (except for
 
57
 * errors).
 
58
 */
 
59
void hard_reconfig( void )
 
60
{
 
61
   struct service            *osp ;
 
62
   struct service_config     *nscp ;
 
63
   struct configuration      new_conf ;
 
64
   psi_h                     iter ;
 
65
   unsigned                  new_services ;
 
66
   unsigned                  old_services      = 0 ;
 
67
   unsigned                  dropped_services   = 0 ;
 
68
   xlog_h                    def_log = DEFAULT_LOG( ps );
 
69
   const char               *func               = "hard_reconfig" ;
 
70
 
 
71
 
 
72
   msg( LOG_NOTICE, func, "Starting reconfiguration" ) ;
 
73
 
 
74
   if ( cnf_get( &new_conf ) == FAILED )
 
75
   {
 
76
      msg( LOG_WARNING, func, "reconfiguration failed" ) ;
 
77
      return ;
 
78
   }
 
79
 
 
80
   iter = psi_create( SERVICES( ps ) ) ;
 
81
   if ( iter == NULL )
 
82
   {
 
83
      out_of_memory( func ) ;
 
84
      cnf_free( &new_conf ) ;
 
85
      return ;
 
86
   }
 
87
 
 
88
   /* After this call, new_conf's defaults point to the old one's defaults */
 
89
   msg( LOG_NOTICE, func, "Swapping defaults" ) ;
 
90
   swap_defaults( &new_conf ) ;
 
91
 
 
92
   /*
 
93
    * Glossary:
 
94
    *      Sconf: service configuration
 
95
    *      Lconf: list of service configurations
 
96
    *
 
97
    * Iterate over all existing services. If the service is included in the 
 
98
    * new Lconf, readjust its attributes (as a side-effect, the new service 
 
99
    * Sconf is removed from the new Lconf).
 
100
    *   Services not in the new Lconf are deactivated.
 
101
    */
 
102
   for ( osp = SP( psi_start( iter ) ) ; osp ; osp = SP( psi_next( iter ) ) )
 
103
   {
 
104
      char *sid = SVC_ID( osp ) ;
 
105
      boolean_e drop_service ;
 
106
 
 
107
      /*
 
108
       * Check if this service is in the new Lconf
 
109
       * Notice that the service Sconf is removed from the new Lconf
 
110
       * if it is found there.
 
111
       */
 
112
      if (  (nscp = cnf_extract( &new_conf, SVC_CONF( osp ) )) )
 
113
      {
 
114
         /*
 
115
          * The first action of readjust is to swap the service configuration
 
116
          * with nscp. This is the reason for passing the address of nscp
 
117
          * (so that on return nscp will *always* point to the old service
 
118
          * configuration).
 
119
          */
 
120
         if ( readjust( osp, &nscp ) == OK )
 
121
         {
 
122
            old_services++ ;
 
123
            drop_service = NO ;
 
124
         }
 
125
         else   /* the readjustment failed */
 
126
            drop_service = YES ;
 
127
         sc_free( nscp ) ;
 
128
      }
 
129
      else
 
130
         drop_service = YES ;
 
131
 
 
132
      if ( drop_service == YES )
 
133
      {
 
134
         /*
 
135
          * Procedure for disabling a service:
 
136
          *
 
137
          *      a. Terminate running servers and cancel retry attempts, in case
 
138
          *         of reconfiguration
 
139
          *      b. Deactivate the service
 
140
          */
 
141
         terminate_servers( osp ) ;
 
142
         cancel_service_retries( osp ) ;
 
143
 
 
144
         /*
 
145
          * Deactivate the service; the service will be deleted only
 
146
          * if its reference count drops to 0.
 
147
          */
 
148
         svc_deactivate( osp ) ;
 
149
         msg( LOG_NOTICE, func, "service %s deactivated", sid ) ;
 
150
         if ( SVC_RELE( osp ) == 0 )
 
151
            psi_remove( iter ) ;
 
152
         else
 
153
            msg( LOG_ERR, func, "Errors deactivating service %s", sid ) ;
 
154
         dropped_services++ ;
 
155
      }
 
156
   }
 
157
 
 
158
   psi_destroy( iter ) ;
 
159
 
 
160
   /*
 
161
    * All services have terminated by now, so close the old common logfile.
 
162
    * remember that swap_defaults put the old defaults section in new_conf.
 
163
    */
 
164
   close_default_log( &new_conf, def_log ) ;
 
165
 
 
166
   /*
 
167
    * At this point the new Lconf only contains services that were not
 
168
    * in the old Lconf.
 
169
    */
 
170
   new_services = cnf_start_services( &new_conf ) ;
 
171
   msg( LOG_NOTICE, func,
 
172
      "Reconfigured: new=%d old=%d dropped=%d (services)",
 
173
         new_services, old_services, dropped_services ) ;
 
174
 
 
175
   if ( stayalive_option == 0 ) {
 
176
      if ( ps.rws.available_services == 0 )
 
177
      {
 
178
         msg( LOG_CRIT, func, "No available services. Exiting" );
 
179
         if ( ps.ros.pid_file ) {
 
180
            unlink(ps.ros.pid_file);
 
181
         }
 
182
         exit( 1 ) ;
 
183
      }
 
184
   }
 
185
 
 
186
   cnf_free( &new_conf ) ; 
 
187
}
 
188
 
 
189
 
 
190
static void swap_defaults( struct configuration *new_conf )
 
191
{
 
192
   struct service_config *temp ;
 
193
 
 
194
   DEFAULT_LOG_ERROR( ps ) = FALSE ;
 
195
   DEFAULT_LOG( ps ) = NULL ;
 
196
   SWAP( DEFAULTS( ps ), CNF_DEFAULTS( new_conf ), temp ) ;
 
197
}
 
198
 
 
199
 
 
200
static void close_default_log(struct configuration *confp, xlog_h def_log)
 
201
{
 
202
   /* Close the common log file, if one was specified */
 
203
   if ( def_log != NULL )
 
204
      log_end( SC_LOG( CNF_DEFAULTS( confp ) ), def_log) ;
 
205
}
 
206
 
 
207
 
 
208
static void sendsig( struct server *serp, int sig )
 
209
{
 
210
   char      *sid   = SVC_ID( SERVER_SERVICE( serp ) ) ;
 
211
   pid_t      pid   = SERVER_PID( serp ) ;
 
212
   const char *func = "sendsig" ;
 
213
 
 
214
   /*
 
215
    * Always use a positive pid, because of the semantics of kill(2)
 
216
    */
 
217
   if ( pid > 0 )
 
218
   {
 
219
      msg( LOG_WARNING, func, "Sending signal %d to %s server %d",
 
220
                                    sig, sid, pid ) ;
 
221
      kill( pid, sig ) ;
 
222
      if ((sig == SIGTERM) || (sig == SIGKILL))
 
223
      {
 
224
         int i, killed = 0;
 
225
         struct timeval tv;
 
226
 
 
227
         /*
 
228
          * We will try 4 seconds to TERM or KILL it. If it hasn't
 
229
          * responded by 2.5 seconds, we will send a KILL to hasten
 
230
          * its demise.
 
231
          */
 
232
 
 
233
         tv.tv_sec = 0;
 
234
         tv.tv_usec = 500000; /* half a second */
 
235
         for (i=0; i<8; i++)
 
236
         {
 
237
            int wret = waitpid(pid, NULL, WNOHANG);
 
238
            if (wret == pid)
 
239
            {
 
240
               killed = 1;
 
241
               break;
 
242
            }
 
243
         
 
244
            /* May not have responded to TERM, send a KILL */
 
245
            if ( i == 5)
 
246
               kill( pid, SIGKILL ) ;
 
247
                 
 
248
            /* Not dead yet, give some time. */
 
249
            select(0, NULL, NULL, NULL, &tv);
 
250
         }
 
251
 
 
252
         /*
 
253
          * If it didn't die, expect problems rebinding to this port if
 
254
          * a hard_reconfig is in process.
 
255
          */
 
256
         if (!killed)
 
257
            msg( LOG_ERR, func, "Server %d did not exit after SIGKILL", 
 
258
                  pid ) ;
 
259
         else {
 
260
            struct server *tmp_serp;
 
261
            if( (tmp_serp = server_lookup(pid)) != NULL ) {
 
262
               server_end(tmp_serp);
 
263
            }
 
264
         }
 
265
      }
 
266
   } 
 
267
   else if ( pid != 0 )
 
268
      msg( LOG_ERR, func, "Negative server pid = %d. Service %s", pid, sid ) ;
 
269
}
 
270
 
 
271
 
 
272
/*
 
273
 * Send signal sig to all running servers of service sp
 
274
 */
 
275
static void deliver_signal( struct service *sp, int sig )
 
276
{
 
277
   unsigned u ;
 
278
 
 
279
   for ( u = 0 ; u < pset_count( SERVERS( ps ) ) ; u++ )
 
280
   {
 
281
      struct server *serp ;
 
282
 
 
283
      serp = SERP( pset_pointer( SERVERS( ps ), u ) ) ;
 
284
      if ( SERVER_SERVICE( serp ) == sp )
 
285
         sendsig( serp, sig ) ;
 
286
   }
 
287
}
 
288
 
 
289
 
 
290
/*
 
291
 * Terminate all servers of the specified service
 
292
 */
 
293
void terminate_servers( struct service *sp )
 
294
{
 
295
   int sig = SC_IS_INTERNAL( SVC_CONF( sp ) ) ? SIGTERM : SIGKILL ;
 
296
 
 
297
   deliver_signal( sp, sig ) ;
 
298
}
 
299
 
 
300
 
 
301
static void stop_interception( struct service *sp )
 
302
{
 
303
   deliver_signal( sp, INTERCEPT_SIG ) ;
 
304
}
 
305
 
 
306
/*
 
307
 * Stop logging. svc_activate starts logging and will leak a file
 
308
 * descriptor and memory if this is not called prior.
 
309
 */
 
310
static void stop_log( struct service *sp, 
 
311
                              struct service_config *old_conf )
 
312
{
 
313
   struct log *lp = SC_LOG( old_conf ) ;
 
314
 
 
315
   if ( LOG_GET_TYPE( lp ) != L_NONE && SVC_IS_LOGGING( sp ) )
 
316
      log_end( lp, SVC_LOG( sp ) ) ;
 
317
   SVC_LOG( sp ) = NULL ;
 
318
}
 
319
 
 
320
/*
 
321
 * Stop any logging and restart if necessary.
 
322
 * Note that this has the side-effect of using the new common log
 
323
 * handle as it should.
 
324
 */
 
325
static status_e restart_log( struct service *sp, 
 
326
                              struct service_config *old_conf )
 
327
{
 
328
   stop_log( sp, old_conf ); 
 
329
   return( log_start( sp, &SVC_LOG( sp ) ) ) ;
 
330
}
 
331
 
 
332
 
 
333
/*
 
334
 * Unregister past versions, register new ones
 
335
 * We do it the dumb way: first unregister; then register
 
336
 * We try to be a little smart by checking if there has
 
337
 * been any change in version numbers (if not, we do nothing).
 
338
 * Also, we save the port number
 
339
 */
 
340
static status_e readjust_rpc_service( struct service_config *old_scp, 
 
341
                                       struct service_config *new_scp )
 
342
{
 
343
   unsigned long      vers ;
 
344
   uint16_t           port                  = SC_PORT( old_scp ) ;
 
345
   struct rpc_data   *new_rdp               = SC_RPCDATA( new_scp ) ;
 
346
   struct rpc_data   *old_rdp               = SC_RPCDATA( old_scp ) ;
 
347
   unsigned           registered_versions   = 0 ;
 
348
   const char        *func                  = "readjust_rpc_service" ;
 
349
 
 
350
#ifndef NO_RPC
 
351
   SC_PORT( new_scp ) = SC_PORT( old_scp ) ;
 
352
 
 
353
   if ( RD_MINVERS( old_rdp ) == RD_MINVERS( new_rdp ) &&
 
354
            RD_MAXVERS( old_rdp ) == RD_MAXVERS( new_rdp ) )
 
355
      return( OK ) ;
 
356
 
 
357
   for ( vers = RD_MINVERS( old_rdp ) ; vers <= RD_MAXVERS( old_rdp ) ; vers++ )
 
358
       (void) pmap_unset( RD_PROGNUM( old_rdp ), vers ) ;
 
359
 
 
360
   for ( vers = RD_MINVERS( new_rdp ) ; vers <= RD_MAXVERS( new_rdp ) ; vers++ )
 
361
      if ( pmap_set( RD_PROGNUM( new_rdp ),
 
362
                              vers, SC_PROTOVAL( new_scp ), port ) )
 
363
         registered_versions++ ;
 
364
      else
 
365
         msg( LOG_ERR, func, 
 
366
            "pmap_set failed. service=%s, program=%ld, version = %ld",
 
367
               SC_ID( new_scp ), RD_PROGNUM( new_rdp ), vers ) ;
 
368
 
 
369
   if ( registered_versions == 0 )
 
370
   {
 
371
      msg( LOG_ERR, func,
 
372
            "No versions registered for RPC service %s", SC_ID( new_scp ) ) ;
 
373
      /*
 
374
       * Avoid the pmap_unset
 
375
       */
 
376
      RD_MINVERS( new_rdp ) = RD_MAXVERS( new_rdp ) + 1 ;
 
377
      return( FAILED ) ;
 
378
   }
 
379
#endif   /* ! NO_RPC */
 
380
   return( OK ) ;
 
381
}
 
382
 
 
383
 
 
384
/*
 
385
 * Readjust service attributes. 
 
386
 *
 
387
 * We assume that the following attributes are the same:
 
388
 *         wait
 
389
 *         socket_type
 
390
 *         type
 
391
 *         protocol
 
392
 *
 
393
 * Readjustment happens in 3 steps:
 
394
 *      1) We swap the svc_conf fields
 
395
 *            This has the side-effect of free'ing the memory associated
 
396
 *            with the old service configuration when the new configuration
 
397
 *            is destroyed.
 
398
 *      2) We readjust the fields that require some action to be taken:
 
399
 *            RPC mapping
 
400
 *            log file open
 
401
 *      3) We update the address control fields.
 
402
 */
 
403
static status_e readjust( struct service *sp, 
 
404
                           struct service_config **new_conf_ptr )
 
405
{
 
406
   struct service_config   *temp_conf ;
 
407
   struct service_config   *old_conf   = SVC_CONF( sp ) ;
 
408
   struct service_config   *new_conf   = *new_conf_ptr ;
 
409
   char                    *sid        = SVC_ID( sp ) ;
 
410
   const char              *func       = "readjust" ;
 
411
 
 
412
   msg( LOG_NOTICE, func, "readjusting service %s", sid ) ;
 
413
 
 
414
   SWAP( SVC_CONF( sp ), *new_conf_ptr, temp_conf ) ;
 
415
 
 
416
   if ( SC_IS_RPC( old_conf ) &&
 
417
                  readjust_rpc_service( old_conf, new_conf ) == FAILED )
 
418
      return( FAILED ) ;
 
419
   
 
420
   /*
 
421
    * This is what happens if the INTERCEPT flag is toggled and an
 
422
    * interceptor is running:
 
423
    *
 
424
    * Case 1: clear->set
 
425
    *      Wait until the server dies (soft reconfig) or
 
426
    *      terminate the server (hard reconfig)
 
427
    *
 
428
    * Case 2: set->clear
 
429
    *    Send a signal to the interceptor to tell it to stop intercepting
 
430
    */
 
431
   if ( SC_IS_INTERCEPTED( old_conf ) != SC_IS_INTERCEPTED( new_conf ) )
 
432
   {
 
433
      if ( SC_IS_INTERCEPTED( new_conf ) )         /* case 1 */
 
434
         terminate_servers( sp ) ;
 
435
      else                                       /* case 2 */
 
436
      {
 
437
         stop_interception( sp ) ;
 
438
         msg( LOG_NOTICE, func, "Stopping interception for %s", sid ) ;
 
439
      }
 
440
   }
 
441
 
 
442
   /* 
 
443
    * See if the bind address was specified in both the old and new config,
 
444
    * then if it changed, readjust the service. The algorithm is check to 
 
445
    * see if they are in the same address family, if so start a simple 
 
446
    * comparison based on the address family. If IPv4, the addresses can be 
 
447
    * compared directly, otherwise use the IPv6 macro. If they are not the 
 
448
    * same, terminate & restart the service. 
 
449
    */
 
450
   if( (SC_BIND_ADDR(old_conf) != NULL) && (SC_BIND_ADDR(new_conf) != NULL) ) {
 
451
      int same = 0;
 
452
 
 
453
      if ( SA(SC_BIND_ADDR(old_conf))->sa_family == 
 
454
           SA(SC_BIND_ADDR(new_conf))->sa_family ) {
 
455
         if ( SA(SC_BIND_ADDR(old_conf))->sa_family == AF_INET ) {
 
456
            if ( SAIN(SC_BIND_ADDR(old_conf))->sin_addr.s_addr == 
 
457
                 SAIN(SC_BIND_ADDR(new_conf))->sin_addr.s_addr)
 
458
               same = 1;
 
459
         }
 
460
         else if ( IN6_ARE_ADDR_EQUAL(
 
461
                  &SAIN6(SC_BIND_ADDR(old_conf))->sin6_addr, 
 
462
                  &SAIN6(SC_BIND_ADDR(new_conf))->sin6_addr) )
 
463
            same = 1;
 
464
      }
 
465
      
 
466
      if ( !same ) {
 
467
         terminate_servers( sp );
 
468
         svc_deactivate( sp );
 
469
         stop_log( sp, old_conf ); /* svc_activate re-starts logging */
 
470
         svc_activate( sp );
 
471
         return OK;
 
472
      }
 
473
   }
 
474
 
 
475
   /* If the service didn't have a bind address before, but does now,
 
476
    * make sure the new bind directive takes effect.
 
477
    */
 
478
   if( (SC_BIND_ADDR(old_conf) == NULL) && (SC_BIND_ADDR(new_conf) != NULL) ) {
 
479
      terminate_servers( sp );
 
480
      svc_deactivate(sp);
 
481
      stop_log( sp, old_conf ); /* svc_activate re-starts logging */
 
482
      svc_activate(sp);
 
483
      return OK;
 
484
   }
 
485
 
 
486
   if( (SC_IPV4(old_conf) && SC_IPV6(new_conf)) || 
 
487
         (SC_IPV6(old_conf) && SC_IPV4(new_conf)) ) {
 
488
      terminate_servers( sp );
 
489
      svc_deactivate(sp);
 
490
      stop_log( sp, old_conf ); /* svc_activate re-starts logging */
 
491
      svc_activate(sp);
 
492
      return OK;
 
493
   }
 
494
 
 
495
   return( restart_log( sp, old_conf ) ) ;
 
496
}
 
497