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.
10 #include <sys/types.h>
11 #include <sys/socket.h>
13 #ifdef HAVE_SYS_RESOURCE_H
14 #include <sys/resource.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
28 #if defined (HAVE_GRP_H)
48 * This function is running in the new process
50 void exec_server( const struct server *serp )
52 const struct service_config *scp = SVC_CONF( SERVER_SERVICE( serp ) ) ;
55 int descriptor = SERVER_FD( serp ) ;
56 const char *server = SC_SERVER( scp ) ;
57 const char *func = "exec_server" ;
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).
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
73 if ( fcntl( descriptor, F_SETFD, 0 ) == -1 )
74 msg( LOG_WARNING, func,
75 "fcntl( %d, clear close-on-exec ) failed: %m", descriptor ) ;
78 msg( LOG_DEBUG, func, "duping %d", descriptor ) ;
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.
88 for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ )
90 if ( dup2( descriptor, fd ) == -1 )
94 "dup2( %d, %d ) failed: %m", descriptor, fd ) ;
101 rl.rlim_max = ps.ros.orig_max_descriptors ;
102 rl.rlim_cur = ps.ros.max_descriptors ;
103 (void) setrlimit( RLIMIT_NOFILE, &rl ) ;
106 if (SC_RLIM_AS (scp))
108 rl.rlim_cur = SC_RLIM_AS( scp );
109 rl.rlim_max = SC_RLIM_AS( scp );
110 (void) setrlimit( RLIMIT_AS, &rl );
114 if (SC_RLIM_CPU (scp))
116 rl.rlim_cur = SC_RLIM_CPU( scp );
117 rl.rlim_max = SC_RLIM_CPU( scp );
118 (void) setrlimit( RLIMIT_CPU, &rl );
122 if (SC_RLIM_DATA (scp))
124 rl.rlim_cur = SC_RLIM_DATA( scp );
125 rl.rlim_max = SC_RLIM_DATA( scp );
126 (void) setrlimit( RLIMIT_DATA, &rl );
130 if (SC_RLIM_RSS (scp))
132 rl.rlim_cur = SC_RLIM_RSS( scp );
133 rl.rlim_max = SC_RLIM_RSS( scp );
134 (void) setrlimit( RLIMIT_RSS, &rl );
138 if (SC_RLIM_STACK (scp))
140 rl.rlim_cur = SC_RLIM_STACK( scp );
141 rl.rlim_max = SC_RLIM_STACK( scp );
142 (void) setrlimit( RLIMIT_STACK, &rl );
146 (void) Sclose( descriptor ) ;
149 #if !defined(HAVE_SETSID)
153 #if !defined(HAVE_SETSID)
158 (void) execve( server, SC_SERVER_ARGV( scp ),
159 env_getvars( SC_ENV( scp )->env_handle ) ) ;
162 * The exec failed. Log the error and exit.
165 msg( LOG_ERR, func, "execv( %s ) failed: %m", server ) ;
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
175 * The rest of ps.ros.Argv is cleared to spaces
177 static void rename_process( const char *name )
179 const char *from = name ;
180 char *to = ps.ros.Argv[ 0 ] ;
183 while ( *from != NUL )
188 if ( tmp_index < ps.ros.Argc )
189 to = ps.ros.Argv[ tmp_index++ ] ;
193 str_fill( to, ' ' ) ;
194 while ( tmp_index < ps.ros.Argc )
195 str_fill( ps.ros.Argv[ tmp_index++ ], ' ' ) ;
199 static void set_credentials( const struct service_config *scp )
201 const char *func = "set_credentials" ;
203 if ( SC_SPECIFIED( scp, A_GROUP ) || SC_SPECIFIED( scp, A_USER ) ) {
204 if ( ps.ros.is_superuser )
206 gid_t gid = SC_GETGID( scp ) ;
208 if ( setgid( gid ) == -1 )
210 msg( LOG_ERR, func, "setgid failed: %m" ) ;
214 #ifndef NO_INITGROUPS
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
221 /* Solar Designer's groups fix */
222 if ( SC_SPECIFIED( scp, A_USER ) && SC_SPECIFIED( scp, A_GROUPS ) &&
223 SC_GROUPS(scp) == YES )
228 * Invoke getpwuid() to get the user's name.
230 * XXX: we should not need to invoke getpwuid(); we should
231 * remember the user name in the configuration file.
233 if ( ( pwd = getpwuid( SC_UID( scp ) ) ) == NULL )
235 msg( LOG_ERR, func, "getpwuid( %d ) (service=%s) failed: %m",
236 SC_UID( scp ), SC_ID( scp ) ) ;
239 str_fill( pwd->pw_passwd, ' ' );
241 if ( initgroups( pwd->pw_name, pwd->pw_gid ) == -1 )
243 msg( LOG_ERR, func, "initgroups( %s, %d ) failed: %m",
244 pwd->pw_name, pwd->pw_gid ) ;
250 if ( setgroups( 0, NULL ) )
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));
257 #endif /* ! NO_INITGROUPS */
261 if ( SC_SPECIFIED( scp, A_USER ) ) {
262 if ( setuid( SC_UID( scp ) ) == -1 )
264 msg( LOG_ERR, func, "setuid failed: %m" ) ;
269 if ( SC_SPECIFIED( scp, A_UMASK ) )
270 umask(SC_UMASK(scp));
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
281 void child_process( struct server *serp )
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" ;
288 signal_default_state();
290 if ((signals_pending[0] >= 0 && Sclose(signals_pending[0])) ||
291 (signals_pending[1] >= 0 && Sclose(signals_pending[1])))
293 msg(LOG_ERR, func, "Failed to close the signal pipe: %m");
296 signals_pending[0] = -1;
297 signals_pending[1] = -1;
307 msg( LOG_DEBUG, func, "Process %d is sleeping", getpid() ) ;
312 if ( ! SC_IS_INTERCEPTED( scp ) )
314 set_credentials( scp ) ;
315 if ( SC_SPECIFIED( scp, A_NICE ) )
316 (void) nice( SC_NICE( scp ) ) ;
319 if ( svc_child_access_control(sp, cp) != OK )
322 if ( SERVER_LOGUSER( serp ) )
328 * We use LOGUSER_SUCCESS_TIMEOUT unless the service requires
329 * identification, in which case we use an infinite timeout
331 timeout = SC_MUST_IDENTIFY( scp ) ? 0 : LOGUSER_SUCCESS_TIMEOUT ;
332 result = log_remote_user( serp, timeout ) ;
334 if ( result != IDR_OK && SC_MUST_IDENTIFY( scp ) )
336 svc_logprint( sp, NOID_ENTRY, "%s %s",
337 conn_addrstr( SERVER_CONNECTION( serp ) ),
338 idresult_explain( result ) ) ;
344 /* this is where the server gets executed -bbraun */
345 if ( ! SC_IS_INTERNAL( scp ) )
347 if( SC_REDIR_ADDR(scp) != NULL )
349 redir_handler( serp );
353 #if defined(HAVE_SETENV)
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) );
362 exec_server( serp ) ;
369 * We don't bother to disassociate from the controlling terminal
370 * (we have a controlling terminal only if debug.on is TRUE)
372 * Also, for interceptor processes, we give them the name:
373 * <program_name> <service-id> interceptor
375 if ( SC_IS_INTERCEPTED( scp ) )
376 strx_print( INT_NULL, name, sizeof( name ) - 1,
377 "%s %s interceptor", program_name, SC_ID( scp ) ) ;
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));
390 if( SC_IPV6(scp) ) addrlen = sizeof(struct sockaddr_in6);
391 else if( SC_IPV4(scp) ) addrlen = sizeof(struct sockaddr_in);
393 len = strx_nprint(name, namelen, "(%s service) %s", program_name,
396 if( getnameinfo( SA(sinp), addrlen, host, hostlen, NULL, 0, 0) != 0 )
397 strcpy(host, "unknown");
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 ) ;
405 rename_process( name ) ;
406 SVC_INTERNAL( sp, serp ) ;
414 * This function is invoked when a SIGCLD is received
416 void child_exit(void)
418 const char *func = "child_exit" ;
420 for ( ;; ) /* Find all children that exited */
424 struct server *serp ;
427 pid = waitpid( -1, &status, WNOHANG ) ;
429 #if defined( sun ) && defined( lint )
430 pid = wait3( (union wait *)&status, WNOHANG, RUSAGE_NULL ) ;
432 pid = wait3( &status, WNOHANG, RUSAGE_NULL ) ;
438 msg( LOG_DEBUG, func, "waitpid returned = %d", pid ) ;
440 msg( LOG_DEBUG, func, "wait3 returned = %d", pid ) ;
444 if ( errno == EINTR )
453 if ( ( serp = server_lookup( pid ) ) != NULL )
455 SERVER_EXITSTATUS(serp) = status ;
459 msg( LOG_NOTICE, func, "unknown child process %d %s", pid,
460 PROC_STOPPED( status ) ? "stopped" : "died" ) ;