[PATCH] server - allow IDENT auth by anyone from a trusted subnet
[tpg/opendispense2.git] / src / server / server.c
index 483806a..21740fd 100644 (file)
@@ -19,6 +19,7 @@
 #include <limits.h>
 #include <stdarg.h>
 #include <signal.h>
+#include <ident.h>
 
 #define        DEBUG_TRACE_CLIENT      0
 #define HACK_NO_REFUNDS        1
@@ -33,6 +34,9 @@
 
 #define MSG_STR_TOO_LONG       "499 Command too long (limit "EXPSTR(INPUT_BUFFER_SIZE)")\n"
 
+#define IDENT_TRUSTED_NETWORK 0x825F0D00
+#define IDENT_TRUSTED_NETMASK 0xFFFFFFC0
+
 // === TYPES ===
 typedef struct sClient
 {
@@ -58,6 +62,7 @@ void  Server_ParseClientCommand(tClient *Client, char *CommandString);
 void   Server_Cmd_USER(tClient *Client, char *Args);
 void   Server_Cmd_PASS(tClient *Client, char *Args);
 void   Server_Cmd_AUTOAUTH(tClient *Client, char *Args);
+void   Server_Cmd_AUTHIDENT(tClient *Client, char *Args);
 void   Server_Cmd_SETEUSER(tClient *Client, char *Args);
 void   Server_Cmd_ENUMITEMS(tClient *Client, char *Args);
 void   Server_Cmd_ITEMINFO(tClient *Client, char *Args);
@@ -88,6 +93,7 @@ const struct sClientCommand {
        {"USER", Server_Cmd_USER},
        {"PASS", Server_Cmd_PASS},
        {"AUTOAUTH", Server_Cmd_AUTOAUTH},
+       {"AUTHIDENT", Server_Cmd_AUTHIDENT},
        {"SETEUSER", Server_Cmd_SETEUSER},
        {"ENUM_ITEMS", Server_Cmd_ENUMITEMS},
        {"ITEM_INFO", Server_Cmd_ITEMINFO},
@@ -164,9 +170,15 @@ void Server_Start(void)
                }
                // In child
                // - Sort out stdin/stdout
+               #if 0
                dup2( open("/dev/null", O_RDONLY, 0644), STDIN_FILENO );
                dup2( open(gsServer_LogFile, O_CREAT|O_APPEND, 0644), STDOUT_FILENO );
                dup2( open(gsServer_ErrorLog, O_CREAT|O_APPEND, 0644), STDERR_FILENO );
+               #else
+               freopen("/dev/null", "r", stdin);
+               freopen(gsServer_LogFile, "a", stdout);
+               freopen(gsServer_ErrorLog, "a", stderr);
+               #endif
        }
 
        // Start the helper thread
@@ -235,13 +247,13 @@ void Server_Start(void)
                        case 0x7F000001:        // 127.0.0.1    localhost
                //      case 0x825F0D00:        // 130.95.13.0
                        case 0x825F0D04:        // 130.95.13.4  merlo
-                       case 0x825F0D05:        // 130.95.13.5  heathred (MR)
+               //      case 0x825F0D05:        // 130.95.13.5  heathred (MR)
                        case 0x825F0D07:        // 130.95.13.7  motsugo
                        case 0x825F0D11:        // 130.95.13.17 mermaid
                        case 0x825F0D12:        // 130.95.13.18 mussel
                        case 0x825F0D17:        // 130.95.13.23 martello
                        case 0x825F0D2A:        // 130.95.13.42 meersau
-                       case 0x825F0D42:        // 130.95.13.66 heathred (Clubroom)
+               //      case 0x825F0D42:        // 130.95.13.66 heathred (Clubroom)
                                bTrusted = 1;
                                break;
                        default:
@@ -509,6 +521,11 @@ void Server_Cmd_AUTOAUTH(tClient *Client, char *Args)
                return ;
        }
 
+       // Save username
+       if(Client->Username)
+               free(Client->Username);
+       Client->Username = strdup(username);
+
        Client->bIsAuthed = 1;
        
        if(giDebugLevel)
@@ -517,6 +534,88 @@ void Server_Cmd_AUTOAUTH(tClient *Client, char *Args)
        sendf(Client->Socket, "200 Auth OK\n");
 }
 
+/**
+ * \brief Authenticate as a user using the IDENT protocol
+ *
+ * Usage: AUTHIDENT
+ */
+void Server_Cmd_AUTHIDENT(tClient *Client, char *Args)
+{
+       char    *username;
+        int    userflags;
+       const int ident_timeout = 5;
+       socklen_t len;
+       struct sockaddr_in client_addr;
+       uint32_t  client_ip;
+
+       if( Args != NULL && strlen(Args) ) {
+               sendf(Client->Socket, "407 AUTHIDENT takes no arguments\n");
+               return ;
+       }
+
+       // Check if trusted (only works with INET sockets at present)
+       len = sizeof(client_addr);
+       if ( ! getpeername(Client->Socket, (struct sockaddr*)&client_addr, &len) ) {
+               // throw an error
+       }
+
+       client_ip = client_addr.sin_addr.s_addr;
+       if ( ! (ntohl(client_ip) == 0x7F000001 || ( (ntohl(client_ip) & IDENT_TRUSTED_NETMASK) == IDENT_TRUSTED_NETWORK ) )) {
+                       if(giDebugLevel)
+                               Debug(Client, "Untrusted client attempting to AUTHIDENT");
+                       sendf(Client->Socket, "401 Untrusted\n");
+                       return ;
+       }
+
+       // Get username via IDENT
+       username = ident_id(Client->Socket, ident_timeout);
+       if (!username) {
+               sendf(Client->Socket, "403 Authentication failure: IDENT auth timed out\n");
+       }
+
+       // Get UID
+       Client->UID = Bank_GetAcctByName( username, 0 );
+       if( Client->UID < 0 ) {
+               if(giDebugLevel)
+                       Debug(Client, "Unknown user '%s'", username);
+               sendf(Client->Socket, "403 Authentication failure: unknown account\n");
+               free(username);
+               return ;
+       }
+
+       userflags = Bank_GetFlags(Client->UID);
+       // You can't be an internal account
+       if( userflags & USER_FLAG_INTERNAL ) {
+               if(giDebugLevel)
+                       Debug(Client, "IDENT auth as '%s', not allowed", username);
+               Client->UID = -1;
+               sendf(Client->Socket, "403 Authentication failure: that account is internal\n");
+               free(username);
+               return ;
+       }
+
+       // Disabled accounts
+       if( userflags & USER_FLAG_DISABLED ) {
+               Client->UID = -1;
+               sendf(Client->Socket, "403 Authentication failure: account disabled\n");
+               free(username);
+               return ;
+       }
+
+       // Save username
+       if(Client->Username)
+               free(Client->Username);
+       Client->Username = strdup(username);
+
+       Client->bIsAuthed = 1;
+
+       if(giDebugLevel)
+               Debug(Client, "IDENT authenticated as '%s' (%i)", username, Client->UID);
+       free(username);
+
+       sendf(Client->Socket, "200 Auth OK\n");
+}
+
 /**
  * \brief Set effective user
  */
@@ -912,6 +1011,16 @@ void Server_Cmd_ADD(tClient *Client, char *Args)
                return ;
        }
 
+       #if !ROOT_CAN_ADD
+       if( strcmp( Client->Username, "root" ) == 0 ) {
+               // Allow adding for new users
+               if( strcmp(reason, "treasurer: new user") != 0 ) {
+                       sendf(Client->Socket, "403 Root may not add\n");
+                       return ;
+               }
+       }
+       #endif
+
        #if HACK_NO_REFUNDS
        if( strstr(reason, "refund") != NULL || strstr(reason, "misdispense") != NULL )
        {
@@ -1323,8 +1432,8 @@ void Server_Cmd_USERFLAGS(tClient *Client, char *Args)
        Bank_SetFlags(uid, mask, value);
 
        // Log the change
-       Log_Info("Updated '%s' with flag set '%s' - Reason: %s",
-               username, flags, reason);
+       Log_Info("Updated '%s' with flag set '%s' by '%s' - Reason: %s",
+               username, flags, Client->Username, reason);
        
        // Return OK
        sendf(Client->Socket, "200 User Updated\n");

UCC git Repository :: git.ucc.asn.au