* Initial commit.
authorUrban Wallasch <urban.wallasch@freenet.de>
Wed, 30 May 2018 17:02:22 +0000 (19:02 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Wed, 30 May 2018 17:02:22 +0000 (19:02 +0200)
.gitignore [new file with mode: 0644]
build.sh [new file with mode: 0755]
fident.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..428f06f
--- /dev/null
@@ -0,0 +1,2 @@
+fident
+fident_dbg
diff --git a/build.sh b/build.sh
new file mode 100755 (executable)
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 (file)
index 0000000..16c5277
--- /dev/null
+++ b/fident.c
@@ -0,0 +1,204 @@
+#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