-#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
+#define _DEFAULT_SOURCE
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <pthread.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#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 <protocol or portnum>\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 */
+ }
+}