/* * Generate the current time using the SMTP format: * 02 FEB 1991 12:31:42 MST * * The result is placed in buf. * buflen is a value-result parameter. It indicates the size of * buf and on exit it has the length of the string placed in buf. */ static void daytime_protocol( char *buf, unsigned int *buflen ) { static const char *month_name[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" } ; time_t now ; struct tm *tmp ; int size = *buflen ; #ifdef HAVE_STRFTIME int cc ; #endif (void) time( &now ) ; tmp = localtime( &now ) ; #ifndef HAVE_STRFTIME strx_print( buflen, buf, size, "%02d %s %d %02d:%02d:%02d %s\r\n", tmp->tm_mday, month_name[ tmp->tm_mon ], 1900 + tmp->tm_year, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tmp->tm_zone ) ; #else cc = strx_nprint( buf, size, "%02d %s %d %02d:%02d:%02d", tmp->tm_mday, month_name[ tmp->tm_mon ], 1900 + tmp->tm_year, tmp->tm_hour, tmp->tm_min, tmp->tm_sec ) ; if ( cc >= 0 ) { *buflen = cc ; size -= cc ; cc = strftime( &buf[ *buflen ], size, " %Z\r\n", tmp ) ; *buflen += cc ; } #endif }
int APPEND (FUNC_PREFIX, fcvt_r) (FLOAT_TYPE value, int ndigit, int *decpt, int *sign, char *buf, size_t len) { int n, i; int left; if (buf == NULL) { __set_errno (EINVAL); return -1; } left = 0; if (!ISINF (value) && !ISNAN (value)) { /* OK, the following is not entirely correct. -0.0 is not handled * correctly but glibc 2.0 does not have a portable function to * implement this test. */ *sign = value < 0.0; if (*sign) value = -value; if (ndigit < 0) { /* Rounding to the left of the decimal point. */ while (ndigit < 0) { FLOAT_TYPE new_value = value * 0.1; if (new_value < 1.0) { ndigit = 0; break; } value = new_value; ++left; ++ndigit; } } } else { /* Value is Inf or NaN. */ *sign = 0; } n = strx_nprint (buf, len, "%.*" FLOAT_FMT_FLAG "f", ndigit, value); if (n < 0) return -1; i = 0; while (i < n && isdigit (buf[i])) ++i; *decpt = i; if (i == 0) /* Value is Inf or NaN. */ return 0; if (i < n) { do ++i; while (i < n && !isdigit (buf[i])); if (*decpt == 1 && buf[0] == '0' && value != 0.0) { /* We must not have leading zeroes. Strip them all out and * adjust *DECPT if necessary. */ --*decpt; while (i < n && buf[i] == '0') { --*decpt; ++i; } } memmove (&buf[MAX (*decpt, 0)], &buf[i], n - i); buf[n - (i - MAX (*decpt, 0))] = '\0'; } if (left) { *decpt += left; if (--len > n) { while (left-- > 0 && n < len) buf[n++] = '0'; buf[n] = '\0'; } } return 0; }
/* * 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 */ }
/* * This function runs in the parent context and updates the global_no_access * list. */ void process_sensor( const struct service *sp, const union xsockaddr *addr) { const char *func = "process_sensor"; if (SC_DENY_TIME(SVC_CONF(sp)) != 0) /* 0 simply logs it */ { if ( pset_count( global_no_access ) < MAX_GLOBAL_NO_ACCESS) { int item_matched = addrlist_match( global_no_access, SA(addr) ); if ( item_matched == 0) { /* no match...adding to the list */ char *dup_addr = new_string(xaddrname( addr ) ); if (dup_addr == NULL ) return ; if (addrlist_add(global_no_access, dup_addr) == FAILED) msg(LOG_ERR, func, "Failed adding %s to the global_no_access list", dup_addr); else { time_t nowtime; char time_buf[40], *tmp; nowtime = time(NULL); msg(LOG_CRIT, func, "Adding %s to the global_no_access list for %d minutes", dup_addr, SC_DENY_TIME(SVC_CONF(sp))); if (SC_DENY_TIME(SVC_CONF(sp)) == -1) strcpy(time_buf, "-1"); else strx_nprint(time_buf, 38, "%ld", (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp)))); tmp = new_string(time_buf); if (tmp != NULL) { if (pset_add(global_no_access_time, tmp) == NULL) { msg(LOG_ERR, func, "Failed adding %s to the global_no_access_time list. " "global_no_access list is broken, xinetd needs " "restarting.", dup_addr); /* ideally, we should rollback the previous addr addition. */ } } if (pset_count(global_no_access) && (timer_id == 0) ) timer_id = xtimer_add( scrub_global_access_list, 60 ); } free(dup_addr); } else { /* Here again, eh?...update time stamp. */ char *exp_time; time_t stored_time; item_matched--; /* Is # plus 1, to even get here must be >= 1 */ exp_time = pset_pointer( global_no_access_time, item_matched ) ; if (exp_time == NULL) return ; if ( parse_base10(exp_time, (int *)&stored_time) ) { /* if never let them off, bypass */ if (stored_time != -1) { time_t nowtime, new_time; nowtime = time(NULL); new_time = (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp))); if (difftime(new_time, (time_t)stored_time) > 0.0) { /* new_time is longer save it */ char time_buf[40], *new_exp_time; strx_nprint(time_buf, 38, "%ld", (long)new_time); new_exp_time = new_string(time_buf); if ( new_exp_time ) { free(exp_time); global_no_access_time->ptrs[ (unsigned)item_matched ] = new_exp_time; } } } } } } else msg(LOG_ERR, func, "Maximum global_no_access count reached."); } }
/* * This function always runs in a forked process. */ idresult_e log_remote_user( const struct server *serp, unsigned timeout ) { static char buf[ IBUFSIZE ] ; int cc ; union xsockaddr sin_local, sin_remote, sin_contact, sin_bind; volatile unsigned local_port; volatile unsigned remote_port; int sd ; socklen_t sin_len ; char *p ; const char *func = "log_remote_user" ; if ( timeout && signal( SIGALRM, sigalrm_handler ) == SIG_ERR ) { msg( LOG_ERR, func, "signal: %m" ) ; return( IDR_ERROR ) ; } /* * Determine local and remote addresses */ sin_len = sizeof( sin_local ) ; if ( getsockname( SERVER_FD( serp ), &sin_local.sa, &sin_len ) == -1 ) { msg( LOG_ERR, func, "(%d) getsockname: %m", getpid() ) ; return( IDR_ERROR ) ; } if ( CONN_XADDRESS( SERVER_CONNECTION( serp ) ) == NULL ) { /* * This shouldn't happen since identification only works for * connection-based services. */ msg( LOG_ERR, func, "connection has no address" ) ; return( IDR_ERROR ) ; } CLEAR( sin_contact ); sin_remote = *CONN_XADDRESS( SERVER_CONNECTION( serp ) ) ; sin_contact = sin_remote; memcpy( &sin_bind, &sin_local, sizeof(sin_bind) ) ; local_port = 0; remote_port = 0; if( sin_remote.sa.sa_family == AF_INET ) { local_port = ntohs( sin_local.sa_in6.sin6_port ) ; remote_port = ntohs( sin_remote.sa_in6.sin6_port ) ; sin_contact.sa_in6.sin6_port = htons( IDENTITY_SERVICE_PORT ) ; sin_bind.sa_in.sin_port = 0 ; } else if( sin_remote.sa.sa_family == AF_INET6 ) { local_port = ntohs( sin_local.sa_in.sin_port ) ; remote_port = ntohs( sin_remote.sa_in.sin_port ) ; sin_contact.sa_in.sin_port = htons( IDENTITY_SERVICE_PORT ) ; sin_bind.sa_in6.sin6_port = 0 ; } /* * Create a socket, bind it, and set the close-on-exec flag on the * descriptor. We set the flag in case we are called as part of a * successful attempt to start a server (i.e. execve will follow). * The socket must be bound to the receiving address or ident might * fail for multi-homed hosts. */ sd = socket( sin_remote.sa.sa_family, SOCK_STREAM, 0 ) ; if ( sd == -1 ) { msg( LOG_ERR, func, "socket creation: %m" ) ; return( IDR_ERROR ) ; } if ( bind(sd, &sin_bind.sa, sizeof(sin_bind.sa)) == -1 ) { msg( LOG_ERR, func, "socket bind: %m" ) ; (void) Sclose( sd ) ; return( IDR_ERROR ) ; } if ( fcntl( sd, F_SETFD, FD_CLOEXEC ) == -1 ) { msg( LOG_ERR, func, "fcntl F_SETFD: %m" ) ; (void) Sclose( sd ) ; return( IDR_ERROR ) ; } if ( timeout ) { if ( sigsetjmp( env, 1 ) == 0 ) START_TIMER( timeout ) ; else { Sclose( sd ) ; return( IDR_TIMEDOUT ) ; } } if ( connect( sd, &sin_contact.sa, sizeof( sin_contact ) ) == -1 ) { if ( timeout ) { STOP_TIMER() ; signal ( SIGALRM, SIG_DFL ) ; } Sclose( sd ); return( IDR_NOSERVER ) ; } cc = strx_nprint( buf, sizeof( buf ), "%d,%d\r\n", remote_port, local_port ) ; if ( write_buf( sd, buf, cc ) == FAILED ) { if ( timeout ) { STOP_TIMER() ; signal ( SIGALRM, SIG_DFL ) ; } Sclose( sd ); return( IDR_ERROR ) ; } p = get_line( sd, buf, sizeof( buf ) ) ; if ( timeout ) { STOP_TIMER() ; signal ( SIGALRM, SIG_DFL ) ; } if ( p == NULL ) { Sclose( sd ); return( IDR_RESPERR ) ; } /* * Verify that the received line is OK */ if ( ( p = verify_line( buf, local_port, remote_port ) ) == NULL ) { msg(LOG_ERR, func, "Bad line received from identity server at %s: %s", xaddrname( &sin_remote ), buf ) ; Sclose( sd ); return( IDR_BADRESP ) ; } svc_logprint( SERVER_CONNSERVICE( serp ), USERID_ENTRY, "%s", p ) ; return( IDR_OK ) ; }