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 */