080a160c7b9595d516c9c70e83689a09b60839d0 galt Mon Jun 3 12:16:53 2013 -0700 fix SQL Injection diff --git src/hg/inc/jksql.h src/hg/inc/jksql.h index 84e950d..1a2ed94 100644 --- src/hg/inc/jksql.h +++ src/hg/inc/jksql.h @@ -7,41 +7,35 @@ * * To use - first open a connection, then pass a SQL query to * sqlGetResult, then use sqlNextRow to examine result row by * row. The returned row is just an array of strings. Use * sqlUnsigned, sqlSigned, and atof to convert numeric results * to normal form. * * These routines will all print an error message and abort if * there's a problem, cleaning up open connections, etc. on abort * (or on program exit). Do a pushAbortHandler if you want to * catch the aborts. The error messages from bad SQL syntax * are actually pretty good (they're just passed on from * mySQL). */ #ifndef JKSQL_H #define JKSQL_H -#ifndef SQLNUM_H -#include "sqlNum.h" -#endif -#ifndef SQLLIST_H +#include "sqlNum.h" #include "sqlList.h" -#endif - -#ifndef HASH_H #include "hash.h" -#endif +#include "dystring.h" extern char *defaultProfileName; // name of default profile struct sqlConnection *sqlConnect(char *database); /* Connect to database on default host as default user. */ struct sqlConnection *sqlMayConnect(char *database); /* Connect to database on default host as default user. * Return NULL (don't abort) on failure. */ struct sqlConnection *sqlConnectProfile(char *profileName, char *database); /* Connect to profile or database using the specified profile. Can specify * profileName, database, or both. The profile is the prefix to the host, * user, and password variables in .hg.conf. For the default profile of "db", * the environment variables HGDB_HOST, HGDB_USER, and HGDB_PASSWORD can @@ -204,30 +198,37 @@ struct sqlResult *sqlGetResult(struct sqlConnection *sc, char *query); /* (Returns NULL if result was empty. : * old info, only applies with mysql_store_result not mysql_use_result) * Otherwise returns a structure that you can do sqlRow() on. */ char *sqlEscapeString(const char* from); /* Prepares string for inclusion in a SQL statement . Remember to free * returned string. Returned string contains strlen(length)*2+1 as many bytes * as orig because in worst case every character has to be escaped.*/ char *sqlEscapeString2(char *to, const char* from); /* Prepares a string for inclusion in a sql statement. Output string * must be 2*strlen(from)+1 */ +unsigned long sqlEscapeString3(char *to, const char* from); +/* Prepares a string for inclusion in a sql statement. Output string + * must be 2*strlen(from)+1. Returns actual escaped size not counting term 0. */ + +void sqlDyAppendEscaped(struct dyString *dy, char *s); +/* Append to dy an escaped s */ + char *sqlEscapeTabFileString2(char *to, const char *from); /* Escape a string for including in a tab seperated file. Output string * must be 2*strlen(from)+1 */ struct sqlResult *sqlMustGetResult(struct sqlConnection *sc, char *query); /* Query database. * old comment: If result empty squawk and die. * This only applied back when sqlGetResult was using mysql_store_result. * These days, with mysql_use_result, we cannot know ahead of time * if there are results, we can only know by actually trying to fetch a row. * At then how would we put it back? So in fact right now sqlMustGetResult * is no different than sqlGetResult. */ void sqlFreeResult(struct sqlResult **pRes); /* Free up a result. */ @@ -542,16 +543,132 @@ void sqlWarnings(struct sqlConnection *conn, int numberOfWarnings); /* Show the number of warnings requested. New feature in mysql5. */ void sqlDump(FILE *fh); /* dump internal info about SQL configuration for debugging purposes */ void sqlPrintStats(FILE *fh); /* print statistic about the number of connections and other options done by * this process. */ struct sqlResult *sqlStoreResult(struct sqlConnection *sc, char *query); /* Returns NULL if result was empty. Otherwise returns a structure * that you can do sqlRow() on. Same interface as sqlGetResult, * but internally this keeps the entire result in memory. */ + + +/* --------- input checks to prevent sql injection --------------------------------------- */ + +#define sqlCkQl sqlCheckQuotedLiteral +char *sqlCheckQuotedLiteral(char *s); +/* Check that none of the chars needing to be escaped are in the string s */ + +char *sqlCheckAlphaNum(char *word); +/* Check that only valid alpha numeric characters are used in word */ + +char *sqlEscapeIfNeeded(char *s, char **pS); +/* Escape if needed. if *pS is not null, free it. */ + +#define sqlCkIl sqlCheckIdentifiersList +char *sqlCheckIdentifiersList(char *identifiers); +/* Check that only valid identifier characters are used in a comma-separated list */ + +#define sqlCkId sqlCheckIdentifier +char *sqlCheckIdentifier(char *identifier); +/* Check that only valid identifier characters are used */ + +#define sqlCkTbl sqlCheckTableName +char *sqlCheckTableName(char *table); +/* check that only valid table name characters are used */ + +char *sqlCheckCgiEncodedName(char *name); +/* check that only valid cgi-encoded characters are used */ + + +// ============================= + +int vaSqlSafefNoAbort(char* buffer, int bufSize, boolean newString, char *format, va_list args); +/* Format string to buffer, vsprintf style, only with buffer overflow + * checking. The resulting string is always terminated with zero byte. + * Scans string parameters for illegal sql chars. */ + +int vaSqlSafef(char* buffer, int bufSize, char *format, va_list args); +/* Format string to buffer, vsprintf style, only with buffer overflow + * checking. The resulting string is always terminated with zero byte. */ + +int sqlSafef(char* buffer, int bufSize, char *format, ...) +/* Format string to buffer, vsprintf style, only with buffer overflow + * checking. The resulting string is always terminated with zero byte. + * Scans string parameters for illegal sql chars. */ +#ifdef __GNUC__ +__attribute__((format(printf, 3, 4))) +#endif +; + + +int vaSqlSafefFrag(char* buffer, int bufSize, char *format, va_list args); +/* Format string to buffer, vsprintf style, only with buffer overflow + * checking. The resulting string is always terminated with zero byte. + * This version does not add the tag since it is assumed to be just a fragment of + * the entire sql string. */ + +int sqlSafefFrag(char* buffer, int bufSize, char *format, ...) +/* Format string to buffer, vsprintf style, only with buffer overflow + * checking. The resulting string is always terminated with zero byte. + * Scans string parameters for illegal sql chars. + * This version does not add the NOSQLINJ tag since it is assumed to be just a fragment of + * the entire sql string. */ +#ifdef __GNUC__ +__attribute__((format(printf, 3, 4))) +#endif +; + + +void sqlDyStringVaPrintfExt(struct dyString *ds, boolean isFrag, char *format, va_list args); +/* VarArgs Printf to end of dyString after scanning string parameters for illegal sql chars. */ + +void sqlDyStringVaPrintf(struct dyString *ds, char *format, va_list args); +/* VarArgs Printf to end of dyString after scanning string parameters for illegal sql chars. */ + +void sqlDyStringPrintf(struct dyString *ds, char *format, ...) +/* Printf to end of dyString after scanning string parameters for illegal sql chars. */ +#ifdef __GNUC__ +__attribute__((format(printf, 2, 3))) +#endif +; + +void sqlDyStringVaPrintfFrag(struct dyString *ds, char *format, va_list args); +/* VarArgs Printf to end of dyString after scanning string parameters for illegal sql chars. NOSLQINJ tag is not added. */ + +void sqlDyStringPrintfFrag(struct dyString *ds, char *format, ...) +/* Printf to end of dyString after scanning string parameters for illegal sql chars. NOSLQINJ tag is not added. */ +#ifdef __GNUC__ +__attribute__((format(printf, 2, 3))) +#endif +; + +void sqlDyStringAppend(struct dyString *ds, char *string); +/* Append zero terminated string to end of dyString. + * Make sure the NOSQLINJ prefix gets added if needed */ + +char *sqlDyStringFrag(struct dyString *ds); +/* If ds is only a sql fragment, do not need leading NOSQLINJ tag */ + +struct dyString *sqlDyStringCreate(char *format, ...) +/* Create a dyString with a printf style initial content + * Make sure the NOSQLINJ prefix gets added if needed */ +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +; + +void sqlCheckError(char *format, ...) +/* A sql injection error has occurred. Check for settings and respond + * as appropriate with error, warning, ignore, dumpstack. + * Then abort if needed. NOTE: unless it aborts, this function will return! */ +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +; + #endif /* JKSQL_H */