Merge branch 'master' of ssh.ucc.asn.au:tpg/opendispense2
[tpg/opendispense2.git] / src / server / server.c
index 01e2d84..4404f9e 100644 (file)
@@ -17,6 +17,7 @@
 #include <string.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <signal.h>
 
 #define        DEBUG_TRACE_CLIENT      0
 
@@ -59,6 +60,7 @@ void  Server_Cmd_SETEUSER(tClient *Client, char *Args);
 void   Server_Cmd_ENUMITEMS(tClient *Client, char *Args);
 void   Server_Cmd_ITEMINFO(tClient *Client, char *Args);
 void   Server_Cmd_DISPENSE(tClient *Client, char *Args);
+void   Server_Cmd_REFUND(tClient *Client, char *Args);
 void   Server_Cmd_GIVE(tClient *Client, char *Args);
 void   Server_Cmd_DONATE(tClient *Client, char *Args);
 void   Server_Cmd_ADD(tClient *Client, char *Args);
@@ -68,6 +70,7 @@ void  Server_Cmd_USERINFO(tClient *Client, char *Args);
 void   _SendUserInfo(tClient *Client, int UserID);
 void   Server_Cmd_USERADD(tClient *Client, char *Args);
 void   Server_Cmd_USERFLAGS(tClient *Client, char *Args);
+void   Server_Cmd_UPDATEITEM(tClient *Client, char *Args);
 // --- Helpers ---
 void   Debug(tClient *Client, const char *Format, ...);
  int   sendf(int Socket, const char *Format, ...);
@@ -87,6 +90,7 @@ const struct sClientCommand {
        {"ENUM_ITEMS", Server_Cmd_ENUMITEMS},
        {"ITEM_INFO", Server_Cmd_ITEMINFO},
        {"DISPENSE", Server_Cmd_DISPENSE},
+       {"REFUND", Server_Cmd_REFUND},
        {"GIVE", Server_Cmd_GIVE},
        {"DONATE", Server_Cmd_DONATE},
        {"ADD", Server_Cmd_ADD},
@@ -94,14 +98,21 @@ const struct sClientCommand {
        {"ENUM_USERS", Server_Cmd_ENUMUSERS},
        {"USER_INFO", Server_Cmd_USERINFO},
        {"USER_ADD", Server_Cmd_USERADD},
-       {"USER_FLAGS", Server_Cmd_USERFLAGS}
+       {"USER_FLAGS", Server_Cmd_USERFLAGS},
+       {"UPDATE_ITEM", Server_Cmd_UPDATEITEM}
 };
 #define NUM_COMMANDS   ((int)(sizeof(gaServer_Commands)/sizeof(gaServer_Commands[0])))
 
 // === GLOBALS ===
- int   giServer_Port = 1020;
- int   giServer_NextClientID = 1;
- int   giServer_Socket;
+// - Configuration
+ int   giServer_Port = 11020;
+ int   gbServer_RunInBackground = 0;
+char   *gsServer_LogFile = "/var/log/dispsrv.log";
+char   *gsServer_ErrorLog = "/var/log/dispsrv.err";
+// - State variables
+ int   giServer_Socket;        // Server socket
+ int   giServer_NextClientID = 1;      // Debug client ID
 
 // === CODE ===
 /**
@@ -113,6 +124,8 @@ void Server_Start(void)
        struct sockaddr_in      server_addr, client_addr;
 
        atexit(Server_Cleanup);
+       // Ignore SIGPIPE (stops crashes when the client exits early)
+       signal(SIGPIPE, SIG_IGN);
 
        // Create Server
        giServer_Socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -133,6 +146,26 @@ void Server_Start(void)
                perror("Binding");
                return ;
        }
+
+#if 0
+       if( gbServer_RunInBackground )
+       {
+               int pid = fork();
+               if( pid == -1 ) {
+                       fprintf(stderr, "ERROR: Unable to fork\n");
+                       perror("fork background");
+                       exit(-1);
+               }
+               if( pid != 0 ) {
+                       // Parent, quit
+                       exit(0);
+               }
+               // In child, sort out stdin/stdout
+               reopen(0, "/dev/null", O_READ);
+               reopen(1, gsServer_LogFile, O_CREAT|O_APPEND);
+               reopen(2, gsServer_ErrorLog, O_CREAT|O_APPEND);
+       }
+#endif
        
        // Listen
        if( listen(giServer_Socket, MAX_CONNECTION_QUEUE) < 0 ) {
@@ -143,6 +176,15 @@ void Server_Start(void)
        
        printf("Listening on 0.0.0.0:%i\n", giServer_Port);
        
+       // write pidfile
+       {
+               FILE *fp = fopen("/var/run/dispsrv.pid", "w");
+               if( fp ) {
+                       fprintf(fp, "%i", getpid());
+                       fclose(fp);
+               }
+       }
+
        for(;;)
        {
                uint    len = sizeof(client_addr);
@@ -191,6 +233,7 @@ void Server_Start(void)
                        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
                                bTrusted = 1;
                                break;
@@ -208,8 +251,9 @@ void Server_Start(void)
 
 void Server_Cleanup(void)
 {
-       printf("Close(%i)\n", giServer_Socket);
+       printf("\nClose(%i)\n", giServer_Socket);
        close(giServer_Socket);
+       unlink("/var/run/dispsrv.pid");
 }
 
 /**
@@ -303,6 +347,7 @@ void Server_ParseClientCommand(tClient *Client, char *CommandString)
        
        if( Server_int_ParseArgs(1, CommandString, &command, &args, NULL) )
        {
+               if( command == NULL )   return ;
 //             printf("command=%s, args=%s\n", command, args);
                // Is this an error? (just ignore for now)
                //args = "";
@@ -377,7 +422,8 @@ void Server_Cmd_USER(tClient *Client, char *Args)
 void Server_Cmd_PASS(tClient *Client, char *Args)
 {
        char    *passhash;
-       
+        int    flags;
+
        if( Server_int_ParseArgs(0, Args, &passhash, NULL) )
        {
                sendf(Client->Socket, "407 PASS takes 1 argument\n");
@@ -387,13 +433,25 @@ void Server_Cmd_PASS(tClient *Client, char *Args)
        // Pass on to cokebank
        Client->UID = Bank_GetUserAuth(Client->Salt, Client->Username, passhash);
 
-       if( Client->UID != -1 ) {
-               Client->bIsAuthed = 1;
-               sendf(Client->Socket, "200 Auth OK\n");
+       if( Client->UID == -1 ) {
+               sendf(Client->Socket, "401 Auth Failure\n");
+               return ;
+       }
+
+       flags = Bank_GetFlags(Client->UID);
+       if( flags & USER_FLAG_DISABLED ) {
+               Client->UID = -1;
+               sendf(Client->Socket, "403 Account Disabled\n");
+               return ;
+       }
+       if( flags & USER_FLAG_INTERNAL ) {
+               Client->UID = -1;
+               sendf(Client->Socket, "403 Internal account\n");
                return ;
        }
        
-       sendf(Client->Socket, "401 Auth Failure\n");
+       Client->bIsAuthed = 1;
+       sendf(Client->Socket, "200 Auth OK\n");
 }
 
 /**
@@ -404,6 +462,7 @@ void Server_Cmd_PASS(tClient *Client, char *Args)
 void Server_Cmd_AUTOAUTH(tClient *Client, char *Args)
 {
        char    *username;
+        int    userflags;
        
        if( Server_int_ParseArgs(0, Args, &username, NULL) )
        {
@@ -424,16 +483,24 @@ void Server_Cmd_AUTOAUTH(tClient *Client, char *Args)
        if( Client->UID < 0 ) {
                if(giDebugLevel)
                        Debug(Client, "Unknown user '%s'", username);
-               sendf(Client->Socket, "401 Auth Failure\n");
+               sendf(Client->Socket, "403 Auth Failure\n");
                return ;
        }
        
+       userflags = Bank_GetFlags(Client->UID);
        // You can't be an internal account
-       if( Bank_GetFlags(Client->UID) & USER_FLAG_INTERNAL ) {
+       if( userflags & USER_FLAG_INTERNAL ) {
                if(giDebugLevel)
                        Debug(Client, "Autoauth as '%s', not allowed", username);
                Client->UID = -1;
-               sendf(Client->Socket, "401 Auth Failure\n");
+               sendf(Client->Socket, "403 Account is internal\n");
+               return ;
+       }
+
+       // Disabled accounts
+       if( userflags & USER_FLAG_DISABLED ) {
+               Client->UID = -1;
+               sendf(Client->Socket, "403 Account disabled\n");
                return ;
        }
 
@@ -451,6 +518,7 @@ void Server_Cmd_AUTOAUTH(tClient *Client, char *Args)
 void Server_Cmd_SETEUSER(tClient *Client, char *Args)
 {
        char    *username;
+        int    eUserFlags, userFlags;
        
        if( Server_int_ParseArgs(0, Args, &username, NULL) )
        {
@@ -464,7 +532,8 @@ void Server_Cmd_SETEUSER(tClient *Client, char *Args)
        }
 
        // Check user permissions
-       if( !(Bank_GetFlags(Client->UID) & (USER_FLAG_COKE|USER_FLAG_ADMIN)) ) {
+       userFlags = Bank_GetFlags(Client->UID);
+       if( !(userFlags & (USER_FLAG_COKE|USER_FLAG_ADMIN)) ) {
                sendf(Client->Socket, "403 Not in coke\n");
                return ;
        }
@@ -477,10 +546,20 @@ void Server_Cmd_SETEUSER(tClient *Client, char *Args)
        }
        
        // You can't be an internal account
-       if( Bank_GetFlags(Client->EffectiveUID) & USER_FLAG_INTERNAL ) {
-               Client->EffectiveUID = -1;
-               sendf(Client->Socket, "404 User not found\n");
-               return ;
+       if( !(userFlags & USER_FLAG_ADMIN) )
+       {
+               eUserFlags = Bank_GetFlags(Client->EffectiveUID);
+               if( eUserFlags & USER_FLAG_INTERNAL ) {
+                       Client->EffectiveUID = -1;
+                       sendf(Client->Socket, "404 User not found\n");
+                       return ;
+               }
+               // Disabled only avaliable to admins
+               if( eUserFlags & USER_FLAG_DISABLED ) {
+                       Client->EffectiveUID = -1;
+                       sendf(Client->Socket, "403 Account disabled\n");
+                       return ;
+               }
        }
        
        sendf(Client->Socket, "200 User set\n");
@@ -641,6 +720,54 @@ void Server_Cmd_DISPENSE(tClient *Client, char *Args)
        }
 }
 
+void Server_Cmd_REFUND(tClient *Client, char *Args)
+{
+       tItem   *item;
+        int    uid, price_override = 0;
+       char    *username, *itemname, *price_str;
+
+       if( Server_int_ParseArgs(0, Args, &username, &itemname, &price_str, NULL) ) {
+               if( !itemname || price_str ) {
+                       sendf(Client->Socket, "407 REFUND takes 2 or 3 arguments\n");
+                       return ;
+               }
+       }
+
+       if( !Client->bIsAuthed ) {
+               sendf(Client->Socket, "401 Not Authenticated\n");
+               return ;
+       }
+
+       // Check user permissions
+       if( !(Bank_GetFlags(Client->UID) & (USER_FLAG_COKE|USER_FLAG_ADMIN))  ) {
+               sendf(Client->Socket, "403 Not in coke\n");
+               return ;
+       }
+
+       uid = Bank_GetAcctByName(username);
+       if( uid == -1 ) {
+               sendf(Client->Socket, "404 Unknown user\n");
+               return ;
+       }
+       
+       item = _GetItemFromString(itemname);
+       if( !item ) {
+               sendf(Client->Socket, "406 Bad Item ID\n");
+               return ;
+       }
+
+       if( price_str )
+               price_override = atoi(price_str);
+
+       switch( DispenseRefund( Client->UID, uid, item, price_override ) )
+       {
+       case 0: sendf(Client->Socket, "200 Item Refunded\n");   return ;
+       default:
+               sendf(Client->Socket, "500 Dispense Error\n");
+               return;
+       }
+}
+
 void Server_Cmd_GIVE(tClient *Client, char *Args)
 {
        char    *recipient, *ammount, *reason;
@@ -666,10 +793,10 @@ void Server_Cmd_GIVE(tClient *Client, char *Args)
        }
        
        // You can't alter an internal account
-       if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) {
-               sendf(Client->Socket, "404 Invalid target user\n");
-               return ;
-       }
+//     if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) {
+//             sendf(Client->Socket, "404 Invalid target user\n");
+//             return ;
+//     }
 
        // Parse ammount
        iAmmount = atoi(ammount);
@@ -777,9 +904,13 @@ void Server_Cmd_ADD(tClient *Client, char *Args)
        }
        
        // You can't alter an internal account
-       if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) {
-               sendf(Client->Socket, "404 Invalid user\n");
-               return ;
+       if( !(Bank_GetFlags(Client->UID) & USER_FLAG_ADMIN) )
+       {
+               if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) {
+                       sendf(Client->Socket, "404 Invalid user\n");
+                       return ;
+               }
+               // TODO: Maybe disallow changes to disabled?
        }
 
        // Parse ammount
@@ -832,12 +963,6 @@ void Server_Cmd_SET(tClient *Client, char *Args)
                sendf(Client->Socket, "404 Invalid user\n");
                return ;
        }
-       
-       // You can't alter an internal account
-       if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) {
-               sendf(Client->Socket, "404 Invalid user\n");
-               return ;
-       }
 
        // Parse ammount
        iAmmount = atoi(ammount);
@@ -1162,6 +1287,52 @@ void Server_Cmd_USERFLAGS(tClient *Client, char *Args)
        sendf(Client->Socket, "200 User Updated\n");
 }
 
+void Server_Cmd_UPDATEITEM(tClient *Client, char *Args)
+{
+       char    *itemname, *price_str, *description;
+        int    price;
+       tItem   *item;
+       
+       if( Server_int_ParseArgs(1, Args, &itemname, &price_str, &description, NULL) ) {
+               sendf(Client->Socket, "407 UPDATE_ITEM takes 3 arguments\n");
+               return ;
+       }
+       
+       if( !Client->bIsAuthed ) {
+               sendf(Client->Socket, "401 Not Authenticated\n");
+               return ;
+       }
+
+       // Check user permissions
+       if( !(Bank_GetFlags(Client->UID) & (USER_FLAG_COKE|USER_FLAG_ADMIN))  ) {
+               sendf(Client->Socket, "403 Not in coke\n");
+               return ;
+       }
+       
+       item = _GetItemFromString(itemname);
+       if( !item ) {
+               // TODO: Create item?
+               sendf(Client->Socket, "406 Bad Item ID\n");
+               return ;
+       }
+       
+       price = atoi(price_str);
+       if( price <= 0 && price_str[0] != '0' ) {
+               sendf(CLient->Socket, "407 Invalid price set\n");
+       }
+       
+       // Update the item
+       free(item->Name);
+       item->Name = strdup(description);
+       item->Price = price;
+       
+       // Update item file
+       Items_UpdateFile();
+       
+       // Return OK
+       sendf(Client->Socket, "200 Item updated\n");
+}
+
 // --- INTERNAL HELPERS ---
 void Debug(tClient *Client, const char *Format, ...)
 {

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