X-Git-Url: https://git.ucc.asn.au/?p=tpg%2Fopendispense2.git;a=blobdiff_plain;f=src%2Fserver%2Fserver.c;h=66d10627290d1a9d3a82b1b46a3f6d0fa7fffe59;hp=1f813d4c577d87f0ccb0e61d24d7b664069aab8e;hb=0da15449ea2ea9f32612cb249b4709ee54df4761;hpb=399c1a3a2a1eb9c81ec0f7bdfb1512bdd2e41c6a diff --git a/src/server/server.c b/src/server/server.c index 1f813d4..66d1062 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -18,9 +18,12 @@ #include #include #include -#include +#include // Signal handling +#include // AUTHIDENT +#include // time(2) #define DEBUG_TRACE_CLIENT 0 +#define HACK_NO_REFUNDS 1 // Statistics #define MAX_CONNECTION_QUEUE 5 @@ -32,6 +35,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 { @@ -57,6 +63,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); @@ -87,6 +94,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}, @@ -151,7 +159,6 @@ void Server_Start(void) // Fork into background if( gbServer_RunInBackground ) { - int newin, newout, newerr; int pid = fork(); if( pid == -1 ) { fprintf(stderr, "ERROR: Unable to fork\n"); @@ -160,17 +167,26 @@ void Server_Start(void) } if( pid != 0 ) { // Parent, quit + printf("Forked child %i\n", pid); exit(0); } // In child // - Sort out stdin/stdout - newin = open("/dev/null", O_RDONLY); - newout = open(gsServer_LogFile, O_CREAT|O_APPEND, 0644); - newerr = open(gsServer_ErrorLog, O_CREAT|O_APPEND, 0644); - dup2(newin, 0); - dup2(newout, 1); - dup2(newerr, 2); + #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); + fprintf(stdout, "OpenDispense 2 Server Started at %lld\n", (long long)time(NULL)); + fprintf(stderr, "OpenDispense 2 Server Started at %lld\n", (long long)time(NULL)); + #endif } + + // Start the helper thread + StartPeriodicThread(); // Listen if( listen(giServer_Socket, MAX_CONNECTION_QUEUE) < 0 ) { @@ -234,12 +250,14 @@ 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 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 + // case 0x825F0D42: // 130.95.13.66 heathred (Clubroom) bTrusted = 1; break; default: @@ -507,6 +525,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) @@ -515,6 +538,95 @@ 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) == -1 ) { + Debug(Client, "500 getpeername() failed\n"); + perror("Getting AUTHIDENT peer name"); + sendf(Client->Socket, "500 getpeername() failed\n"); + return ; + } + + client_ip = client_addr.sin_addr.s_addr; + if(giDebugLevel >= 2) { + Debug(Client, "client_ip = %x, ntohl(client_ip) = %x", client_ip, ntohl(client_ip)); + } + 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"); + return ; + } + + // 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 */ @@ -570,6 +682,13 @@ void Server_Cmd_SETEUSER(tClient *Client, char *Args) return ; } } + + // Disabled accounts + if( userFlags & USER_FLAG_DISABLED ) { + Client->UID = -1; + sendf(Client->Socket, "403 Account disabled\n"); + return ; + } sendf(Client->Socket, "200 User set\n"); } @@ -728,7 +847,7 @@ void Server_Cmd_DISPENSE(tClient *Client, char *Args) case 1: sendf(Client->Socket, "501 Unable to dispense\n"); return ; case 2: sendf(Client->Socket, "402 Poor You\n"); return ; default: - sendf(Client->Socket, "500 Dispense Error\n"); + sendf(Client->Socket, "500 Dispense Error (%i)\n", ret); return ; } } @@ -910,6 +1029,24 @@ 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 ) + { + sendf(Client->Socket, "499 Don't use `dispense acct` for refunds, use `dispense refund` (and `dispense -G` to get item IDs)\n"); + return ; + } + #endif + // Get recipient uid = Bank_GetAcctByName(user, 0); if( uid == -1 ) { @@ -1313,8 +1450,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");