#include "compat.h"
#include <libconfig.h>
#include "backuppcd-auth.h"

struct bpcd_auth_userinfo;
struct bpcd_auth_userinfo {
	const char *username;
	const char *passhash;
	backuppc_privs_t privs;
	struct bpcd_auth_userinfo *_next;
};

struct bpcd_auth_userinfo *userlist = NULL;

static int bpcd_auth_opt_user(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra) {
	struct bpcd_auth_userinfo *newnode;
	char *valcopy_s, *valcopy;
	char *privstr;

	newnode = malloc(sizeof(*newnode));
	if (newnode == NULL) {
		return(LC_CBRET_ERROR);
	}

	valcopy_s = valcopy = strdup(value);

	newnode->username = strsep(&valcopy, " ,\t");
	if (newnode->username == NULL) {
		free(valcopy_s);
		free(newnode);
		fprintf(stderr, "error: usage: USER <Username> <Password> <Privilegs>\n");
		return(LC_CBRET_ERROR);
	}

	newnode->passhash = strsep(&valcopy, " ,\t");
	if (newnode->passhash == NULL) {
		free(valcopy_s);
		free(newnode);
		fprintf(stderr, "error: usage: USER <Username> <Password> <Privilegs>\n");
		return(LC_CBRET_ERROR);
	}

	privstr = strsep(&valcopy, " ,\t");
	if (privstr == NULL) {
		free(valcopy_s);
		free(newnode);
		fprintf(stderr, "error: usage: USER <Username> <Password> <Privilegs>\n");
		return(LC_CBRET_ERROR);
	}

	if (strlen(newnode->passhash) != 40) {
		free(valcopy_s);
		free(newnode);
		fprintf(stderr, "error: Password hash must be exactly 40 charectars long.\n");
		return(LC_CBRET_ERROR);
	}

	if (strcasecmp(privstr, "Read") == 0) {
		newnode->privs = BPC_PRIV_READ;
	} else if (strcasecmp(privstr, "Write") == 0) {
		newnode->privs = BPC_PRIV_WRITE;
	} else if (strcasecmp(privstr, "ReadWrite") == 0) {
		newnode->privs = BPC_PRIV_RDWR;
	} else if (strcasecmp(privstr, "RD") == 0) {
		newnode->privs = BPC_PRIV_READ;
	} else if (strcasecmp(privstr, "WR") == 0) {
		newnode->privs = BPC_PRIV_WRITE;
	} else if (strcasecmp(privstr, "RDWR") == 0) {
		newnode->privs = BPC_PRIV_RDWR;
	} else if (strcasecmp(privstr, "r") == 0) {
		newnode->privs = BPC_PRIV_READ;
	} else if (strcasecmp(privstr, "w") == 0) {
		newnode->privs = BPC_PRIV_WRITE;
	} else if (strcasecmp(privstr, "rw") == 0) {
		newnode->privs = BPC_PRIV_RDWR;
	} else {
		free(valcopy_s);
		free(newnode);
		fprintf(stderr, "error: usage: Privileges must be one of: READ, WRITE, or READWRITE\n");
		return(LC_CBRET_ERROR);
	}

	newnode->_next = userlist;
	userlist = newnode;

	return(LC_CBRET_OKAY);
}

void bpcd_auth_init(void) {
	lc_register_callback("User", 'u', LC_VAR_STRING, bpcd_auth_opt_user, NULL);
	return;
}

backuppc_privs_t bpcd_auth_verify(const char *username, const char *passhash, uint32_t address) {
	struct bpcd_auth_userinfo *tmp;

	for (tmp = userlist; tmp; tmp = tmp->_next) {

		/*
		 * Should the username be case-sensitive ? (XXX)
		 */
		if (strcasecmp(tmp->username, username) == 0) {
			if (strcasecmp(tmp->passhash, passhash) == 0) {
				return(tmp->privs);
			} else {
				return(BPC_PRIV_ERROR);
			}
		}
	}

	return(BPC_PRIV_ERROR);
}
