From ee724c0360fac7840d032812b5ab677aa0d15074 Mon Sep 17 00:00:00 2001
From: John Hodge <tpg@ucc.asn.au>
Date: Sat, 12 Jan 2013 21:55:24 +0800
Subject: [PATCH] Implimented pin checks fully

---
 src/client/common.h   |  2 ++
 src/client/main.c     | 51 ++++++++++++++++++++++++++++++++++++++++++-
 src/client/protocol.c | 48 ++++++++++++++++++++++++++++++++++++++--
 src/server/server.c   | 26 +++++++++++++++-------
 4 files changed, 116 insertions(+), 11 deletions(-)

diff --git a/src/client/common.h b/src/client/common.h
index 4c592ff..2ac604f 100644
--- a/src/client/common.h
+++ b/src/client/common.h
@@ -87,6 +87,8 @@ extern void	_PrintUserLine(const char *Line);
 extern int	Dispense_AddUser(int Socket, const char *Username);
 extern int	Dispense_SetUserType(int Socket, const char *Username, const char *TypeString, const char *Reason);
 extern int	Dispense_SetItem(int Socket, const char *Type, int ID, int NewPrice, const char *NewName);
+extern int	DispenseCheckPin(int Socket, const char *Username, const char *Pin);
+extern int	DispenseSetPin(int Socket, const char *Pin);
 
 #endif
 
diff --git a/src/client/main.c b/src/client/main.c
index 444ab34..da301be 100644
--- a/src/client/main.c
+++ b/src/client/main.c
@@ -12,7 +12,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>	// isspace
-#include <unistd.h>	// close
+#include <pwd.h>	// getpwuids
+#include <unistd.h>	// close/getuid
 #include <limits.h>	// INT_MIN/INT_MAX
 #include "common.h"
 
@@ -637,6 +638,54 @@ int main(int argc, char *argv[])
 		close(sock);
 		return ret;
 	}
+	// Check a user's pin
+	else if(strcmp(gsTextArgs[0], "pincheck") == 0)
+	{
+		if( giTextArgc < 2 || giTextArgc > 3 ) {
+			fprintf(stderr, "Error: `dispense pincheck` takes one/two arguments\n");
+			ShowUsage();
+			return RV_ARGUMENTS;
+		}
+		struct passwd	*pwd = getpwuid( getuid() );
+		gsUserName = strdup(pwd->pw_name);
+		
+		const char *pin = gsTextArgs[1];
+		const char *user = gsUserName;
+		if( giTextArgc == 3 )
+			user = gsTextArgs[2];
+
+		
+		sock = OpenConnection(gsDispenseServer, giDispensePort);
+		if( sock < 0 )	return RV_SOCKET_ERROR;
+		ret = Authenticate(sock);
+		if(ret)	return ret;
+		
+		ret = DispenseCheckPin(sock, user, pin);
+		
+		close(sock);
+		return ret;
+	}
+	// Update 'your' pin
+	else if(strcmp(gsTextArgs[0], "pinset") == 0)
+	{
+		if( giTextArgc != 2 ) {
+			fprintf(stderr, "Error: `dispense pinset` takes one argument\n");
+			ShowUsage();
+			return RV_ARGUMENTS;
+		}
+		
+		const char *pin = gsTextArgs[1];
+		
+		sock = OpenConnection(gsDispenseServer, giDispensePort);
+		if( sock < 0 )	return RV_SOCKET_ERROR;
+		ret = Authenticate(sock);
+		if(ret)	return ret;
+
+		ret = DispenseSetPin(sock, pin);
+		
+		close(sock);
+		return ret;
+	}
 	// Item name / pattern
 	else
 	{
diff --git a/src/client/protocol.c b/src/client/protocol.c
index ad8a6bf..dae51cb 100644
--- a/src/client/protocol.c
+++ b/src/client/protocol.c
@@ -21,6 +21,7 @@
 #include <unistd.h>	// close/getuid
 #include <limits.h>	// INT_MIN/INT_MAX
 #include <stdarg.h>
+#include <ctype.h>	// isdigit
 #include "common.h"
 
 // === PROTOTYPES ===
@@ -520,14 +521,14 @@ int DispenseCheckPin(int Socket, const char *Username, const char *Pin)
 		return RV_ARGUMENTS;
 	}
 		
-	for( int i = 0; i < 4; i ++ )
+	for( int i = 0; i < 4; i ++ ) {
 		if( !isdigit(Pin[i]) ) {
 			fprintf(stderr, "Pin format incorrect (character %i not a digit)\n", i);
 			return RV_ARGUMENTS;
 		}
 	}
 	
-	sendf(Socket, "CHECK_PIN %s %s\n", Username, Pin);
+	sendf(Socket, "PIN_CHECK %s %s\n", Username, Pin);
 	buf = ReadLine(Socket);
 	
 	responseCode = atoi(buf);
@@ -566,6 +567,49 @@ int DispenseCheckPin(int Socket, const char *Username, const char *Pin)
 	return ret;
 }
 
+int DispenseSetPin(int Socket, const char *Pin)
+{
+	 int	ret, responseCode;
+	char	*buf;
+	
+	if( strlen(Pin) != 4 ) {
+		fprintf(stderr, "Pin format incorrect (not 4 characters long)\n");
+		return RV_ARGUMENTS;
+	}
+		
+	for( int i = 0; i < 4; i ++ ) {
+		if( !isdigit(Pin[i]) ) {
+			fprintf(stderr, "Pin format incorrect (character %i not a digit)\n", i);
+			return RV_ARGUMENTS;
+		}
+	}
+	
+	sendf(Socket, "PIN_SET %s\n", Pin);
+	buf = ReadLine(Socket);
+	
+	responseCode = atoi(buf);
+	switch(responseCode)
+	{
+	case 200:
+		printf("Pin Updated\n");
+		ret = 0;
+		break;
+	case 401:
+		printf("Not authenticated\n");
+		ret = RV_PERMISSIONS;
+		break;
+	case 407:
+		printf("Client/server disagreement on pin format\n");
+		ret = RV_SERVER_ERROR;
+		break;
+	default:
+		printf("Unknown response code %i ('%s')\n", responseCode, buf);
+		ret = RV_UNKNOWN_ERROR;
+		break;
+	}
+	return ret;
+}
+
 /**
  * \brief Dispense an item
  * \return Boolean Failure
diff --git a/src/server/server.c b/src/server/server.c
index 2afd1a7..a48b69a 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -28,6 +28,9 @@
 
 #define PIDFILE	"/var/run/dispsrv.pid"
 
+#define Debug_Notice(msg, v...)	printf("%08llun: "msg"\n", (unsigned long long)time(NULL) ,##v)
+#define Debug_Debug(msg, v...)	printf("%08llud: "msg"\n", (unsigned long long)time(NULL) ,##v)
+
 // Statistics
 #define MAX_CONNECTION_QUEUE	5
 #define INPUT_BUFFER_SIZE	256
@@ -155,7 +158,6 @@ void Server_Start(void)
 		}
 	}
 
-	atexit(Server_Cleanup);
 	// Ignore SIGPIPE (stops crashes when the client exits early)
 	signal(SIGPIPE, SIG_IGN);
 
@@ -176,6 +178,7 @@ void Server_Start(void)
 	if( bind(giServer_Socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0 ) {
 		fprintf(stderr, "ERROR: Unable to bind to 0.0.0.0:%i\n", giServer_Port);
 		perror("Binding");
+		close(giServer_Socket);
 		return ;
 	}
 
@@ -190,7 +193,7 @@ void Server_Start(void)
 		}
 		if( pid != 0 ) {
 			// Parent, quit
-			printf("Forked child %i\n", pid);
+			Debug_Notice("Forked child server as PID %i\n", pid);
 			exit(0);
 		}
 		// In child
@@ -207,6 +210,7 @@ void Server_Start(void)
 		fprintf(stderr, "OpenDispense 2 Server Started at %lld\n", (long long)time(NULL));
 		#endif
 	}
+	atexit(Server_Cleanup);
 
 	// Start the helper thread
 	StartPeriodicThread();
@@ -218,7 +222,7 @@ void Server_Start(void)
 		return ;
 	}
 	
-	printf("Listening on 0.0.0.0:%i\n", giServer_Port);
+	Debug_Notice("Listening on 0.0.0.0:%i", giServer_Port);
 	
 	// write pidfile
 	{
@@ -258,7 +262,7 @@ void Server_Start(void)
 		if(giDebugLevel >= 2) {
 			char	ipstr[INET_ADDRSTRLEN];
 			inet_ntop(AF_INET, &client_addr.sin_addr, ipstr, INET_ADDRSTRLEN);
-			printf("Client connection from %s:%i\n",
+			Debug_Debug("Client connection from %s:%i",
 				ipstr, ntohs(client_addr.sin_port));
 		}
 		
@@ -312,7 +316,7 @@ void Server_Start(void)
 
 void Server_Cleanup(void)
 {
-	printf("\nClose(%i)\n", giServer_Socket);
+	Debug_Debug("Close(%i)", giServer_Socket);
 	close(giServer_Socket);
 	unlink(PIDFILE);
 }
@@ -1560,7 +1564,7 @@ void Server_Cmd_PINCHECK(tClient *Client, char *Args)
 	}
 	pin = atoi(pinstr);
 
-	// Not strictly needed, but ensures that randoms don't do brute forcing
+	// Not authenticated? go away!
 	if( !Client->bIsAuthed ) {
 		sendf(Client->Socket, "401 Not Authenticated\n");
 		return ;
@@ -1591,6 +1595,13 @@ void Server_Cmd_PINCHECK(tClient *Client, char *Args)
 	if( !Bank_IsPinValid(uid, pin) )
 	{
 		sendf(Client->Socket, "201 Pin incorrect\n");
+		struct sockaddr_storage	addr;
+		socklen_t len = sizeof(addr);
+		char ipstr[INET6_ADDRSTRLEN];
+		getpeername(Client->Socket, (void*)&addr, &len);
+		struct sockaddr_in *s = (struct sockaddr_in *)&addr;
+		inet_ntop(addr.ss_family, &s->sin_addr, ipstr, sizeof(ipstr));
+		Debug_Notice("Bad pin from %s for %s by %i", ipstr, username, Client->UID);
 		if( backoff < 5)
 			backoff ++;
 		return ;
@@ -1608,7 +1619,7 @@ void Server_Cmd_PINSET(tClient *Client, char *Args)
 	
 
 	if( Server_int_ParseArgs(0, Args, &pinstr, NULL) ) {
-		sendf(Client->Socket, "407 PIN_SET takes 2 arguments\n");
+		sendf(Client->Socket, "407 PIN_SET takes 1 argument\n");
 		return ;
 	}
 	
@@ -1618,7 +1629,6 @@ void Server_Cmd_PINSET(tClient *Client, char *Args)
 	}
 	pin = atoi(pinstr);
 
-	// Not strictly needed, but ensures that randoms don't do brute forcing
 	if( !Client->bIsAuthed ) {
 		sendf(Client->Socket, "401 Not Authenticated\n");
 		return ;
-- 
GitLab