#include <string.h>
#define MAX_CONNECTION_QUEUE 5
-#define INPUT_BUFFER_SIZE 128
+#define INPUT_BUFFER_SIZE 256
+
+#define HASH_TYPE SHA512
+#define HASH_LENGTH 64
#define MSG_STR_TOO_LONG "499 Command too long (limit "EXPSTR(INPUT_BUFFER_SIZE)")\n"
typedef struct sClient
{
int ID; // Client ID
+
+ int bIsTrusted; // Is the connection from a trusted host/port
char *Username;
char Salt[9];
// === PROTOTYPES ===
void Server_Start(void);
-void Server_HandleClient(int Socket);
+void Server_HandleClient(int Socket, int bTrusted);
char *Server_ParseClientCommand(tClient *Client, char *CommandString);
+// --- Commands ---
char *Server_Cmd_USER(tClient *Client, char *Args);
+char *Server_Cmd_PASS(tClient *Client, char *Args);
+char *Server_Cmd_AUTOAUTH(tClient *Client, char *Args);
+// --- Helpers ---
+void HexBin(uint8_t *Dest, char *Src, int BufSize);
// === GLOBALS ===
int giServer_Port = 1020;
char *Name;
char *(*Function)(tClient *Client, char *Arguments);
} gaServer_Commands[] = {
- {"USER", Server_Cmd_USER}
+ {"USER", Server_Cmd_USER},
+ {"PASS", Server_Cmd_PASS},
+ {"AUTOAUTH", Server_Cmd_AUTOAUTH}
};
#define NUM_COMMANDS (sizeof(gaServer_Commands)/sizeof(gaServer_Commands[0]))
for(;;)
{
uint len = sizeof(client_addr);
+ int bTrusted = 0;
client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &len);
if(client_socket < 0) {
if(giDebugLevel >= 2) {
char ipstr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, ipstr, INET_ADDRSTRLEN);
- printf("Client connection from %s\n", ipstr);
+ printf("Client connection from %s:%i\n",
+ ipstr, ntohs(client_addr.sin_port));
+ }
+
+ // Trusted Connections
+ if( ntohs(client_addr.sin_port) < 1024 )
+ {
+ // TODO: Make this runtime configurable
+ switch( ntohl( client_addr.sin_addr.s_addr ) )
+ {
+ case 0x7F000001: // 127.0.0.1 localhost
+ //case 0x825E0D00: // 130.95.13.0
+ case 0x825E0D12: // 130.95.13.18 mussel
+ case 0x825E0D17: // 130.95.13.23 martello
+ bTrusted = 1;
+ break;
+ default:
+ break;
+ }
}
// TODO: Multithread this?
- Server_HandleClient(client_socket);
+ Server_HandleClient(client_socket, bTrusted);
close(client_socket);
}
/**
* \brief Reads from a client socket and parses the command strings
* \param Socket Client socket number/handle
+ * \param bTrusted Is the client trusted?
*/
-void Server_HandleClient(int Socket)
+void Server_HandleClient(int Socket, int bTrusted)
{
char inbuf[INPUT_BUFFER_SIZE];
char *buf = inbuf;
// Initialise Client info
clientInfo.ID = giServer_NextClientID ++;
-
+ clientInfo.bIsTrusted = bTrusted;
+
// Read from client
/*
* Notes:
fprintf(stderr, "ERROR: Unable to recieve from client on socket %i\n", Socket);
return ;
}
+
+ if(giDebugLevel >= 2) {
+ printf("Client %i: Disconnected\n", clientInfo.ID);
+ }
}
/**
free(Client->Username);
Client->Username = strdup(Args);
+ #if USE_SALT
// Create a salt (that changes if the username is changed)
+ // Yes, I know, I'm a little paranoid, but who isn't?
Client->Salt[0] = 0x21 + (rand()&0x3F);
Client->Salt[1] = 0x21 + (rand()&0x3F);
Client->Salt[2] = 0x21 + (rand()&0x3F);
// "100 Salt xxxxXXXX\n"
ret = strdup("100 SALT xxxxXXXX\n");
sprintf(ret, "100 SALT %s\n", Client->Salt);
-
+ #else
+ ret = strdup("100 User Set\n");
+ #endif
return ret;
}
+
+/**
+ * \brief Authenticate as a user
+ *
+ * Usage: PASS <hash>
+ */
+char *Server_Cmd_PASS(tClient *Client, char *Args)
+{
+ uint8_t clienthash[HASH_LENGTH] = {0};
+
+ // Read user's hash
+ HexBin(clienthash, Args, HASH_LENGTH);
+
+ if( giDebugLevel ) {
+ int i;
+ printf("Client %i: Password hash ", Client->ID);
+ for(i=0;i<HASH_LENGTH;i++)
+ printf("%02x", clienthash[i]&0xFF);
+ printf("\n");
+ }
+
+ return strdup("401 Auth Failure\n");
+}
+
+/**
+ * \brief Authenticate as a user without a password
+ *
+ * Usage: AUTOAUTH <user>
+ */
+char *Server_Cmd_AUTOAUTH(tClient *Client, char *Args)
+{
+ char *spos = strchr(Args, ' ');
+ if(spos) *spos = '\0'; // Remove characters after the ' '
+
+ // Check if trusted
+ if( !Client->bIsTrusted ) {
+ if(giDebugLevel)
+ printf("Client %i: Untrusted client attempting to AUTOAUTH\n", Client->ID);
+ return strdup("401 Untrusted\n");
+ }
+
+ // Get UID
+ Client->UID = GetUserID( Args );
+ if( Client->UID < 0 ) {
+ if(giDebugLevel)
+ printf("Client %i: Unknown user '%s'\n", Client->ID, Args);
+ return strdup("401 Auth Failure\n");
+ }
+
+ if(giDebugLevel)
+ printf("Client %i: Authenticated as '%s' (%i)\n", Client->ID, Args, Client->UID);
+
+ return strdup("200 Auth OK\n");
+}
+
+// --- INTERNAL HELPERS ---
+// TODO: Move to another file
+void HexBin(uint8_t *Dest, char *Src, int BufSize)
+{
+ int i;
+ for( i = 0; i < BufSize; i ++ )
+ {
+ uint8_t val = 0;
+
+ if('0' <= *Src && *Src <= '9')
+ val |= (*Src-'0') << 4;
+ else if('A' <= *Src && *Src <= 'F')
+ val |= (*Src-'A'+10) << 4;
+ else if('a' <= *Src && *Src <= 'f')
+ val |= (*Src-'a'+10) << 4;
+ else
+ break;
+ Src ++;
+
+ if('0' <= *Src && *Src <= '9')
+ val |= (*Src-'0');
+ else if('A' <= *Src && *Src <= 'F')
+ val |= (*Src-'A'+10);
+ else if('a' <= *Src && *Src <= 'f')
+ val |= (*Src-'a'+10);
+ else
+ break;
+ Src ++;
+
+ Dest[i] = val;
+ }
+ for( ; i < BufSize; i++ )
+ Dest[i] = 0;
+}
+
+/**
+ * \brief Decode a Base64 value
+ */
+int UnBase64(uint8_t *Dest, char *Src, int BufSize)
+{
+ uint32_t val;
+ int i, j;
+ char *start_src = Src;
+
+ for( i = 0; i+2 < BufSize; i += 3 )
+ {
+ val = 0;
+ for( j = 0; j < 4; j++, Src ++ ) {
+ if('A' <= *Src && *Src <= 'Z')
+ val |= (*Src - 'A') << ((3-j)*6);
+ else if('a' <= *Src && *Src <= 'z')
+ val |= (*Src - 'a' + 26) << ((3-j)*6);
+ else if('0' <= *Src && *Src <= '9')
+ val |= (*Src - '0' + 52) << ((3-j)*6);
+ else if(*Src == '+')
+ val |= 62 << ((3-j)*6);
+ else if(*Src == '/')
+ val |= 63 << ((3-j)*6);
+ else if(!*Src)
+ break;
+ else if(*Src != '=')
+ j --; // Ignore invalid characters
+ }
+ Dest[i ] = (val >> 16) & 0xFF;
+ Dest[i+1] = (val >> 8) & 0xFF;
+ Dest[i+2] = val & 0xFF;
+ if(j != 4) break;
+ }
+
+ // Finish things off
+ if(i < BufSize)
+ Dest[i] = (val >> 16) & 0xFF;
+ if(i+1 < BufSize)
+ Dest[i+1] = (val >> 8) & 0xFF;
+
+ return Src - start_src;
+}