fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / child.c
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 <sys/time.h>
13 #ifdef HAVE_SYS_RESOURCE_H
14 #include <sys/resource.h>
15 #endif
16 #include <sys/wait.h>
17 #include <sys/stat.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <syslog.h>
21 #include <errno.h>
22 #include <pwd.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #if defined (HAVE_GRP_H)
29 #include <grp.h>
30 #endif
31 #ifdef HAVE_NETDB_H
32 #include <netdb.h>
33 #endif
34
35 #include "str.h"
36 #include "child.h"
37 #include "sconf.h"
38 #include "msg.h"
39 #include "main.h"
40 #include "xconfig.h"
41 #include "ident.h"
42 #include "sconst.h"
43 #include "signals.h"
44 #include "options.h"
45 #include "redirect.h"
46
47 /*
48  * This function is running in the new process
49  */
50 void exec_server( const struct server *serp )
51 {
52    const struct service_config *scp = SVC_CONF( SERVER_SERVICE( serp ) ) ;
53    struct rlimit rl ;
54    int fd ;
55    int descriptor = SERVER_FD( serp ) ;
56    const char *server = SC_SERVER( scp ) ;
57    const char *func = "exec_server" ;
58
59    /*
60     * The following code solves a problem with post-version-4.3
61     * Ultrix systems (the bug was reported, and a fix was provided by
62     * doug@seas.smu.edu; a slightly modified version of this
63     * fix is included here).
64     *
65     * If this is a 'nowait' service, we pass the service descriptor
66     * to the server. Note that we have set the close-on-exec flag
67     * on all service descriptors. It is unclear whether the dup2()
68     * will create a descriptor with the close-on-exec flag set,
69     * so we explicitly clear the flag (since we are doing this
70     * after the fork, it does not affect the descriptor of the
71     * parent process).
72     */
73    if ( fcntl( descriptor, F_SETFD, 0 ) == -1 )
74       msg( LOG_WARNING, func,
75          "fcntl( %d, clear close-on-exec ) failed: %m", descriptor ) ;
76
77    if ( debug.on )
78       msg( LOG_DEBUG, func, "duping %d", descriptor ) ;
79
80    /*
81     * If server_loguser flag is on, then syslog may have opened fd 0, 1, or
82     * 2. We call msg_suspend() now so that the logging system doesn't use 
83     * the dup'ed descriptor.
84     */
85
86    msg_suspend() ;
87
88    for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ )
89    {
90       if ( dup2( descriptor, fd ) == -1 )
91       {
92          msg_resume();
93          msg( LOG_ERR, func,
94                "dup2( %d, %d ) failed: %m", descriptor, fd ) ;
95          _exit( 1 ) ;
96       }
97    }
98
99
100 #ifdef RLIMIT_NOFILE
101    rl.rlim_max = ps.ros.orig_max_descriptors ;
102    rl.rlim_cur = ps.ros.max_descriptors ;
103    (void) setrlimit( RLIMIT_NOFILE, &rl ) ;
104 #endif
105 #ifdef RLIMIT_AS
106    if (SC_RLIM_AS (scp))
107    {
108       rl.rlim_cur = SC_RLIM_AS( scp );
109       rl.rlim_max = SC_RLIM_AS( scp );
110       (void) setrlimit( RLIMIT_AS, &rl );
111    }
112 #endif
113 #ifdef RLIMIT_CPU
114    if (SC_RLIM_CPU (scp))
115    {
116       rl.rlim_cur = SC_RLIM_CPU( scp );
117       rl.rlim_max = SC_RLIM_CPU( scp );
118       (void) setrlimit( RLIMIT_CPU, &rl );
119    }
120 #endif
121 #ifdef RLIMIT_DATA
122    if (SC_RLIM_DATA (scp))
123    {
124       rl.rlim_cur = SC_RLIM_DATA( scp );
125       rl.rlim_max = SC_RLIM_DATA( scp );
126       (void) setrlimit( RLIMIT_DATA, &rl );
127    }
128 #endif
129 #ifdef RLIMIT_RSS
130    if (SC_RLIM_RSS (scp))
131    {
132       rl.rlim_cur = SC_RLIM_RSS( scp );
133       rl.rlim_max = SC_RLIM_RSS( scp );
134       (void) setrlimit( RLIMIT_RSS, &rl );
135    }
136 #endif
137 #ifdef RLIMIT_STACK
138    if (SC_RLIM_STACK (scp))
139    {
140       rl.rlim_cur = SC_RLIM_STACK( scp );
141       rl.rlim_max = SC_RLIM_STACK( scp );
142       (void) setrlimit( RLIMIT_STACK, &rl );
143    }
144 #endif
145
146    (void) Sclose( descriptor ) ;
147
148 #ifndef solaris
149 #if !defined(HAVE_SETSID)
150    msg_resume();
151 #endif
152    no_control_tty() ;
153 #if !defined(HAVE_SETSID)
154    msg_suspend();
155 #endif
156 #endif
157
158    (void) execve( server, SC_SERVER_ARGV( scp ),
159              env_getvars( SC_ENV( scp )->env_handle ) ) ;
160
161    /*
162     * The exec failed. Log the error and exit.
163     */
164    msg_resume() ;
165    msg( LOG_ERR, func, "execv( %s ) failed: %m", server ) ;
166    _exit( 0 ) ;
167 }
168
169
170 /*
171  * Rename this process by changing the ps.ros.Argv vector
172  * Try to put the name of the service in ps.ros.Argv[0], Argv[1]
173  * until either the service name is exhausted or we run out
174  * of ps.ros.Argv's. 
175  * The rest of ps.ros.Argv is cleared to spaces
176  */
177 static void rename_process( const char *name )
178 {
179    const char *from = name ;
180    char *to = ps.ros.Argv[ 0 ] ;
181    int tmp_index = 1 ;
182
183    while ( *from != NUL )
184    {
185       if ( *to != NUL )
186          *to++ = *from++ ;
187       else
188          if ( tmp_index < ps.ros.Argc )
189             to = ps.ros.Argv[ tmp_index++ ] ;
190          else
191             break ;
192    }
193    str_fill( to, ' ' ) ;
194    while ( tmp_index < ps.ros.Argc )
195       str_fill( ps.ros.Argv[ tmp_index++ ], ' ' ) ;
196 }
197
198
199 static void set_credentials( const struct service_config *scp )
200 {
201    const char *func = "set_credentials" ;
202
203    if ( SC_SPECIFIED( scp, A_GROUP ) || SC_SPECIFIED( scp, A_USER ) ) {
204       if ( ps.ros.is_superuser )
205       {
206          gid_t gid = SC_GETGID( scp ) ;
207
208          if ( setgid( gid ) == -1 )
209          {
210             msg( LOG_ERR, func, "setgid failed: %m" ) ;
211             _exit( 1 ) ;
212          }
213
214 #ifndef NO_INITGROUPS
215          /*
216           * Bug discovered by maf+@osu.edu (a bug fix was also provided;
217           * a slightly modified version is included here):
218           *      initgroups was not being invoked to set the remaining
219           *      groups appropriately
220           */
221          /* Solar Designer's groups fix */
222          if ( SC_SPECIFIED( scp, A_USER ) && SC_SPECIFIED( scp, A_GROUPS ) &&
223             SC_GROUPS(scp) == YES )
224          {
225             struct passwd *pwd ;
226
227             /*
228              * Invoke getpwuid() to get the user's name.
229              *
230              * XXX:   we should not need to invoke getpwuid(); we should
231              *         remember the user name in the configuration file.
232              */
233             if ( ( pwd = getpwuid( SC_UID( scp ) ) ) == NULL )
234             {
235                msg( LOG_ERR, func, "getpwuid( %d ) (service=%s) failed: %m",
236                   SC_UID( scp ), SC_ID( scp ) ) ;
237                _exit( 1 ) ;
238             }
239             str_fill( pwd->pw_passwd, ' ' );
240
241             if ( initgroups( pwd->pw_name, pwd->pw_gid ) == -1 )
242             {
243                msg( LOG_ERR, func, "initgroups( %s, %d ) failed: %m",
244                   pwd->pw_name, pwd->pw_gid ) ;
245                _exit( 1 ) ;
246             }
247          }
248          else
249          {
250             if ( setgroups( 0, NULL ) )
251             {
252                msg( LOG_ERR, func, "setgroups( 0, NULL ) failed: %m" ) ;
253                msg( LOG_ERR, func, "Your system may require that 'groups = yes' be defined for this service: %s", SC_NAME(scp));
254                _exit( 1 ) ;
255             }
256          }
257 #endif   /* ! NO_INITGROUPS */
258       }
259    }
260
261    if ( SC_SPECIFIED( scp, A_USER ) ) {
262          if ( setuid( SC_UID( scp ) ) == -1 )
263          {
264             msg( LOG_ERR, func, "setuid failed: %m" ) ;
265             _exit( 1 ) ;
266          }
267       }
268
269    if ( SC_SPECIFIED( scp, A_UMASK ) ) 
270       umask(SC_UMASK(scp));
271 }
272
273
274
275 /*
276  * This function is invoked in a forked process to run a server. 
277  * If the service is internal the appropriate function is invoked
278  * otherwise the server program is exec'ed.
279  * This function also logs the remote user id if appropriate
280  */
281 void child_process( struct server *serp )
282 {
283    struct service          *sp  = SERVER_SERVICE( serp ) ;
284    connection_s            *cp  = SERVER_CONNECTION( serp ) ;
285    struct service_config   *scp = SVC_CONF( sp ) ;
286    const char              *func = "child_process" ;
287
288    signal_default_state();
289
290    if ((signals_pending[0] >= 0 && Sclose(signals_pending[0])) ||
291        (signals_pending[1] >= 0 && Sclose(signals_pending[1])))
292    {
293       msg(LOG_ERR, func, "Failed to close the signal pipe: %m");
294       _exit(1);
295    }
296    signals_pending[0] = -1;
297    signals_pending[1] = -1;
298
299    Sclose(0);
300    Sclose(1);
301    Sclose(2);
302
303
304 #ifdef DEBUG_SERVER
305    if ( debug.on )
306    {
307       msg( LOG_DEBUG, func, "Process %d is sleeping", getpid() ) ;
308       sleep( 10 ) ;
309    }
310 #endif
311
312    if ( ! SC_IS_INTERCEPTED( scp ) )
313    {
314       set_credentials( scp ) ;
315       if ( SC_SPECIFIED( scp, A_NICE ) )
316          (void) nice( SC_NICE( scp ) ) ;
317    }
318
319    if ( svc_child_access_control(sp, cp) != OK )
320       exit(0);
321
322    if ( SERVER_LOGUSER( serp ) )
323    {
324       unsigned   timeout ;
325       idresult_e result ;
326       
327       /*
328        * We use LOGUSER_SUCCESS_TIMEOUT unless the service requires
329        * identification, in which case we use an infinite timeout
330        */
331       timeout = SC_MUST_IDENTIFY( scp ) ? 0 : LOGUSER_SUCCESS_TIMEOUT ;
332       result = log_remote_user( serp, timeout ) ;
333
334       if ( result != IDR_OK && SC_MUST_IDENTIFY( scp ) )
335       {
336          svc_logprint( sp, NOID_ENTRY, "%s %s",
337                   conn_addrstr( SERVER_CONNECTION( serp ) ),
338                      idresult_explain( result ) ) ;
339          _exit( 0 ) ;
340       }
341    }
342
343
344    /* this is where the server gets executed  -bbraun */
345    if ( ! SC_IS_INTERNAL( scp ) )
346    {
347       if( SC_REDIR_ADDR(scp) != NULL )
348       {
349          redir_handler( serp );
350       }
351       else
352       {
353 #if defined(HAVE_SETENV)
354          char buff[1024];
355
356          strx_sprint(buff, sizeof(buff)-1, "REMOTE_HOST=%s", conn_addrstr(cp));
357          if( env_addstr(SC_ENV(scp)->env_handle, buff) != ENV_OK ) {
358             msg( LOG_ERR, func, "Error adding REMOTE_HOST variable for %s: %m", SC_NAME(scp) );
359             _exit( 1 ) ;
360          }
361 #endif
362          exec_server( serp ) ;
363       }
364    }
365    else
366    {
367       char name[ 180 ] ;
368       /*
369        * We don't bother to disassociate from the controlling terminal
370        *   (we have a controlling terminal only if debug.on is TRUE)
371        *
372        * Also, for interceptor processes, we give them the name:
373        *            <program_name> <service-id> interceptor
374        */
375       if ( SC_IS_INTERCEPTED( scp ) )
376          strx_print( INT_NULL, name, sizeof( name ) - 1,
377                            "%s %s interceptor", program_name, SC_ID( scp ) ) ;
378       else
379       {
380          int namelen = sizeof( name ) - 1 ;      /* leave space for the NUL */
381          char host[NI_MAXHOST];
382          size_t hostlen = NI_MAXHOST;
383          socklen_t addrlen = 0;
384          union xsockaddr *sinp = CONN_XADDRESS(SERVER_CONNECTION(serp));
385          int len;
386
387          if( sinp == NULL )
388             exit(0);
389
390          if( SC_IPV6(scp) ) addrlen = sizeof(struct sockaddr_in6);
391          else if( SC_IPV4(scp) ) addrlen = sizeof(struct sockaddr_in);
392
393          len = strx_nprint(name, namelen, "(%s service) %s", program_name,
394             SC_ID( scp ) ) ;
395
396          if( getnameinfo( SA(sinp), addrlen, host, hostlen, NULL, 0, 0) != 0 )
397                strcpy(host, "unknown");
398
399          if ( SC_IPV6(scp) && SC_ACCEPTS_CONNECTIONS( scp ) && 
400                !IN6_IS_ADDR_UNSPECIFIED(&sinp->sa_in6.sin6_addr) )
401             strx_print( INT_NULL, &name[ len ], namelen - len, " %s" , host ) ;
402          if ( SC_IPV4(scp) && SC_ACCEPTS_CONNECTIONS( scp ) )
403             strx_print( INT_NULL, &name[ len ], namelen - len, " %s", host ) ;
404       }
405       rename_process( name ) ;
406       SVC_INTERNAL( sp, serp ) ;
407    }
408    _exit( 0 ) ;
409    /* NOTREACHED */
410 }
411
412
413 /*
414  * This function is invoked when a SIGCLD is received
415  */
416 void child_exit(void)
417 {
418    const char *func = "child_exit" ;
419
420    for ( ;; )         /* Find all children that exited */
421    {
422       int status ;
423       pid_t pid ;
424       struct server *serp ;
425       
426 #ifdef HAVE_WAITPID
427       pid = waitpid( -1, &status, WNOHANG ) ;
428 #else
429 #if defined( sun ) && defined( lint )
430       pid = wait3( (union wait *)&status, WNOHANG, RUSAGE_NULL ) ;
431 #else
432       pid = wait3( &status, WNOHANG, RUSAGE_NULL ) ;
433 #endif
434 #endif
435
436       if ( debug.on )
437 #ifdef HAVE_WAITPID
438          msg( LOG_DEBUG, func, "waitpid returned = %d", pid ) ;
439 #else
440          msg( LOG_DEBUG, func, "wait3 returned = %d", pid ) ;
441 #endif
442       
443       if ( pid == -1 ) {
444          if ( errno == EINTR )
445             continue ;
446          else
447             break ;
448       }
449
450       if ( pid == 0 )
451          break ;
452       
453       if ( ( serp = server_lookup( pid ) ) != NULL )
454       {
455          SERVER_EXITSTATUS(serp) = status ;
456          server_end( serp ) ;
457       }
458       else
459          msg( LOG_NOTICE, func, "unknown child process %d %s", pid,
460             PROC_STOPPED( status ) ? "stopped" : "died" ) ;
461    }
462 }
463