080a160c7b9595d516c9c70e83689a09b60839d0
galt
  Mon Jun 3 12:16:53 2013 -0700
fix SQL Injection
diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index ac7647f..c1d9ccb 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -272,31 +272,31 @@
 
 void showExistingSessions(char *userName)
 /* Print out a table with buttons for sharing/unsharing/loading/deleting
  * previously saved sessions. */
 {
 struct sqlConnection *conn = hConnectCentral();
 struct sqlResult *sr = NULL;
 char **row = NULL;
 char query[512];
 boolean foundAny = FALSE;
 char *encUserName = cgiEncodeFull(userName);
 boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0);
 
 printf("<H3>My Sessions</H3>\n");
 printf("<TABLE BORDERWIDTH=0>\n");
-safef(query, sizeof(query), "SELECT sessionName, shared, firstUse from %s "
+sqlSafef(query, sizeof(query), "SELECT sessionName, shared, firstUse from %s "
       "WHERE userName = '%s' ORDER BY sessionName;",
       namedSessionTable, encUserName);
 sr = sqlGetResult(conn, query);
 printf("<TH><TD><B>session name</B></TD><TD><B>created on</B></TD><TD align=center><B>use this&nbsp;<BR>session&nbsp;</B></TD>"
        "<TD align=center><B>delete this&nbsp;<BR>session&nbsp;</B></TD><TD align=center><B>share with&nbsp;<BR>others?&nbsp;</B></TD><TD align=center><B>link to<BR>session</B></TD>"
        "<TD align=center><B>send to<BR>mail</B></TD></TH>");
 while ((row = sqlNextRow(sr)) != NULL)
     {
     char *encSessionName = row[0];
     char *sessionName = cgiDecodeClone(encSessionName);
     char *link = NULL;
     boolean shared = atoi(row[1]);
     char *firstUse = row[2];
     char buf[512];
     printf("<TR><TD>&nbsp;&nbsp;</TD><TD>");
@@ -613,57 +613,60 @@
 boolean shareSession = cartBoolean(cart, hgsNewSessionShare);
 char *userName = getLinkUserName();
 char *encUserName = cgiEncodeFull(userName);
 struct sqlConnection *conn = hConnectCentral();
 
 if (sqlTableExists(conn, namedSessionTable))
     {
     struct sqlResult *sr = NULL;
     struct dyString *dy = dyStringNew(16 * 1024);
     char **row;
     char *firstUse = "now()";
     int useCount = INITIAL_USE_COUNT;
     char firstUseBuf[32];
 
     /* If this session already existed, preserve its firstUse and useCount. */
-    dyStringPrintf(dy, "SELECT firstUse, useCount FROM %s "
+    sqlDyStringPrintf(dy, "SELECT firstUse, useCount FROM %s "
 		       "WHERE userName = '%s' AND sessionName = '%s';",
 		   namedSessionTable, encUserName, encSessionName);
     sr = sqlGetResult(conn, dy->string);
     if ((row = sqlNextRow(sr)) != NULL)
 	{
 	safef(firstUseBuf, sizeof(firstUseBuf), "'%s'", row[0]);
 	firstUse = firstUseBuf;
 	useCount = atoi(row[1]) + 1;
 	}
     sqlFreeResult(&sr);
 
     /* Remove pre-existing session (if any) before updating. */
     dyStringClear(dy);
-    dyStringPrintf(dy, "DELETE FROM %s WHERE userName = '%s' AND "
+    sqlDyStringPrintf(dy, "DELETE FROM %s WHERE userName = '%s' AND "
 		       "sessionName = '%s';",
 		   namedSessionTable, encUserName, encSessionName);
     sqlUpdate(conn, dy->string);
 
     dyStringClear(dy);
-    dyStringPrintf(dy, "INSERT INTO %s ", namedSessionTable);
+    sqlDyStringPrintf(dy, "INSERT INTO %s ", namedSessionTable);
     dyStringAppend(dy, "(userName, sessionName, contents, shared, "
 		       "firstUse, lastUse, useCount) VALUES (");
     dyStringPrintf(dy, "'%s', '%s', ", encUserName, encSessionName);
     dyStringAppend(dy, "'");
     cleanHgSessionFromCart(cart);
-    cartEncodeState(cart, dy);
+    struct dyString *encoded = newDyString(4096);
+    cartEncodeState(cart, encoded);
+    sqlDyAppendEscaped(dy, encoded->string);
+    dyStringFree(&encoded);
     dyStringAppend(dy, "', ");
     dyStringPrintf(dy, "%d, ", (shareSession ? 1 : 0));
     dyStringPrintf(dy, "%s, now(), %d);", firstUse, useCount);
     sqlUpdate(conn, dy->string);
     dyStringFree(&dy);
 
     /* Prevent modification of custom tracks just saved to namedSessionDb: */
     cartCopyCustomTracks(cart);
 
     if (useCount > INITIAL_USE_COUNT)
 	dyStringPrintf(dyMessage,
 	  "Overwrote the contents of session <B>%s</B> "
 	  "(that %s be shared with other users).  "
 	  "%s %s",
 	  htmlEncode(sessionName), (shareSession ? "may" : "may not"),
@@ -796,46 +799,46 @@
 {
 struct dyString *dyMessage = dyStringNew(1024);
 struct hashEl *cartHelList = NULL, *hel = NULL;
 struct sqlConnection *conn = hConnectCentral();
 char *userName = getLinkUserName();
 char *encUserName = cgiEncodeFull(userName);
 boolean didSomething = FALSE;
 char query[512];
 
 cartHelList = cartFindPrefix(cart, hgsSharePrefix);
 if (cartHelList != NULL)
     {
     struct hash *sharedHash = hashNew(0);
     char **row;
     struct sqlResult *sr;
-    safef(query, sizeof(query),
+    sqlSafef(query, sizeof(query),
 	  "select sessionName,shared from %s where userName = '%s'",
 	  namedSessionTable, encUserName);
     sr = sqlGetResult(conn, query);
     while ((row = sqlNextRow(sr)) != NULL)
 	hashAddInt(sharedHash, row[0], atoi(row[1]));
     sqlFreeResult(&sr);
     for (hel = cartHelList;  hel != NULL;  hel = hel->next)
 	{
 	char *encSessionName = hel->name + strlen(hgsSharePrefix);
 	char *sessionName = cgiDecodeClone(encSessionName);
 	boolean alreadyShared = hashIntVal(sharedHash, encSessionName);
 	boolean shared  = cartUsualBoolean(cart, hel->name, TRUE);
 	if (shared != alreadyShared)
 	    {
-	    safef(query, sizeof(query), "UPDATE %s SET shared = %d "
+	    sqlSafef(query, sizeof(query), "UPDATE %s SET shared = %d "
 		  "WHERE userName = '%s' AND sessionName = '%s';",
 		  namedSessionTable, shared, encUserName, encSessionName);
 	    sqlUpdate(conn, query);
 	    sessionTouchLastUse(conn, encUserName, encSessionName);
 	    dyStringPrintf(dyMessage,
 			   "Marked session <B>%s</B> as %s.<BR>\n",
 			   htmlEncode(sessionName),
 			   (shared ? "shared" : "unshared"));
 	    didSomething = TRUE;
 	    }
 	}
     hashFree(&sharedHash);
     }
 hel = cartFindPrefix(cart, hgsLoadPrefix);
 if (hel != NULL)
@@ -847,31 +850,31 @@
     dyStringPrintf(dyMessage,
 		   "Loaded settings from session <B>%s</B>. %s %s<BR>\n",
 		   htmlEncode(sessionName),
 		   getSessionLink(encUserName, encSessionName),
 		   getSessionEmailLink(encUserName, encSessionName));
     cartLoadUserSession(conn, userName, sessionName, cart, NULL, wildStr);
     checkForCustomTracks(dyMessage);
     didSomething = TRUE;
     }
 
 cartHelList = cartFindPrefix(cart, hgsDeletePrefix);
 for (hel = cartHelList;  hel != NULL;  hel = hel->next)
     {
     char *encSessionName = hel->name + strlen(hgsDeletePrefix);
     char *sessionName = cgiDecodeClone(encSessionName);
-    safef(query, sizeof(query), "DELETE FROM %s "
+    sqlSafef(query, sizeof(query), "DELETE FROM %s "
 	  "WHERE userName = '%s' AND sessionName = '%s';",
 	  namedSessionTable, encUserName, encSessionName);
     sqlUpdate(conn, query);
     dyStringPrintf(dyMessage,
 		   "Deleted session <B>%s</B>.<BR>\n",
 		   htmlEncode(sessionName));
     didSomething = TRUE;
     }
 
 hDisconnectCentral(&conn);
 if (didSomething)
     return(dyStringCannibalize(&dyMessage));
 else
     {
     dyStringFree(&dyMessage);
@@ -1002,35 +1005,35 @@
 char *doSessionDetail(char *sessionName)
 /* Show details about a particular session. */
 {
 struct dyString *dyMessage = dyStringNew(4096);
 char *encSessionName = cgiEncodeFull(sessionName);
 char *userName = getLinkUserName();
 char *encUserName = cgiEncodeFull(userName);
 struct sqlConnection *conn = hConnectCentral();
 struct sqlResult *sr = NULL;
 char **row = NULL;
 char query[512];
 webPushErrHandlersCart(cart);
 boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0);
 
 if (gotSettings)
-    safef(query, sizeof(query), "SELECT shared, firstUse, settings from %s "
+    sqlSafef(query, sizeof(query), "SELECT shared, firstUse, settings from %s "
 	  "WHERE userName = '%s' AND sessionName = '%s'",
           namedSessionTable, encUserName, encSessionName);
 else
-    safef(query, sizeof(query), "SELECT shared, firstUse from %s "
+    sqlSafef(query, sizeof(query), "SELECT shared, firstUse from %s "
 	  "WHERE userName = '%s' AND sessionName = '%s'",
           namedSessionTable, encUserName, encSessionName);
 sr = sqlGetResult(conn, query);
 if ((row = sqlNextRow(sr)) != NULL)
     {
     boolean shared = atoi(row[0]);
     char *firstUse = row[1];
     char *settings = NULL;
     if (gotSettings)
 	settings = row[2];
     char *description = getSetting(settings, "description");
     if (description == NULL) description = "";
 
     dyStringPrintf(dyMessage, "<A HREF=\"../goldenPath/help/hgSessionHelp.html#Details\" "
 		   "TARGET=_BLANK>Session Details Help</A><P/>\n");
@@ -1108,119 +1111,116 @@
 webPushErrHandlersCart(cart);
 char *sessionName = oldSessionName;
 char *encSessionName = cgiEncodeFull(sessionName);
 char *encOldSessionName = encSessionName;
 char *userName = getLinkUserName();
 char *encUserName = cgiEncodeFull(userName);
 struct sqlConnection *conn = hConnectCentral();
 struct sqlResult *sr = NULL;
 char **row = NULL;
 char query[512];
 boolean shared = TRUE;
 char *settings = NULL;
 boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0);
 
 if (gotSettings)
-    safef(query, sizeof(query), "SELECT shared, settings from %s "
+    sqlSafef(query, sizeof(query), "SELECT shared, settings from %s "
 	  "WHERE userName = '%s' AND sessionName = '%s'",
           namedSessionTable, encUserName, encSessionName);
 else
-    safef(query, sizeof(query), "SELECT shared from %s "
+    sqlSafef(query, sizeof(query), "SELECT shared from %s "
 	  "WHERE userName = '%s' AND sessionName = '%s'",
           namedSessionTable, encUserName, encSessionName);
 sr = sqlGetResult(conn, query);
 if ((row = sqlNextRow(sr)) != NULL)
     {
     shared = atoi(row[0]);
     if (gotSettings)
 	settings = cloneString(row[1]);
     sqlFreeResult(&sr);
     }
 else
     errAbort("doSessionChange: got no results from query:<BR>\n%s\n", query);
 
 char *newName = cartOptionalString(cart, hgsNewSessionName);
 if (isNotEmpty(newName) && !sameString(sessionName, newName))
     {
     char *encNewName = cgiEncodeFull(newName);
-    safef(query, sizeof(query),
+    sqlSafef(query, sizeof(query),
 	  "UPDATE %s set sessionName = '%s' WHERE userName = '%s' AND sessionName = '%s';",
 	  namedSessionTable, encNewName, encUserName, encSessionName);
 	sqlUpdate(conn, query);
     dyStringPrintf(dyMessage, "Changed session name from %s to <B>%s</B>.\n",
 		   sessionName, newName);
     sessionName = newName;
     encSessionName = encNewName;
     renamePrefixedCartVar(hgsLoadPrefix, encOldSessionName, encNewName);
     renamePrefixedCartVar(hgsDeletePrefix, encOldSessionName, encNewName);
     }
 char varName[256];
 safef(varName, sizeof(varName), hgsSharePrefix "%s", encOldSessionName);
 if (cgiBooleanDefined(varName))
     {
     boolean newShared = cartBoolean(cart, varName);
     if (newShared != shared)
 	{
-	safef(query, sizeof(query),
+	sqlSafef(query, sizeof(query),
 	      "UPDATE %s set shared = %d WHERE userName = '%s' AND sessionName = '%s';",
 	      namedSessionTable, newShared, encUserName, encSessionName);
 	sqlUpdate(conn, query);
 	dyStringPrintf(dyMessage, "Marked session <B>%s</B> as %s.<BR>\n",
 		       htmlEncode(sessionName), (newShared ? "shared" : "unshared"));
 
 	}
     cartRemove(cart, varName);
     char shadowVarName[512];
     safef(shadowVarName, sizeof(shadowVarName), "%s%s", cgiBooleanShadowPrefix(), varName);
     cartRemove(cart, shadowVarName);
     }
 if (gotSettings)
     {
     struct hash *settingsHash = raFromString(settings);
     char *description = hashFindVal(settingsHash, "description");
     char *newDescription = cartOptionalString(cart, hgsNewSessionDescription);
     if (newDescription != NULL)
 	{
-	newDescription = replaceChars(newDescription, "\\", "\\\\\\\\");
-	newDescription = replaceChars(newDescription, "\r", "\\\\r");
-	newDescription = replaceChars(newDescription, "\n", "\\\\n");
+	// newline escaping of \n is needed for ra syntax.
+        // not sure why \r and \ are being escaped, but it may be too late to change
+        // since there are probably records in the database that way now.
+	newDescription = replaceChars(newDescription, "\\", "\\\\");
+	newDescription = replaceChars(newDescription, "\r", "\\r");
+	newDescription = replaceChars(newDescription, "\n", "\\n");
 	}
     else
 	newDescription = "";
-    if (description != NULL)
-	description = replaceChars(description, "\\", "\\\\");
-    else
+    if (description == NULL)
 	description = "";
     if (!sameString(description, newDescription))
 	{
 	hashRemove(settingsHash, "description");
 	hashAdd(settingsHash, "description", newDescription);
 	struct dyString *dyRa = dyStringNew(512);
 	struct hashEl *hel = hashElListHash(settingsHash);
 	while (hel != NULL)
 	    {
-	    if (sameString(hel->name, "description"))
-		dyStringPrintf(dyRa, "%s %s\n", hel->name, newDescription);
-	    else
 		dyStringPrintf(dyRa, "%s %s\n", hel->name, (char *)hel->val);
 	    hel = hel->next;
 	    }
 	struct dyString *dyQuery = dyStringNew(1024);
-	dyStringPrintf(dyQuery, "UPDATE %s set settings = ", namedSessionTable);
-	dyStringQuoteString(dyQuery, '"', dyRa->string);
-	dyStringPrintf(dyQuery, "WHERE userName = '%s' AND sessionName = '%s';",
-		       encUserName, encSessionName);
+	sqlDyStringPrintf(dyQuery, "UPDATE %s set settings = '%s' "
+				   "WHERE userName = '%s' AND sessionName = '%s';",
+			namedSessionTable, dyRa->string, encUserName, encSessionName);
 	sqlUpdate(conn, dyQuery->string);
 	dyStringPrintf(dyMessage, "Updated description of <B>%s</B>.\n", sessionName);
 	}
     }
 if (isEmpty(dyMessage->string))
     dyStringPrintf(dyMessage, "No changes to session <B>%s</B>.\n", sessionName);
 dyStringPrintf(dyMessage, "%s %s",
 	       getSessionLink(encUserName, encSessionName),
 	       getSessionEmailLink(encUserName, encSessionName));
 return dyStringCannibalize(&dyMessage);
 }
 
 
 void hgSession()
 /* hgSession - Interface with wiki login and do session saving/loading.