--- /dev/null
+#define _DEFAULT_SOURCE\r
+\r
+#include <sys/types.h>\r
+#include <sys/socket.h>\r
+\r
+#include <errno.h>\r
+#include <stdint.h>\r
+#include <inttypes.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <unistd.h>\r
+#include <pwd.h>\r
+#include <grp.h>\r
+#include <pthread.h>\r
+#include <netdb.h>\r
+#include <netinet/in.h>\r
+#include <arpa/inet.h>\r
+\r
+\r
+#ifdef DEBUG\r
+ #define DPRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); }while(0)\r
+#else\r
+ #define DPRINT(...) do{;}while(0)\r
+#endif\r
+\r
+typedef\r
+ struct {\r
+ int sd;\r
+ struct sockaddr_in addr;\r
+ socklen_t addrlen;\r
+ }\r
+ srvarg_t;\r
+\r
+static void die( const char *msg )\r
+{\r
+ perror( msg );\r
+ exit( EXIT_FAILURE );\r
+}\r
+\r
+static void droproot( const char *uname, const char *gname )\r
+{\r
+ const struct group *gr = getgrnam( gname );\r
+ const struct passwd *pw = getpwnam( uname );\r
+\r
+ if ( NULL == gr )\r
+ die( gname );\r
+ if ( NULL == pw )\r
+ die( uname );\r
+\r
+ const gid_t newgid = gr->gr_gid;\r
+ const uid_t newuid = pw->pw_uid;\r
+ const gid_t oldgid = getegid();\r
+ const uid_t olduid = geteuid();\r
+\r
+ if ( 0 == olduid )\r
+ setgroups( 1, &newgid );\r
+ if ( newgid != oldgid && 0 != setregid( newgid, newgid ) )\r
+ die( "setregid" );\r
+ if ( newuid != olduid && 0 != setreuid( newuid, newuid ) )\r
+ die( "setreuid" );\r
+\r
+ /* Check by trying to regain old IDs: */\r
+ if ( newgid != oldgid && ( 0 == setegid( oldgid ) || getegid() != newgid ) )\r
+ die( "setegid" );\r
+ if ( newuid != olduid && ( 0 == seteuid( olduid ) || geteuid() != newuid ) )\r
+ die( "seteuid" );\r
+\r
+ DPRINT( "EGID=%d, EUID=%d\n", getegid(), geteuid() );\r
+}\r
+\r
+\r
+// #define DFLT_MSG "ERROR : UNKNOWN-ERROR"\r
+#define DFLT_MSG "USERID : OTHER : UNKNOWN"\r
+\r
+static void *servlet( void *parg )\r
+{\r
+ srvarg_t *arg = parg;\r
+ uint16_t ps = 0, pc = 0;\r
+ int sd = arg->sd;\r
+ ssize_t rb = 0;\r
+ char buf[200] = "";\r
+ char rsp[400] = "";\r
+ char *ep = NULL;\r
+ struct timeval timeout;\r
+\r
+ timeout.tv_sec = 3;\r
+ timeout.tv_usec = 0;\r
+ setsockopt( sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout );\r
+ DPRINT( "(%s:%d) ", inet_ntoa( arg->addr.sin_addr ), (int)arg->addr.sin_port );\r
+ rb = recv( sd, buf, sizeof buf - 1, 0 );\r
+ if ( 0 < rb )\r
+ {\r
+ buf[rb] = '\0';\r
+ ep = buf;\r
+ while ( *ep )\r
+ if ( '\r' == *ep || '\n' == *ep )\r
+ *ep = '\0';\r
+ else\r
+ ++ep;\r
+ DPRINT( "[%s] ", buf );\r
+ if ( 2 == sscanf( buf, "%"SCNu16" ,%"SCNu16" ", &ps, &pc )\r
+ && 0 < snprintf( rsp, sizeof rsp, "%"PRIu16" , %"PRIu16" : %s\r\n", ps, pc, DFLT_MSG ) )\r
+ {\r
+ DPRINT( "%s", rsp );\r
+ send( sd, rsp, strlen( rsp ), 0 );\r
+ }\r
+ }\r
+ DPRINT( "%s", *rsp ? "" : "\n" );\r
+ close( sd );\r
+ free( parg );\r
+ return 0;\r
+}\r
+\r
+int main( int argc, char *argv[] )\r
+{\r
+ struct sockaddr_in addr;\r
+ int sd, port;\r
+ const int enable = 1;\r
+\r
+ if ( argc != 2 )\r
+ {\r
+ fprintf( stderr, "usage: %s <protocol or portnum>\n", argv[0] );\r
+ exit( EXIT_FAILURE );\r
+ }\r
+\r
+ if ( !isdigit( argv[1][0] ) )\r
+ {\r
+ struct servent *srv = getservbyname( argv[1], "tcp" );\r
+ if ( srv == NULL )\r
+ die( argv[1] );\r
+ DPRINT( "%s: port=%d\n", srv->s_name, ntohs( srv->s_port ) );\r
+ port = srv->s_port;\r
+ }\r
+ else\r
+ {\r
+ port = atoi( argv[1] );\r
+ DPRINT( "port=%d\n", port );\r
+ port = htons( port );\r
+ }\r
+\r
+ sd = socket( PF_INET, SOCK_STREAM, 0 );\r
+ if ( sd < 0 )\r
+ die( "socket" );\r
+ if ( 0 > setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof enable ) )\r
+ die( "setsockopt(SO_REUSEADDR)" );\r
+\r
+ memset( &addr, 0, sizeof addr );\r
+ addr.sin_family = AF_INET;\r
+ addr.sin_port = port;\r
+ addr.sin_addr.s_addr = INADDR_ANY;\r
+ if ( bind( sd, (struct sockaddr*)&addr, sizeof addr ) != 0 )\r
+ die( "bind" );\r
+\r
+ droproot( "nobody", "nogroup" );\r
+\r
+ if ( listen( sd, 10 ) != 0 )\r
+ die( "listen" );\r
+\r
+ puts( "" );\r
+\r
+ while ( 1 )\r
+ {\r
+ int csd;\r
+ socklen_t addrlen = sizeof addr;\r
+\r
+ if ( 0 > ( csd = accept( sd, (struct sockaddr *)&addr, &addrlen ) ) )\r
+ {\r
+ switch ( errno )\r
+ {\r
+ case EBADF:\r
+ case EFAULT:\r
+ case EINVAL:\r
+ case ENOTSOCK:\r
+ case EOPNOTSUPP:\r
+ case EPROTO:\r
+ die( "accept" );\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ srvarg_t *parg;\r
+ pthread_t child;\r
+\r
+ if ( NULL != ( parg = malloc( sizeof *parg ) ) )\r
+ {\r
+ if ( sizeof addr < addrlen )\r
+ addrlen = sizeof addr;\r
+ memcpy( &parg->addr, &addr, addrlen );\r
+ parg->addrlen = addrlen;\r
+ parg->sd = csd;\r
+ if ( 0 != pthread_create( &child, 0, servlet, (void *)parg ) )\r
+ free( parg );\r
+ else /* parg is free'd in child! */\r
+ pthread_detach( child );\r
+ }\r
+ }\r
+ sleep( 1 ); /* hard throttle */\r
+ }\r
+}\r