status_e setup_environ( struct service_config *scp, struct service_config *def ) { struct environment *ep = SC_ENV( scp ) ; if ( ! SC_SPECIFIED( scp, A_PASSENV ) ) { if ( ! SC_SPECIFIED( def, A_PASSENV ) ) { if ( ! SC_SPECIFIED( scp, A_ENV ) ) { ep->env_type = STD_ENV ; ep->env_handle = std_env ; return( OK ) ; } else return( make_env_with_strings( ep, std_env, SC_ENV_VAR_DEFS(scp) ) ) ; } else /* SC_SPECIFIED( def, A_PASSENV ) */ { struct environment *dep = SC_ENV( def ) ; if ( dep->env_type == NO_ENV && make_env_from_vars( dep, std_env, SC_PASS_ENV_VARS(def) ) == FAILED ) return( FAILED ) ; if ( ! SC_SPECIFIED( scp, A_ENV ) ) { ep->env_type = DEF_ENV ; ep->env_handle = dep->env_handle ; return( OK ) ; } else return( make_env_with_strings( ep, dep->env_handle, SC_ENV_VAR_DEFS(scp) ) ) ; } } else /* SC_SPECIFIED( scp, A_PASSENV ) */ { if ( make_env_from_vars( ep, std_env, SC_PASS_ENV_VARS(scp) ) == FAILED ) return( FAILED ) ; if ( ! SC_SPECIFIED( scp, A_ENV ) ) return( OK ) ; else { if ( update_env_with_strings( ep->env_handle, SC_ENV_VAR_DEFS(scp) ) == FAILED ) { env_destroy( ep->env_handle ) ; return( FAILED ) ; } return( OK ) ; } } }
/* * Identify the attribute in <attr_name>. * * Check if * 1) the attribute has been defined already * 2) the value count is correct * 3) the assign op is appropriate * * Invoke appropriate parser. * * This function will return FAILED only if its in the default section * and an attribute cannot be ID'd. Otherwise, it returns OK. */ static status_e identify_attribute( entry_e entry_type, struct service_config *scp, const char *attr_name, enum assign_op op, pset_h attr_values ) { const struct attribute *ap ; const char *func = "identify_attribute" ; if ( entry_type == SERVICE_ENTRY ) ap = attr_lookup( service_attributes, attr_name ) ; else ap = attr_lookup( default_attributes, attr_name ) ; if ( ap == NULL ) return OK; /* We simply ignore keywords not on the list */ if ( ! MODIFIABLE( ap ) ) { if ( SC_SPECIFIED( scp, ap->a_id ) ) { parsemsg( LOG_WARNING, func, "Service %s: attribute already set: %s", SC_NAME(scp), attr_name ) ; return OK; } if ( op != SET_EQ ) { parsemsg( LOG_WARNING, func, "Service %s: operator '%s' cannot be used for attribute '%s'", SC_NAME(scp), ( op == PLUS_EQ ) ? "+=" : "-=", attr_name ) ; return OK; } } else /* modifiable attribute */ { /* * For the defaults entry, '=' and '+=' have the same meaning */ if ( entry_type == DEFAULTS_ENTRY && op == SET_EQ ) op = PLUS_EQ ; } if ( FIXED_VALUES( ap ) && (unsigned)ap->a_nvalues != pset_count( attr_values ) ) { parsemsg( LOG_WARNING, func, "attribute %s expects %d values and %d values were specified", attr_name, ap->a_nvalues, pset_count( attr_values ) ) ; return OK; } if ( (*ap->a_parser)( attr_values, scp, op ) == OK ) { /* This is the normal path. */ SC_SPECIFY( scp, ap->a_id ) ; } else if ( entry_type == SERVICE_ENTRY ) { parsemsg( LOG_ERR, func, "Error parsing attribute %s - DISABLING SERVICE", attr_name ) ; SC_DISABLE( scp ); } /* * We are in the default section and an error was detected. At * this point, we should terminate since whatever attribute * was trying to be specified cannot be propagated. */ else if ( !debug.on ) return FAILED; return OK; }
/* * Get a service entry. Steps: * * 1. Parse entry attributes * 2. Determine service id * 3. Insert entry in table */ static void get_service_entry( int fd, pset_h sconfs, const char *name, struct service_config *defaults ) { struct service_config *scp ; const char *func = "get_service_entry" ; scp = sc_alloc( name ) ; if ( scp == NULL ) { skip_entry( fd ) ; return ; } /* Now fill in default attributes if given. */ if ( SC_SPECIFIED( defaults, A_LOG_ON_SUCCESS ) && ! SC_IS_PRESENT( scp, A_LOG_ON_SUCCESS) ) fill_attribute( A_LOG_ON_SUCCESS, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_LOG_ON_FAILURE ) && ! SC_IS_PRESENT( scp, A_LOG_ON_FAILURE ) ) fill_attribute( A_LOG_ON_FAILURE, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_ONLY_FROM ) && ! SC_IS_PRESENT( scp, A_ONLY_FROM ) ) fill_attribute( A_ONLY_FROM, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_NO_ACCESS ) && ! SC_IS_PRESENT( scp, A_NO_ACCESS ) ) fill_attribute( A_NO_ACCESS, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_PASSENV ) && ! SC_IS_PRESENT( scp, A_PASSENV ) ) fill_attribute( A_PASSENV, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_ACCESS_TIMES ) && ! SC_IS_PRESENT( scp, A_ACCESS_TIMES ) ) fill_attribute( A_ACCESS_TIMES, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_BANNER ) && ! SC_IS_PRESENT( scp, A_BANNER ) ) fill_attribute( A_BANNER, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_BANNER_SUCCESS ) && ! SC_IS_PRESENT( scp, A_BANNER_SUCCESS ) ) fill_attribute( A_BANNER_SUCCESS, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_BANNER_FAIL ) && ! SC_IS_PRESENT( scp, A_BANNER_FAIL ) ) fill_attribute( A_BANNER_FAIL, scp, defaults ) ; if ( parse_entry( SERVICE_ENTRY, fd, scp ) == FAILED ) { sc_free( scp ) ; skip_entry( fd ) ; return ; } /* * If no service id was specified, set it equal to the service name */ if ( ! SC_SPECIFIED( scp, A_ID ) ) { if ( (SC_ID(scp) = new_string( SC_NAME(scp) )) ) SC_PRESENT( scp, A_ID ) ; else { out_of_memory( func ) ; sc_free( scp ) ; return ; } } if ( ! (pset_add( sconfs, scp )) ) { out_of_memory( func ) ; sc_free( scp ) ; return ; } }
/* * Read the configuration file (descriptor fd) and place all * services found there in the configuration. */ void parse_conf_file( int fd, struct configuration *confp, const char *filename) { pset_h sconfs = CNF_SERVICE_CONFS( confp ) ; struct service_config *default_config = CNF_DEFAULTS( confp ) ; boolean_e found_defaults = NO ; struct service_config default_default_config ; const char *func = "parse_conf_file" ; int incfd; line_count = 0 ; current_file = filename; CLEAR( default_default_config ) ; for ( ;; ) { entry_e entry_type ; char *service_name = NULL; /* * if find_next_entry is successful, service_name * will point to malloc'ed memory */ entry_type = find_next_entry( fd, &service_name ) ; switch ( entry_type ) { case INCLUDE_ENTRY: { int saved_line_count = line_count; incfd = open(service_name, O_RDONLY); if( incfd < 0 ) { parsemsg( LOG_ERR, func, "Unable to open included configuration file: %s", service_name); break; } parsemsg( LOG_DEBUG,func, "Reading included configuration file: %s",service_name); parse_conf_file(incfd, confp, service_name); /* * parse_conf_file eventually calls Srdline, try Sclosing it * to unmmap memory. */ Sclose(incfd); /* Restore since we've returned from included file */ current_file = filename; line_count = saved_line_count; } break; case INCLUDEDIR_ENTRY: { int saved_line_count = line_count; handle_includedir(service_name, confp); current_file = filename; line_count = saved_line_count; } break; case SERVICE_ENTRY: get_service_entry( fd, sconfs, service_name, default_config ) ; break ; case DEFAULTS_ENTRY: if ( found_defaults == YES ) { parsemsg( LOG_ERR, func, "only 1 defaults entry is allowed. This entry will be ignored" ) ; skip_entry( fd ) ; } else if ( parse_entry( DEFAULTS_ENTRY, fd, default_config ) == OK ) { found_defaults = YES ; /* * We must check bind_address to see if it was deferred. */ if (SC_SPECIFIED( default_config, A_BIND) && SC_BIND_ADDR(default_config) == NULL) M_CLEAR( default_config->sc_specified_attributes, A_BIND ) ; } break ; case BAD_ENTRY: skip_entry( fd ) ; break ; case NO_ENTRY: return ; } if (service_name) free(service_name); } }
/* * Print info about service scp to file descriptor fd */ void sc_dump( struct service_config *scp, int fd, int tab_level, bool_int is_defaults ) { const struct name_value *nvp ; unsigned u ; char **pp ; if ( is_defaults ) tabprint( fd, tab_level, "Service defaults\n" ) ; else tabprint( fd, tab_level, "Service configuration: %s\n", SC_NAME(scp) ) ; if ( ! is_defaults ) { tabprint( fd, tab_level+1, "id = %s\n", SC_ID(scp) ) ; if ( ! M_ARE_ALL_CLEAR( SC_XFLAGS(scp) ) ) { tabprint( fd, tab_level+1, "flags =" ) ; for ( nvp = &service_flags[ 0 ] ; nvp->name != NULL ; nvp++ ) if ( M_IS_SET( SC_XFLAGS(scp), nvp->value ) ) Sprint( fd, " %s", nvp->name ) ; Sputchar( fd, '\n' ) ; } if ( ! M_ARE_ALL_CLEAR( SC_TYPE(scp) ) ) { tabprint( fd, tab_level+1, "type =" ) ; for ( nvp = &service_types[ 0 ] ; nvp->name != NULL ; nvp++ ) if ( M_IS_SET( SC_TYPE(scp), nvp->value ) ) Sprint( fd, " %s", nvp->name ) ; Sputchar( fd, '\n' ) ; } tabprint( fd, tab_level+1, "socket_type = %s\n", nv_get_name( socket_types, SC_SOCKET_TYPE(scp) ) ) ; tabprint( fd, tab_level+1, "Protocol (name,number) = (%s,%d)\n", SC_PROTONAME(scp), SC_PROTOVAL(scp) ) ; if ( SC_SPECIFIED( scp, A_PORT ) ) tabprint( fd, tab_level+1, "port = %d\n", SC_PORT(scp) ) ; } if ( SC_SPECIFIED( scp, A_INSTANCES ) ) { if ( SC_INSTANCES(scp) == UNLIMITED ) tabprint( fd, tab_level+1, "Instances = UNLIMITED\n" ) ; else tabprint( fd, tab_level+1, "Instances = %d\n", SC_INSTANCES(scp) ) ; } if ( SC_SPECIFIED( scp, A_WAIT ) ) { if ( SC_WAIT(scp) ) tabprint( fd, tab_level+1, "wait = yes\n" ) ; else tabprint( fd, tab_level+1, "wait = no\n" ) ; } if ( SC_SPECIFIED( scp, A_USER ) ) tabprint( fd, tab_level+1, "user = %d\n", SC_UID(scp) ) ; if ( SC_SPECIFIED( scp, A_GROUP ) ) tabprint( fd, tab_level+1, "group = %d\n", SC_GID(scp) ) ; if ( SC_SPECIFIED( scp, A_GROUPS ) ) { if (SC_GROUPS(scp) == 1) tabprint( fd, tab_level+1, "Groups = yes\n" ); else tabprint( fd, tab_level+1, "Groups = no\n" ); } if ( SC_SPECIFIED( scp, A_UMASK ) ) tabprint( fd, tab_level+1, "umask = %o\n", SC_UMASK(scp) ) ; if ( SC_SPECIFIED( scp, A_NICE ) ) tabprint( fd, tab_level+1, "Nice = %d\n", SC_NICE(scp) ) ; if ( SC_SPECIFIED( scp, A_CPS ) ) tabprint( fd, tab_level+1, "CPS = max conn:%lu wait:%lu\n", SC_TIME_CONN_MAX(scp), SC_TIME_WAIT(scp) ); if ( SC_SPECIFIED( scp, A_PER_SOURCE ) ) tabprint( fd, tab_level+1, "PER_SOURCE = %d\n", SC_PER_SOURCE(scp) ); if ( SC_SPECIFIED( scp, A_BIND ) ) { if ( SC_BIND_ADDR(scp) ) { char bindname[NI_MAXHOST]; unsigned int len = 0; if( SC_BIND_ADDR(scp)->sa.sa_family == AF_INET ) len = sizeof(struct sockaddr_in); else len = sizeof(struct sockaddr_in6); memset(bindname, 0, sizeof(bindname)); if( getnameinfo(&SC_BIND_ADDR(scp)->sa, len, bindname, NI_MAXHOST, NULL, 0, 0) != 0 ) strcpy(bindname, "unknown"); tabprint( fd, tab_level+1, "Bind = %s\n", bindname ); } else if ( SC_ORIG_BIND_ADDR(scp) ) { tabprint( fd, tab_level+1, "Bind = %s\n", SC_ORIG_BIND_ADDR(scp) ); } else { /* This should NEVER happen */ msg(LOG_ERR, "sc_dump", "bad configuration for %s:", SC_NAME(scp)); } } else tabprint( fd, tab_level+1, "Bind = All addresses.\n" ); if ( ! is_defaults ) { if ( (! SC_IS_INTERNAL( scp )) && (SC_REDIR_ADDR(scp) == NULL) ) { tabprint( fd, tab_level+1, "Server = %s\n", SC_SERVER(scp) ) ; tabprint( fd, tab_level+1, "Server argv =" ) ; if ( SC_SERVER_ARGV(scp) ) { for ( pp = SC_SERVER_ARGV(scp) ; *pp ; pp++ ) Sprint( fd, " %s", *pp ) ; } else Sprint( fd, " (NULL)"); Sputchar( fd, '\n' ) ; } #ifdef LIBWRAP if ( SC_LIBWRAP(scp) != NULL ) { tabprint( fd, tab_level + 1, "Libwrap = %s\n", SC_LIBWRAP(scp) ); } #endif if ( SC_REDIR_ADDR(scp) != NULL ) { char redirname[NI_MAXHOST]; unsigned int len = 0; if( SC_REDIR_ADDR(scp)->sa.sa_family == AF_INET ) len = sizeof(struct sockaddr_in); if( SC_REDIR_ADDR(scp)->sa.sa_family == AF_INET6 ) len = sizeof(struct sockaddr_in6); memset(redirname, 0, sizeof(redirname)); if( getnameinfo(&SC_REDIR_ADDR(scp)->sa, len, redirname, NI_MAXHOST, NULL, 0, 0) != 0 ) strcpy(redirname, "unknown"); tabprint( fd, tab_level+1, "Redirect = %s:%d\n", redirname, SC_REDIR_ADDR(scp)->sa_in.sin_port ); } if ( SC_IS_RPC( scp ) ) { struct rpc_data *rdp = SC_RPCDATA( scp ) ; tabprint( fd, tab_level+1, "RPC data\n" ) ; tabprint( fd, tab_level+2, "program number = %ld\n", rdp->rd_program_number ) ; tabprint( fd, tab_level+2, "rpc_version = " ) ; if ( rdp->rd_min_version == rdp->rd_max_version ) Sprint( fd, "%ld\n", rdp->rd_min_version ) ; else Sprint( fd, "%ld-%ld\n", rdp->rd_min_version, rdp->rd_max_version ) ; } if ( SC_SPECIFIED( scp, A_ACCESS_TIMES ) ) { tabprint( fd, tab_level+1, "Access times =" ) ; ti_dump( SC_ACCESS_TIMES(scp), fd ) ; Sputchar ( fd, '\n' ) ; } } /* This is important enough that each service should list it. */ tabprint( fd, tab_level+1, "Only from: " ) ; if ( SC_ONLY_FROM(scp) ) { /* Next check is done since -= doesn't zero out lists. */ if ( pset_count(SC_ONLY_FROM(scp)) == 0) Sprint( fd, "All sites" ); else addrlist_dump( SC_ONLY_FROM(scp), fd ) ; } else Sprint( fd, "All sites" ); Sputchar( fd, '\n' ) ; /* This is important enough that each service should list it. */ tabprint( fd, tab_level+1, "No access: " ) ; if ( SC_NO_ACCESS(scp) ) { /* Next check is done since -= doesn't zero out lists. */ if ( pset_count(SC_NO_ACCESS(scp)) == 0) Sprint( fd, "No blocked sites" ); else addrlist_dump( SC_NO_ACCESS(scp), fd ) ; } else Sprint( fd, "No blocked sites" ); Sputchar( fd, '\n' ) ; if ( SC_SENSOR(scp) ) { tabprint( fd, tab_level+1, "Deny Time: " ) ; Sprint( fd, "%d\n", SC_DENY_TIME(scp)); } dump_log_data( fd, scp, tab_level+1 ) ; if ( SC_IS_PRESENT( scp, A_PASSENV ) ) { tabprint( fd, tab_level+1, "Passenv =" ) ; for ( u = 0 ; u < pset_count( SC_PASS_ENV_VARS(scp) ) ; u++ ) Sprint( fd, " %s", (char *) pset_pointer( SC_PASS_ENV_VARS(scp), u ) ) ; Sputchar ( fd, '\n' ) ; } if ( ! is_defaults ) if ( SC_SPECIFIED( scp, A_ENV ) ) { tabprint( fd, tab_level+1, "Environment additions:\n" ) ; for ( u = 0 ; u < pset_count( SC_ENV_VAR_DEFS(scp) ) ; u++ ) tabprint( fd, tab_level+2, "%s\n", (char *) pset_pointer( SC_ENV_VAR_DEFS(scp), u ) ) ; } if ( SC_ENV( scp )->env_type == CUSTOM_ENV ) { tabprint( fd, tab_level+1, "Environment strings:\n" ) ; for ( pp = env_getvars( SC_ENV( scp )->env_handle ) ; *pp ; pp++ ) tabprint( fd, tab_level+2, "%s\n", *pp ) ; } Sflush( fd ) ; }
static status_e activate_normal( struct service *sp ) { union xsockaddr tsin; int sd = SVC_FD( sp ) ; struct service_config *scp = SVC_CONF( sp ) ; uint16_t service_port = SC_PORT( scp ) ; char *sid = SC_ID( scp ) ; const char *func = "activate_normal" ; unsigned int sin_len = sizeof(tsin); int on = 1; #ifdef IPV6_V6ONLY int v6on = 0; #endif if( SC_BIND_ADDR(scp) != NULL ) memcpy(&tsin, SC_BIND_ADDR(scp), sin_len); else memset(&tsin, 0, sin_len); if( SC_IPV4( scp ) ) { tsin.sa_in.sin_family = AF_INET ; tsin.sa_in.sin_port = htons( service_port ) ; sin_len = sizeof(struct sockaddr_in); } else if( SC_IPV6( scp ) ) { tsin.sa_in6.sin6_family = AF_INET6; tsin.sa_in6.sin6_port = htons( service_port ); sin_len = sizeof(struct sockaddr_in6); } #ifdef IPV6_V6ONLY if( SC_IPV6(scp) ) { if( SC_SPECIFIED(scp, A_V6ONLY) ) { v6on = 1; } else { v6on = 0; } if( setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) { msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" ); } } #endif if ( setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof( on ) ) == -1 ) msg( LOG_WARNING, func, "setsockopt SO_REUSEADDR failed (%m). service = %s", sid ) ; if( SC_NODELAY( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) { if ( setsockopt( sd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof( on ) ) == -1 ) msg( LOG_WARNING, func, "setsockopt TCP_NODELAY failed (%m). service = %s", sid ) ; } if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) { if( setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof( on ) ) < 0 ) msg( LOG_WARNING, func, "setsockopt SO_KEEPALIVE failed (%m). service = %s", sid ) ; } if ( bind( sd, &tsin.sa, sin_len ) == -1 ) { msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; return( FAILED ) ; } #ifdef IN_MULTICAST if( SC_IPV4(scp) && IN_MULTICAST( ntohl(tsin.sa_in.sin_addr.s_addr) ) ) { struct ifaddrs *addrs, *addr; struct ip_mreq mreq; if (getifaddrs(&addrs) == 0) { addr = addrs; while (addr) { if (addr->ifa_addr && (addr->ifa_flags & IFF_MULTICAST)) { mreq.imr_multiaddr.s_addr = tsin.sa_in.sin_addr.s_addr; mreq.imr_interface.s_addr = ((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr; setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); } addr = addr->ifa_next; } freeifaddrs(addrs); if ( debug.on ) msg( LOG_DEBUG, func, "Adding multicast membership." ); } else { msg( LOG_ERR, func, "getifaddrs failed (%m). service = %s", sid ); } } #endif return( OK ) ; }
/* * This function is invoked in a forked process to run a server. * If the service is internal the appropriate function is invoked * otherwise the server program is exec'ed. * This function also logs the remote user id if appropriate */ void child_process( struct server *serp ) { struct service *sp = SERVER_SERVICE( serp ) ; connection_s *cp = SERVER_CONNECTION( serp ) ; struct service_config *scp = SVC_CONF( sp ) ; const char *func = "child_process" ; signal_default_state(); if ((signals_pending[0] >= 0 && Sclose(signals_pending[0])) || (signals_pending[1] >= 0 && Sclose(signals_pending[1]))) { msg(LOG_ERR, func, "Failed to close the signal pipe: %m"); _exit(1); } signals_pending[0] = -1; signals_pending[1] = -1; Sclose(0); Sclose(1); Sclose(2); #ifdef DEBUG_SERVER if ( debug.on ) { msg( LOG_DEBUG, func, "Process %d is sleeping", getpid() ) ; sleep( 10 ) ; } #endif if ( ! SC_IS_INTERCEPTED( scp ) ) { set_credentials( scp ) ; if ( SC_SPECIFIED( scp, A_NICE ) ) (void) nice( SC_NICE( scp ) ) ; } if ( svc_child_access_control(sp, cp) != OK ) exit(0); if ( SERVER_LOGUSER( serp ) ) { unsigned timeout ; idresult_e result ; /* * We use LOGUSER_SUCCESS_TIMEOUT unless the service requires * identification, in which case we use an infinite timeout */ timeout = SC_MUST_IDENTIFY( scp ) ? 0 : LOGUSER_SUCCESS_TIMEOUT ; result = log_remote_user( serp, timeout ) ; if ( result != IDR_OK && SC_MUST_IDENTIFY( scp ) ) { svc_logprint( sp, NOID_ENTRY, "%s %s", conn_addrstr( SERVER_CONNECTION( serp ) ), idresult_explain( result ) ) ; _exit( 0 ) ; } } #ifdef HAVE_SESSIONCREATE if ( scp->sc_sessioncreate == YES ) { if ( SessionCreate(0, sessionHasTTY|sessionIsRemote) != noErr ) svc_logprint( sp, "SessionCreate", "SessionCreate() failed!" ); } #endif /* this is where the server gets executed -bbraun */ if ( ! SC_IS_INTERNAL( scp ) ) { if( scp->sc_redir_addr != NULL ) { redir_handler( serp ); } else { #if defined(HAVE_SETENV) char buff[1024]; strx_sprint(buff, sizeof(buff)-1, "REMOTE_HOST=%s", conn_addrstr(cp)); if( env_addstr(SC_ENV(scp)->env_handle, buff) != ENV_OK ) { msg( LOG_ERR, func, "Error adding REMOTE_HOST variable for %s: %m", SC_NAME(scp) ); _exit( 1 ) ; } #endif exec_server( serp ) ; } } else { char name[ 180 ] ; /* * We don't bother to disassociate from the controlling terminal * (we have a controlling terminal only if debug.on is TRUE) * * Also, for interceptor processes, we give them the name: * <program_name> <service-id> interceptor */ if ( SC_IS_INTERCEPTED( scp ) ) strx_print( INT_NULL, name, sizeof( name ) - 1, "%s %s interceptor", program_name, SC_ID( scp ) ) ; else { int namelen = sizeof( name ) - 1 ; /* leave space for the NUL */ char host[NI_MAXHOST]; size_t hostlen = NI_MAXHOST; socklen_t addrlen = 0; union xsockaddr *sinp = CONN_XADDRESS(SERVER_CONNECTION(serp)); int len; if( sinp == NULL ) exit(0); if( SC_IPV6(scp) ) addrlen = sizeof(struct sockaddr_in6); else if( SC_IPV4(scp) ) addrlen = sizeof(struct sockaddr_in); len = strx_nprint(name, namelen, "(%s service) %s", program_name, SC_ID( scp ) ) ; if( getnameinfo( SA(sinp), addrlen, host, hostlen, NULL, 0, 0) != 0 ) strcpy(host, "unknown"); if ( SC_IPV6(scp) && SC_ACCEPTS_CONNECTIONS( scp ) && !IN6_IS_ADDR_UNSPECIFIED(&sinp->sa_in6.sin6_addr) ) strx_print( INT_NULL, &name[ len ], namelen - len, " %s" , host ) ; if ( SC_IPV4(scp) && SC_ACCEPTS_CONNECTIONS( scp ) ) strx_print( INT_NULL, &name[ len ], namelen - len, " %s", host ) ; } rename_process( name ) ; SVC_INTERNAL( sp, serp ) ; } _exit( 0 ) ; /* NOTREACHED */ }
static void set_credentials( const struct service_config *scp ) { const char *func = "set_credentials" ; if ( SC_SPECIFIED( scp, A_GROUP ) || SC_SPECIFIED( scp, A_USER ) ) { if ( ps.ros.is_superuser ) { gid_t gid = SC_GETGID( scp ) ; if ( setgid( gid ) == -1 ) { msg( LOG_ERR, func, "setgid failed: %m" ) ; _exit( 1 ) ; } #ifndef NO_INITGROUPS /* * Bug discovered by [email protected] (a bug fix was also provided; * a slightly modified version is included here): * initgroups was not being invoked to set the remaining * groups appropriately */ /* Solar Designer's groups fix */ if ( SC_SPECIFIED( scp, A_USER ) && SC_SPECIFIED( scp, A_GROUPS ) && scp->sc_groups == YES ) { struct passwd *pwd ; /* * Invoke getpwuid() to get the user's name. * * XXX: we should not need to invoke getpwuid(); we should * remember the user name in the configuration file. */ if ( ( pwd = getpwuid( SC_UID( scp ) ) ) == NULL ) { msg( LOG_ERR, func, "getpwuid( %d ) (service=%s) failed: %m", SC_UID( scp ), SC_ID( scp ) ) ; _exit( 1 ) ; } str_fill( pwd->pw_passwd, ' ' ); if ( initgroups( pwd->pw_name, pwd->pw_gid ) == -1 ) { msg( LOG_ERR, func, "initgroups( %s, %d ) failed: %m", pwd->pw_name, pwd->pw_gid ) ; _exit( 1 ) ; } } else { if ( setgroups( 0, NULL ) ) { msg( LOG_ERR, func, "setgroups( 0, NULL ) failed: %m" ) ; msg( LOG_ERR, func, "Your system may require that 'groups = yes' be defined for this service: %s", scp->sc_name); _exit( 1 ) ; } } #endif /* ! NO_INITGROUPS */ } } if ( SC_SPECIFIED( scp, A_USER ) ) { if ( setuid( SC_UID( scp ) ) == -1 ) { msg( LOG_ERR, func, "setuid failed: %m" ) ; _exit( 1 ) ; } } if ( SC_SPECIFIED( scp, A_UMASK ) ) umask(scp->sc_umask); }