From 8dcd43a1ae254d4c693af983c1f684ae93275069 Mon Sep 17 00:00:00 2001 From: Urban Wallasch Date: Wed, 30 May 2018 19:02:22 +0200 Subject: [PATCH] * Initial commit. --- .gitignore | 2 + build.sh | 4 ++ fident.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 .gitignore create mode 100755 build.sh create mode 100644 fident.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..428f06f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +fident +fident_dbg diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..a53c995 --- /dev/null +++ b/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +cc -Wall -Wextra -std=c99 -pedantic -ofident -lpthread fident.c +strip fident +cc -Wall -Wextra -std=c99 -pedantic -DDEBUG -ofident_dbg -lpthread fident.c diff --git a/fident.c b/fident.c new file mode 100644 index 0000000..16c5277 --- /dev/null +++ b/fident.c @@ -0,0 +1,204 @@ +#define _DEFAULT_SOURCE + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef DEBUG + #define DPRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); }while(0) +#else + #define DPRINT(...) do{;}while(0) +#endif + +typedef + struct { + int sd; + struct sockaddr_in addr; + socklen_t addrlen; + } + srvarg_t; + +static void die( const char *msg ) +{ + perror( msg ); + exit( EXIT_FAILURE ); +} + +static void droproot( const char *uname, const char *gname ) +{ + const struct group *gr = getgrnam( gname ); + const struct passwd *pw = getpwnam( uname ); + + if ( NULL == gr ) + die( gname ); + if ( NULL == pw ) + die( uname ); + + const gid_t newgid = gr->gr_gid; + const uid_t newuid = pw->pw_uid; + const gid_t oldgid = getegid(); + const uid_t olduid = geteuid(); + + if ( 0 == olduid ) + setgroups( 1, &newgid ); + if ( newgid != oldgid && 0 != setregid( newgid, newgid ) ) + die( "setregid" ); + if ( newuid != olduid && 0 != setreuid( newuid, newuid ) ) + die( "setreuid" ); + + /* Check by trying to regain old IDs: */ + if ( newgid != oldgid && ( 0 == setegid( oldgid ) || getegid() != newgid ) ) + die( "setegid" ); + if ( newuid != olduid && ( 0 == seteuid( olduid ) || geteuid() != newuid ) ) + die( "seteuid" ); + + DPRINT( "EGID=%d, EUID=%d\n", getegid(), geteuid() ); +} + + +// #define DFLT_MSG "ERROR : UNKNOWN-ERROR" +#define DFLT_MSG "USERID : OTHER : UNKNOWN" + +static void *servlet( void *parg ) +{ + srvarg_t *arg = parg; + uint16_t ps = 0, pc = 0; + int sd = arg->sd; + ssize_t rb = 0; + char buf[200] = ""; + char rsp[400] = ""; + char *ep = NULL; + struct timeval timeout; + + timeout.tv_sec = 3; + timeout.tv_usec = 0; + setsockopt( sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout ); + DPRINT( "(%s:%d) ", inet_ntoa( arg->addr.sin_addr ), (int)arg->addr.sin_port ); + rb = recv( sd, buf, sizeof buf - 1, 0 ); + if ( 0 < rb ) + { + buf[rb] = '\0'; + ep = buf; + while ( *ep ) + if ( '\r' == *ep || '\n' == *ep ) + *ep = '\0'; + else + ++ep; + DPRINT( "[%s] ", buf ); + if ( 2 == sscanf( buf, "%"SCNu16" ,%"SCNu16" ", &ps, &pc ) + && 0 < snprintf( rsp, sizeof rsp, "%"PRIu16" , %"PRIu16" : %s\r\n", ps, pc, DFLT_MSG ) ) + { + DPRINT( "%s", rsp ); + send( sd, rsp, strlen( rsp ), 0 ); + } + } + DPRINT( "%s", *rsp ? "" : "\n" ); + close( sd ); + free( parg ); + return 0; +} + +int main( int argc, char *argv[] ) +{ + struct sockaddr_in addr; + int sd, port; + const int enable = 1; + + if ( argc != 2 ) + { + fprintf( stderr, "usage: %s \n", argv[0] ); + exit( EXIT_FAILURE ); + } + + if ( !isdigit( argv[1][0] ) ) + { + struct servent *srv = getservbyname( argv[1], "tcp" ); + if ( srv == NULL ) + die( argv[1] ); + DPRINT( "%s: port=%d\n", srv->s_name, ntohs( srv->s_port ) ); + port = srv->s_port; + } + else + { + port = atoi( argv[1] ); + DPRINT( "port=%d\n", port ); + port = htons( port ); + } + + sd = socket( PF_INET, SOCK_STREAM, 0 ); + if ( sd < 0 ) + die( "socket" ); + if ( 0 > setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof enable ) ) + die( "setsockopt(SO_REUSEADDR)" ); + + memset( &addr, 0, sizeof addr ); + addr.sin_family = AF_INET; + addr.sin_port = port; + addr.sin_addr.s_addr = INADDR_ANY; + if ( bind( sd, (struct sockaddr*)&addr, sizeof addr ) != 0 ) + die( "bind" ); + + droproot( "nobody", "nogroup" ); + + if ( listen( sd, 10 ) != 0 ) + die( "listen" ); + + puts( "" ); + + while ( 1 ) + { + int csd; + socklen_t addrlen = sizeof addr; + + if ( 0 > ( csd = accept( sd, (struct sockaddr *)&addr, &addrlen ) ) ) + { + switch ( errno ) + { + case EBADF: + case EFAULT: + case EINVAL: + case ENOTSOCK: + case EOPNOTSUPP: + case EPROTO: + die( "accept" ); + break; + default: + break; + } + } + else + { + srvarg_t *parg; + pthread_t child; + + if ( NULL != ( parg = malloc( sizeof *parg ) ) ) + { + if ( sizeof addr < addrlen ) + addrlen = sizeof addr; + memcpy( &parg->addr, &addr, addrlen ); + parg->addrlen = addrlen; + parg->sd = csd; + if ( 0 != pthread_create( &child, 0, servlet, (void *)parg ) ) + free( parg ); + else /* parg is free'd in child! */ + pthread_detach( child ); + } + } + sleep( 1 ); /* hard throttle */ + } +} -- 2.30.2