Browse Source

ckdb - disallow web usernames like BTC addresses

master
kanoi 10 years ago
parent
commit
03efdd0332
  1. 8
      src/ckdb.c
  2. 11
      src/ckdb.h
  3. 21
      src/ckdb_cmd.c
  4. 49
      src/ckdb_data.c

8
src/ckdb.c

@ -174,8 +174,12 @@ const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.
const char *idpatt = "^[_A-Za-z][_A-Za-z0-9]*$"; const char *idpatt = "^[_A-Za-z][_A-Za-z0-9]*$";
const char *intpatt = "^[0-9][0-9]*$"; const char *intpatt = "^[0-9][0-9]*$";
const char *hashpatt = "^[A-Fa-f0-9]*$"; const char *hashpatt = "^[A-Fa-f0-9]*$";
// TODO: bitcoind will check it properly /* BTC addresses start with '1' (one) or '3' (three),
const char *addrpatt = "^[A-Za-z0-9]*$"; * exclude: capital 'I' (eye), capital 'O' (oh),
* lowercase 'l' (elle) and '0' (zero)
* and with a simple test must be ADDR_MIN_LEN to ADDR_MAX_LEN (ckdb.h)
* bitcoind is used to fully validate them when required */
const char *addrpatt = "^[13][A-HJ-NP-Za-km-z1-9]*$";
// So the records below have the same 'name' as the klist // So the records below have the same 'name' as the klist
const char Transfer[] = "Transfer"; const char Transfer[] = "Transfer";

11
src/ckdb.h

@ -52,7 +52,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "0.9.4" #define DB_VERSION "0.9.4"
#define CKDB_VERSION DB_VERSION"-0.631" #define CKDB_VERSION DB_VERSION"-0.640"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -80,6 +80,14 @@ extern const char *intpatt;
extern const char *hashpatt; extern const char *hashpatt;
extern const char *addrpatt; extern const char *addrpatt;
/* If a trimmed username is like an address but this many or more characters,
* disallow it */
#define ADDR_USER_CHECK 16
// BTC address size
#define ADDR_MIN_LEN 26
#define ADDR_MAX_LEN 34
typedef struct loadstatus { typedef struct loadstatus {
tv_t oldest_sharesummary_firstshare_n; tv_t oldest_sharesummary_firstshare_n;
tv_t newest_sharesummary_firstshare_a; tv_t newest_sharesummary_firstshare_a;
@ -1334,6 +1342,7 @@ extern PGconn *dbconnect();
extern char *safe_text(char *txt); extern char *safe_text(char *txt);
extern void username_trim(USERS *users); extern void username_trim(USERS *users);
extern bool like_address(char *username);
extern void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS); extern void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS);

21
src/ckdb_cmd.c

@ -15,7 +15,7 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
{ {
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
K_ITEM *i_username, *i_emailaddress, *i_passwordhash, *u_item; K_ITEM *i_username, *i_emailaddress, *i_passwordhash, *u_item = NULL;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@ -23,11 +23,22 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
if (!i_username) if (!i_username)
return strdup(reply); return strdup(reply);
i_emailaddress = require_name(trf_root, "emailaddress", 7, (char *)mailpatt, reply, siz); /* If a username added from the web site looks like an address
* then disallow it - a false positive is not an issue
* Allowing it will create a security issue - someone could create
* an account with someone else's, as yet unused, payout address
* and redirect the payout to another payout address.
* ... and the person who owns the payout address can't check that
* in advance, they'll just find out with their first payout not
* arriving at their payout address */
if (!like_address(transfer_data(i_username))) {
i_emailaddress = require_name(trf_root, "emailaddress", 7,
(char *)mailpatt, reply, siz);
if (!i_emailaddress) if (!i_emailaddress)
return strdup(reply); return strdup(reply);
i_passwordhash = require_name(trf_root, "passwordhash", 64, (char *)hashpatt, reply, siz); i_passwordhash = require_name(trf_root, "passwordhash", 64,
(char *)hashpatt, reply, siz);
if (!i_passwordhash) if (!i_passwordhash)
return strdup(reply); return strdup(reply);
@ -35,6 +46,7 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
transfer_data(i_emailaddress), transfer_data(i_emailaddress),
transfer_data(i_passwordhash), transfer_data(i_passwordhash),
by, code, inet, now, trf_root); by, code, inet, now, trf_root);
}
if (!u_item) { if (!u_item) {
LOGERR("%s() %s.failed.DBE", __func__, id); LOGERR("%s() %s.failed.DBE", __func__, id);
@ -223,7 +235,8 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
email = NULL; email = NULL;
} }
i_address = optional_name(trf_root, "address", i_address = optional_name(trf_root, "address",
27, (char *)addrpatt, ADDR_MIN_LEN,
(char *)addrpatt,
reply, siz); reply, siz);
if (i_address) if (i_address)
address = transfer_data(i_address); address = transfer_data(i_address);

49
src/ckdb_data.c

@ -67,6 +67,55 @@ void username_trim(USERS *users)
} }
} }
/* Is the trimmed username like an address?
* False positive is OK (i.e. 'like')
* Before checking, it is trimmed to avoid web display confusion
* Length check is done before trimming - this may give a false
* positive on any username with lots of trim characters ... which is OK */
bool like_address(char *username)
{
char *tmp, *front, *trail;
size_t len;
regex_t re;
int ret;
len = strlen(username);
if (len < ADDR_USER_CHECK)
return false;
tmp = strdup(username);
front = tmp;
while (*front && TRIM_IGNORE(*front))
front++;
trail = front + strlen(front) - 1;
while (trail >= front) {
if (TRIM_IGNORE(*trail))
*(trail--) = '\0';
else
break;
}
if (regcomp(&re, addrpatt, REG_NOSUB) != 0) {
LOGEMERG("%s(): failed to compile addrpatt '%s'",
__func__, addrpatt);
free(tmp);
// This will disable adding any new usernames ...
return true;
}
ret = regexec(&re, front, (size_t)0, NULL, 0);
regfree(&re);
if (ret == 0) {
free(tmp);
return true;
}
free(tmp);
return false;
}
void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS) void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS)
{ {
char *tmp; char *tmp;

Loading…
Cancel
Save