* This file is licenced under the 3-clause BSD Licence. See the file
* COPYING for full details.
*/
+//#define DEBUG_TRACE_SERVER 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
#include <netdb.h> // gethostbyname
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h> // close/getuid
#include <limits.h> // INT_MIN/INT_MAX
#include <stdarg.h>
+#include <ctype.h> // isdigit
#include "common.h"
// === PROTOTYPES ===
return -1;
}
-// printf("geteuid() = %i, getuid() = %i\n", geteuid(), getuid());
-
if( geteuid() == 0 || getuid() == 0 )
{
int i;
}
if( i == 1024 )
printf("Warning: AUTOAUTH unavaliable\n");
-// else
-// printf("Bound to 0.0.0.0:%i\n", i);
}
if( connect(sock, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0 ) {
return 0;
}
+int DispenseCheckPin(int Socket, const char *Username, 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_CHECK %s %s\n", Username, Pin);
+ buf = ReadLine(Socket);
+
+ responseCode = atoi(buf);
+ switch( responseCode )
+ {
+ case 200: // Pin correct
+ printf("Pin OK\n");
+ ret = 0;
+ break;
+ case 201:
+ printf("Pin incorrect\n");
+ ret = RV_INVALID_USER;
+ break;
+ case 401:
+ printf("Not authenticated\n");
+ ret = RV_PERMISSIONS;
+ break;
+ case 403:
+ printf("Only coke members can check accounts other than their own\n");
+ ret = RV_PERMISSIONS;
+ break;
+ case 404:
+ printf("User '%s' not found\n", Username);
+ ret = RV_INVALID_USER;
+ break;
+ case 407:
+ printf("Rate limited or client-server disagree on pin format\n");
+ ret = RV_SERVER_ERROR;
+ break;
+ default:
+ printf("Unknown response code %i ('%s')\n", responseCode, buf);
+ ret = RV_UNKNOWN_ERROR;
+ break;
+ }
+ free(buf);
+ 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
rv = RV_BAD_ITEM;
break;
case 403: // Not in coke
- fprintf(stderr, "You are not in coke (sucker)\n");
+ fprintf(stderr, "Permissions error: %s\n", buf+4);
rv = RV_PERMISSIONS;
break;
case 404: // Unknown user
switch(responseCode)
{
case 200: return 0; // OK
- case 403: // Not in coke
+ case 403: // Not an administrator
fprintf(stderr, "You are not an admin\n");
return RV_PERMISSIONS;
case 404: // Unknown user
// ===
// Helpers
// ===
+/// Read from the input socket until a newline is seen
char *ReadLine(int Socket)
{
static char buf[BUFSIZ];
- static int bufPos = 0;
static int bufValid = 0;
- int len;
+ int len = 0;
char *newline = NULL;
int retLen = 0;
- char *ret = malloc(10);
+ char *ret = malloc(32);
#if DEBUG_TRACE_SERVER
printf("ReadLine: ");
ret[0] = '\0';
+ // While a newline hasn't been seen
while( !newline )
{
+ assert(bufValid < BUFSIZ);
+ // If there is data left over from a previous call, use the data from that for the first pass
if( bufValid ) {
len = bufValid;
+ bufValid = 0;
}
else {
- len = recv(Socket, buf+bufPos, BUFSIZ-1-bufPos, 0);
+ // Otherwise read some data
+ len = recv(Socket, buf, BUFSIZ, 0);
if( len <= 0 ) {
free(ret);
return strdup("599 Client Connection Error\n");
}
}
- buf[bufPos+len] = '\0';
+ assert(len < BUFSIZ);
+ buf[len] = '\0';
- newline = strchr( buf+bufPos, '\n' );
+ // Search for newline in buffer
+ newline = strchr( buf, '\n' );
if( newline ) {
*newline = '\0';
}
- retLen += strlen(buf+bufPos);
+ // Increment return length by amount of data up to newline (or end of read)
+ retLen += strlen(buf);
ret = realloc(ret, retLen + 1);
- strcat( ret, buf+bufPos );
-
- if( newline ) {
- int newLen = newline - (buf+bufPos) + 1;
- bufValid = len - newLen;
- len = newLen;
- }
- if( len + bufPos == BUFSIZ - 1 ) bufPos = 0;
- else bufPos += len;
+ assert(ret); // evil NULL check
+ strcat( ret, buf ); // append buffer data
}
#if DEBUG_TRACE_SERVER
printf("%i '%s'\n", retLen, ret);
#endif
+
+ // If the newline wasn't the last character in the buffer. (I.e. there's extra data for the next call)
+ assert(newline - buf + 1 <= len);
+ if( newline - buf + 1 < len ) {
+ int extra_bytes = len - (newline - buf + 1);
+ // Copy `extra_bytes` from end of buffer down to start and set `bufValid` to `extra_bytes`?
+ memmove(&buf[0], newline + 1, extra_bytes);
+ bufValid = extra_bytes;
+
+ #if DEBUG_TRACE_SERVER > 1
+ printf("- Caching %i bytes '%.*s'\n", bufValid, bufValid, buf);
+ #endif
+ }
return ret;
}