48e9615eab7851f82c0f0899d83e76cea0ba4925
[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    int                     fd, null_fd;
288
289    signal_default_state();
290
291    if ((signals_pending[0] >= 0 && Sclose(signals_pending[0])) ||
292        (signals_pending[1] >= 0 && Sclose(signals_pending[1])))
293    {
294       msg(LOG_ERR, func, "Failed to close the signal pipe: %m");
295       _exit(1);
296    }
297    signals_pending[0] = -1;
298    signals_pending[1] = -1;
299
300    if ( ( null_fd = open( "/dev/null", O_RDONLY ) ) == -1 )
301    {
302       msg( LOG_ERR, func, "open('/dev/null') failed: %m") ;
303       _exit( 1 ) ;
304    }
305
306    for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ )
307    {
308       if ( fd != null_fd && dup2( null_fd, fd ) == -1 )
309       {
310          msg( LOG_ERR, func, "dup2(%d, %d) failed: %m") ;
311          _exit( 1 ) ;
312       }
313    }
314    if ( null_fd > MAX_PASS_FD )
315       (void) Sclose( null_fd ) ;
316
317
318 #ifdef DEBUG_SERVER
319    if ( debug.on )
320    {
321       msg( LOG_DEBUG, func, "Process %d is sleeping", getpid() ) ;
322       sleep( 10 ) ;
323    }
324 #endif
325
326    if ( ! SC_IS_INTERCEPTED( scp ) )
327    {
328       set_credentials( scp ) ;
329       if ( SC_SPECIFIED( scp, A_NICE ) )
330          (void) nice( SC_NICE( scp ) ) ;
331    }
332
333    if ( svc_child_access_control(sp, cp) != OK )
334       exit(0);
335
336    if ( SERVER_LOGUSER( serp ) )
337    {
338       unsigned   timeout ;
339       idresult_e result ;
340       
341       /*
342        * We use LOGUSER_SUCCESS_TIMEOUT unless the service requires
343        * identification, in which case we use an infinite timeout
344        */
345       timeout = SC_MUST_IDENTIFY( scp ) ? 0 : LOGUSER_SUCCESS_TIMEOUT ;
346       result = log_remote_user( serp, timeout ) ;
347
348       if ( result != IDR_OK && SC_MUST_IDENTIFY( scp ) )
349       {
350          svc_logprint( sp, NOID_ENTRY, "%s %s",
351                   conn_addrstr( SERVER_CONNECTION( serp ) ),
352                      idresult_explain( result ) ) ;
353          _exit( 0 ) ;
354       }
355    }
356
357
358    /* this is where the server gets executed  -bbraun */
359    if ( ! SC_IS_INTERNAL( scp ) )
360    {
361       if( SC_REDIR_ADDR(scp) != NULL )
362       {
363          redir_handler( serp );
364       }
365       else
366       {
367 #if defined(HAVE_SETENV)
368          char buff[1024];
369
370          strx_sprint(buff, sizeof(buff)-1, "REMOTE_HOST=%s", conn_addrstr(cp));
371          if( env_addstr(SC_ENV(scp)->env_handle, buff) != ENV_OK ) {
372             msg( LOG_ERR, func, "Error adding REMOTE_HOST variable for %s: %m", SC_NAME(scp) );
373             _exit( 1 ) ;
374          }
375 #endif
376          exec_server( serp ) ;
377       }
378    }
379    else
380    {
381       char name[ 180 ] ;
382       /*
383        * We don't bother to disassociate from the controlling terminal
384        *   (we have a controlling terminal only if debug.on is TRUE)
385        *
386        * Also, for interceptor processes, we give them the name:
387        *            <program_name> <service-id> interceptor
388        */
389       if ( SC_IS_INTERCEPTED( scp ) )
390          strx_print( INT_NULL, name, sizeof( name ) - 1,
391                            "%s %s interceptor", program_name, SC_ID( scp ) ) ;
392       else
393       {
394          int namelen = sizeof( name ) - 1 ;      /* leave space for the NUL */
395          char host[NI_MAXHOST];
396          size_t hostlen = NI_MAXHOST;
397          socklen_t addrlen = 0;
398          union xsockaddr *sinp = CONN_XADDRESS(SERVER_CONNECTION(serp));
399          int len;
400
401          if( sinp == NULL )
402             exit(0);
403
404          if( SC_IPV6(scp) ) addrlen = sizeof(struct sockaddr_in6);
405          else if( SC_IPV4(scp) ) addrlen = sizeof(struct sockaddr_in);
406
407          len = strx_nprint(name, namelen, "(%s service) %s", program_name,
408             SC_ID( scp ) ) ;
409
410          if( getnameinfo( SA(sinp), addrlen, host, hostlen, NULL, 0, 0) != 0 )
411                strcpy(host, "unknown");
412
413          if ( SC_IPV6(scp) && SC_ACCEPTS_CONNECTIONS( scp ) && 
414                !IN6_IS_ADDR_UNSPECIFIED(&sinp->sa_in6.sin6_addr) )
415             strx_print( INT_NULL, &name[ len ], namelen - len, " %s" , host ) ;
416          if ( SC_IPV4(scp) && SC_ACCEPTS_CONNECTIONS( scp ) )
417             strx_print( INT_NULL, &name[ len ], namelen - len, " %s", host ) ;
418       }
419       rename_process( name ) ;
420       SVC_INTERNAL( sp, serp ) ;
421    }
422    _exit( 0 ) ;
423    /* NOTREACHED */
424 }
425
426
427 /*
428  * This function is invoked when a SIGCLD is received
429  */
430 void child_exit(void)
431 {
432    const char *func = "child_exit" ;
433
434    for ( ;; )         /* Find all children that exited */
435    {
436       int status ;
437       pid_t pid ;
438       struct server *serp ;
439       
440 #ifdef HAVE_WAITPID
441       pid = waitpid( -1, &status, WNOHANG ) ;
442 #else
443 #if defined( sun ) && defined( lint )
444       pid = wait3( (union wait *)&status, WNOHANG, RUSAGE_NULL ) ;
445 #else
446       pid = wait3( &status, WNOHANG, RUSAGE_NULL ) ;
447 #endif
448 #endif
449
450       if ( debug.on )
451 #ifdef HAVE_WAITPID
452          msg( LOG_DEBUG, func, "waitpid returned = %d", pid ) ;
453 #else
454          msg( LOG_DEBUG, func, "wait3 returned = %d", pid ) ;
455 #endif
456       
457       if ( pid == -1 ) {
458          if ( errno == EINTR )
459             continue ;
460          else
461             break ;
462       }
463
464       if ( pid == 0 )
465          break ;
466       
467       if ( ( serp = server_lookup( pid ) ) != NULL )
468       {
469          SERVER_EXITSTATUS(serp) = status ;
470          server_end( serp ) ;
471       }
472       else
473          msg( LOG_NOTICE, func, "unknown child process %d %s", pid,
474             PROC_STOPPED( status ) ? "stopped" : "died" ) ;
475    }
476 }
477