3435a322a06574dc5fa426795597faf62aedcfa1 galt Thu Jun 13 16:08:13 2013 -0700 extending sqlCheckIdentifiersList to support just one literal '.' since it is used by hgTables/bedList.c::bedSqlFieldsExceptForChrom() diff --git src/hg/lib/jksql.c src/hg/lib/jksql.c index 7ac9f5f..9f29626 100644 --- src/hg/lib/jksql.c +++ src/hg/lib/jksql.c @@ -2836,129 +2836,160 @@ static void sqlCheckAllowAlphaChars(char allowed[256]) /* Allow all chars by setting to 0 */ { sqlCheckAllowUpperChars(allowed); sqlCheckAllowLowerChars(allowed); } static void sqlCheckAllowAlphaNumChars(char allowed[256]) /* Allow all chars by setting to 0 */ { sqlCheckAllowAlphaChars(allowed); sqlCheckAllowDigitChars(allowed); } - /* Currently used 10 times in the code via define sqlChkIl. */ char *sqlCheckIdentifiersList(char *identifiers) -/* Check that only valid identifier characters are used in a comma-separated list */ +/* Check that only valid identifier characters are used in a comma-separated list + * '.' is allowed also since some code uses it in place of an actual field name. + * See hgTables/bedList.c::bedSqlFieldsExceptForChrom(). */ { static boolean init = FALSE; static char allowed[256]; if (!init) { sqlCheckDisallowAllChars(allowed); sqlCheckAllowAlphaNumChars(allowed); sqlCheckAllowChar('.', allowed); sqlCheckAllowChar('_', allowed); // sqlTableExists looks like a single table check, but apparently it has become abused // to support multiple tables e.g. sqlTableExists sqlCheckAllowChar(' ', allowed); sqlCheckAllowChar(',', allowed); + sqlCheckAllowChar('\'', allowed); // single quote allowed for special case fieldname is '.' // NOTE it is important for security that no other characters be allowed here init = TRUE; } if (!sqlCheckAllowedChars(identifiers, allowed)) { sqlCheckError("Illegal character found in identifier list %s", identifiers); return identifiers; } // Unfortunately, just checking that the characters are legal is far from enough to ensure safety. // the comma is required. Currently aliases and tick quotes are not supported. int len = strlen(identifiers); char c = 0; int i = 0; boolean needText = TRUE; boolean spaceOk = FALSE; +boolean textDone = FALSE; // Currently identifiers list must start with an identifier, no leading spaces or comma allowed. // Currently the comma must immediately follow the identifier // Currently zero or one spaces may follow the comma // List should end with an identifier. No trailing comma or space allowed. // NOTE it is important for security that commas separate values. // We do not want to support multiple words separated by spaces. while (i < len) { c = identifiers[i]; if (c == ' ') { if (!spaceOk) { sqlCheckError("Invalid Identifiers List [%s] unexpected space character", identifiers); return identifiers; } spaceOk = FALSE; } else if (c == ',') { if (needText) { sqlCheckError("Invalid Identifiers List [%s] unexpected comma character", identifiers); return identifiers; } spaceOk = TRUE; needText = TRUE; + textDone = FALSE; } else // other chars are part of the identifier { + if (textDone) + { + sqlCheckError("Invalid Identifiers List [%s] expected comma", identifiers); + return identifiers; + } needText = FALSE; spaceOk = FALSE; + if (c == '\'') // check for '.' exception allowed + { + if (i+strlen("'.'") > len) + { + sqlCheckError("Invalid Identifiers List [%s] quoted-literal not supported", identifiers); + return identifiers; + } + if (identifiers[i+1] != '.') // next char must be a period + { + sqlCheckError("Invalid Identifiers List [%s] quoted-literal not supported", identifiers); + return identifiers; + } + if (identifiers[i+2] != '\'') // next char must be a single-quote + { + sqlCheckError("Invalid Identifiers List [%s] quoted-literal not supported", identifiers); + return identifiers; + } + i += 2; + textDone = TRUE; + } } ++i; } if (needText || spaceOk) { sqlCheckError("Invalid Identifiers List [%s] unexpected trailing comma or space character", identifiers); return identifiers; } return identifiers; } + char *sqlCheckIdentifier(char *identifier) /* Check that only valid identifier characters are used */ { static boolean init = FALSE; static char allowed[256]; if (!init) { sqlCheckDisallowAllChars(allowed); sqlCheckAllowAlphaNumChars(allowed); sqlCheckAllowChar('.', allowed); sqlCheckAllowChar('_', allowed); // NOTE it is important for security that no other characters be allowed here init = TRUE; } if (!sqlCheckAllowedChars(identifier, allowed)) { sqlCheckError("Illegal character found in identifier %s", identifier); } return identifier; } + /* --------------------------- */ int sqlEscapeAllStrings(char *buffer, char *s, int bufSize, char escPunc) /* Escape all strings demarked by escPunc char. * * Returns final size not including terminating 0. * User needs to pre-allocate enough space that mysql_escape will never run out of space. * This function should be efficient on statements with many strings to be escaped. */ { char *sOrig = s; int sz = 0; int remainder = bufSize; boolean done = FALSE; while (1) { char *start = strchr(s, escPunc);