44ccfacbe3a3d4b300f80d48651c77837a4b571e
galt
  Tue Apr 26 11:12:02 2022 -0700
SQL INJECTION Prevention Version 2 - this improves our methods by making subclauses of SQL that get passed around be both easy and correct to use. The way that was achieved was by getting rid of the obscure and not well used functions sqlSafefFrag and sqlDyStringPrintfFrag and replacing them with the plain versions of those functions, since these are not needed anymore. The new version checks for NOSQLINJ in unquoted %-s which is used to include SQL clauses, and will give an error the NOSQLINJ clause is not present, and this will automatically require the correct behavior by developers. sqlDyStringPrint is a very useful function, however because it was not enforced, users could use various other dyString functions and they operated without any awareness or checking for SQL correct use. Now those dyString functions are prohibited and it will produce an error if you try to use a dyString function on a SQL string, which is simply detected by the presence of the NOSQLINJ prefix.

diff --git src/hg/cgilib/genoLay.c src/hg/cgilib/genoLay.c
index 4c49afe..c9e9db6 100644
--- src/hg/cgilib/genoLay.c
+++ src/hg/cgilib/genoLay.c
@@ -1,564 +1,567 @@
 /* genoLay - genome layout. Arranges chromosomes so that they
  * tend to fit together nicely on a single page. */
 
 /* Copyright (C) 2014 The Regents of the University of California 
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 #include "common.h"
 #include "hash.h"
 #include "jksql.h"
 #include "vGfx.h"
 #include "cytoBand.h"
 #include "hCytoBand.h"
 #include "genoLay.h"
 
 
 void genoLayDump(struct genoLay *gl)
 /* Print out info on genoLay */
 {
 struct genoLayChrom *chrom;
 struct slRef *left, *right, *ref;
 int total;
 printf("gl: lineCount %d, leftLabelWidth %d, rightLabelWidth %d, basesPerPixel %f<BR>\n",
 	gl->lineCount, gl->leftLabelWidth, gl->rightLabelWidth, gl->basesPerPixel);
 for (left = gl->leftList, right = gl->rightList; left != NULL || right != NULL;)
     {
     total=0;
     if (left != NULL)
 	{
 	chrom = left->val;
 	printf("%s@%d,%d[%d] %d ----  ", chrom->fullName, chrom->x, chrom->y, chrom->width, chrom->size);
 	total += chrom->size;
         left = left->next;
 	}
     if (right != NULL)
 	{
 	chrom = right->val;
 	printf("%d  %s@%d,%d[%d]", chrom->size, chrom->fullName, chrom->x, chrom->y, chrom->width);
 	total += chrom->size;
         right = right->next;
 	}
     printf(" : %d<BR>", total);
     }
 total=0;
 for (ref = gl->bottomList; ref != NULL; ref = ref->next)
     {
     chrom = ref->val;
     total += chrom->size;
     printf("%s@%d,%d[%d] %d ...  ", chrom->fullName, chrom->x, chrom->y, chrom->width, chrom->size);
     }
 printf(" : %d<BR>", total);
 }
 
 int genoLayChromCmpName(const void *va, const void *vb)
 /* Compare two chromosome names so as to sort numerical part
  * by number.. */
 {
 const struct genoLayChrom *a = *((struct genoLayChrom **)va);
 const struct genoLayChrom *b = *((struct genoLayChrom **)vb);
 char *aName = a->shortName, *bName = b->shortName;
 if (isdigit(aName[0]))
     {
     if (isdigit(bName[0]))
 	{
 	int diff = atoi(aName) - atoi(bName);
 	if (diff == 0)
 	    diff = strcmp(skipNumeric(aName), skipNumeric(bName));
 	return diff;
 	}
     else
         return -1;
     }
 else if (isdigit(bName[0]))
     return 1;
 else
     return strcmp(aName, bName);
 }
 
 struct genoLayChrom *genoLayDbChromsExt(struct sqlConnection *conn, 
 	boolean withRandom, boolean abortOnErr)
 /* Get chrom info list. */
 {
 struct sqlResult *sr;
 char **row;
 struct genoLayChrom *chrom, *chromList = NULL;
-sr = sqlGetResult(conn, NOSQLINJ "select chrom,size from chromInfo");
+
+char query[1024];
+sqlSafef(query, sizeof query, "select chrom,size from chromInfo"); 
+sr = sqlGetResult(conn, query);
 while ((row = sqlNextRow(sr)) != NULL)
     {
     char *name = row[0];
     if (withRandom || 
         (
         (startsWith("chr", name))
      && (!startsWith("chrUn", name))
      && (!sameString("chrM", name))
      && (!strchr(name, '_'))   // avoiding _random and _hap*
 	)
        )
 	{
 	AllocVar(chrom);
 	chrom->fullName = cloneString(name);
 	chrom->shortName = chrom->fullName+3;
 	chrom->size = sqlUnsigned(row[1]);
 	slAddHead(&chromList, chrom);
 	}
     }
 if (chromList == NULL)
     {
     if (abortOnErr)
     	errAbort("No chromosomes found in chromInfo.");
     return NULL;
     }
 int count = slCount(chromList);
 if (count > 500)
     {
     if (abortOnErr)
 	errAbort("Sorry, cannot do genome layout on an assembly "
     	    "with too many (%d) chromosomes exceeds 500. "
     	    "Please select another organism or assembly.", count);
     }
 slReverse(&chromList);
 slSort(&chromList, genoLayChromCmpName);
 return chromList;
 }
 
 struct genoLayChrom *genoLayDbChroms(struct sqlConnection *conn, 
 	boolean withRandom)
 /* Get chrom info list. */
 {
 return genoLayDbChromsExt(conn, withRandom, TRUE);
 }
 
 
 static void separateSexChroms(struct slRef *in,
 	struct slRef **retAutoList, struct slRef **retSexList)
 /* Separate input chromosome list into sex and non-sex chromosomes. */
 {
 struct slRef *autoList = NULL, *sexList = NULL, *ref, *next;
 
 for (ref = in; ref != NULL; ref = next)
     {
     struct genoLayChrom *chrom = ref->val;
     char *name = chrom->shortName;
     next = ref->next;
     if (sameWord(name, "X") || sameWord(name, "Y") || sameWord(name, "Z")
     	|| sameWord(name, "W"))
 	{
 	slAddHead(&sexList, ref);
 	}
     else
         {
 	slAddHead(&autoList, ref);
 	}
     }
 slReverse(&sexList);
 slReverse(&autoList);
 *retAutoList = autoList;
 *retSexList = sexList;
 }
 
 struct genoLay *genoLayNew(struct genoLayChrom *chromList,
 	MgFont *font, int picWidth, int betweenChromHeight,
 	int minLeftLabelWidth, int minRightLabelWidth,
 	char *how)
 /* Figure out layout.  For human and most mammals this will be
  * two columns with sex chromosomes on bottom.  This is complicated
  * by the platypus having a bunch of sex chromosomes. */
 {
 int margin = 3;
 struct slRef *refList = NULL, *ref, *left, *right;
 struct genoLayChrom *chrom;
 struct genoLay *gl;
 int autoCount, halfCount, bases;
 int leftLabelWidth=0, rightLabelWidth=0, labelWidth;
 int spaceWidth = mgFontCharWidth(font, ' ');
 int extraLabelPadding = 0;
 int autosomeOtherPixels=0, sexOtherPixels=0;
 int autosomeBasesInLine=0;	/* Maximum bases in a line for autosome. */
 int sexBasesInLine=0;		/* Bases in line for sex chromsome. */
 double sexBasesPerPixel, autosomeBasesPerPixel, basesPerPixel;
 int pos = margin;
 int y = 0;
 int fontHeight = mgFontLineHeight(font);
 int chromHeight = fontHeight;
 int lineHeight = chromHeight + betweenChromHeight;
 boolean allOneLine = FALSE;
 
 refList = refListFromSlList(chromList);
 
 /* Allocate genoLay object and fill in simple fields. */
 AllocVar(gl);
 gl->chromList = chromList;
 gl->chromHash = hashNew(0);
 gl->font = font;
 gl->picWidth = picWidth;
 gl->margin = margin;
 gl->spaceWidth = spaceWidth;
 gl->lineHeight = lineHeight;
 gl->betweenChromHeight = betweenChromHeight;
 gl->betweenChromOffsetY = 0;
 gl->chromHeight = chromHeight;
 gl->chromOffsetY = lineHeight - chromHeight;
 
 
 /* Save chromosomes in hash too, for easy access */
 for (chrom = chromList; chrom != NULL; chrom = chrom->next)
     hashAdd(gl->chromHash, chrom->fullName, chrom);
 
 if (sameString(how, genoLayOnePerLine))
     {
     gl->leftList = refList;
     }
 else if (sameString(how, genoLayAllOneLine))
     {
     gl->bottomList = refList;
     allOneLine = TRUE;
     }
 else
     {
     /* Put sex chromosomes on bottom, and rest on left. */
     separateSexChroms(refList, &refList, &gl->bottomList);
     autoCount = slCount(refList);
     gl->leftList = refList;
 
     /* If there are a lot of chromosomes, then move later
      * (and smaller) chromosomes to a new right column */
     if (autoCount > 12)
 	{
 	halfCount = (autoCount+1)/2;
 	ref = slElementFromIx(refList, halfCount-1);
 	gl->rightList = ref->next;
 	ref->next = NULL;
 	slReverse(&gl->rightList);
 	}
     }
 
 if (allOneLine)
     {
     unsigned long totalBases = 0, bStart=0, bEnd;
     int chromCount = 0, chromIx=0;
     for (ref = gl->bottomList; ref != NULL; ref = ref->next)
         {
 	chrom = ref->val;
 	totalBases += chrom->size;
 	chromCount += 1;
 	}
     int availablePixels = picWidth - minLeftLabelWidth - minRightLabelWidth
        - 2*margin - (chromCount-1);
     double basesPerPixel = (double)totalBases/availablePixels;
     gl->picHeight = 2*margin + lineHeight + fontHeight;
     for (ref = gl->bottomList; ref != NULL; ref = ref->next)
         {
 	chrom = ref->val;
 	bEnd = bStart + chrom->size;
 	int pixStart = round(bStart / basesPerPixel);
 	int pixEnd = round(bEnd / basesPerPixel);
 	chrom->width = pixEnd - pixStart;
 	chrom->height = lineHeight;
 	chrom->x = pixStart + margin + chromIx + minLeftLabelWidth;
 	chrom->y = 0;
 	chromIx += 1;
 	bStart = bEnd;
 	}
     gl->lineCount = 1;
     gl->picHeight = 2*margin + lineHeight + fontHeight + 1;
     gl->allOneLine = TRUE;
     gl->leftLabelWidth = minLeftLabelWidth;
     gl->rightLabelWidth = minRightLabelWidth;
     gl->basesPerPixel = basesPerPixel;
     gl->pixelsPerBase = 1.0/basesPerPixel;
     }
 else
     {
     /* Figure out space needed for autosomes. */
     left = gl->leftList;
     right = gl->rightList;
     while (left || right)
 	{
 	bases = 0;
 	if (left)
 	    {
 	    chrom = left->val;
 	    labelWidth = mgFontStringWidth(font, chrom->shortName) + spaceWidth;
 	    if (leftLabelWidth < labelWidth)
 		leftLabelWidth = labelWidth;
 	    bases = chrom->size;
 	    left = left->next;
 	    }
 	if (right)
 	    {
 	    chrom = right->val;
 	    labelWidth = mgFontStringWidth(font, chrom->shortName) + spaceWidth;
 	    if (rightLabelWidth < labelWidth)
 		rightLabelWidth = labelWidth;
 	    bases += chrom->size;
 	    right = right->next;
 	    }
 	if (autosomeBasesInLine < bases)
 	    autosomeBasesInLine = bases;
 	gl->lineCount += 1;
 	}
 
     /* Figure out space needed for bottom chromosomes. */
     if (gl->bottomList)
 	{
 	gl->lineCount += 1;
 	sexOtherPixels = spaceWidth + 2*margin;
 	for (ref = gl->bottomList; ref != NULL; ref = ref->next)
 	    {
 	    chrom = ref->val;
 	    sexBasesInLine += chrom->size;
 	    labelWidth = mgFontStringWidth(font, chrom->shortName) + spaceWidth;
 	    if (ref == gl->bottomList )
 		{
 		if (leftLabelWidth < labelWidth)
 		    leftLabelWidth  = labelWidth;
 		sexOtherPixels = leftLabelWidth;
 		}
 	    else if (ref->next == NULL)
 		{
 		if (rightLabelWidth < labelWidth)
 		    rightLabelWidth  = labelWidth;
 		sexOtherPixels += rightLabelWidth + spaceWidth;
 		}
 	    else
 		{
 		sexOtherPixels += labelWidth + spaceWidth;
 		}
 	    }
 	}
 
     /* Do some adjustments if side labels are bigger than needed for
      * chromosome names. */
     if (leftLabelWidth < minLeftLabelWidth)
 	{
 	extraLabelPadding += (minLeftLabelWidth - leftLabelWidth);
 	leftLabelWidth = minLeftLabelWidth;
 	}
     if (rightLabelWidth < minRightLabelWidth)
 	{
 	extraLabelPadding += (minRightLabelWidth - rightLabelWidth);
 	rightLabelWidth = minRightLabelWidth;
 	}
     sexOtherPixels += extraLabelPadding;
 
     /* Figure out the number of bases needed per pixel. */
     autosomeOtherPixels = 2*margin + spaceWidth + leftLabelWidth + rightLabelWidth;
     basesPerPixel = autosomeBasesPerPixel 
 	    = autosomeBasesInLine/(picWidth-autosomeOtherPixels);
     if (gl->bottomList)
 	{
 	sexBasesPerPixel = sexBasesInLine/(picWidth-sexOtherPixels);
 	if (sexBasesPerPixel > basesPerPixel)
 	    basesPerPixel = sexBasesPerPixel;
 	}
 
     /* Save positions and sizes of some things in layout structure. */
     gl->leftLabelWidth = leftLabelWidth;
     gl->rightLabelWidth = rightLabelWidth;
     gl->basesPerPixel = basesPerPixel;
     gl->pixelsPerBase = 1.0/basesPerPixel;
 
     /* Set pixel positions for left autosomes */
     for (ref = gl->leftList; ref != NULL; ref = ref->next)
 	{
 	chrom = ref->val;
 	chrom->x = leftLabelWidth + margin;
 	chrom->y = y;
 	chrom->width = round(chrom->size/basesPerPixel);
 	chrom->height = lineHeight;
 	y += lineHeight;
 	}
 
     /* Set pixel positions for right autosomes */
     y = 0;
     for (ref = gl->rightList; ref != NULL; ref = ref->next)
 	{
 	chrom = ref->val;
 	chrom->width = round(chrom->size/basesPerPixel);
 	chrom->height = lineHeight;
 	chrom->x = picWidth - margin - rightLabelWidth - chrom->width;
 	chrom->y = y;
 	y += lineHeight;
 	}
     gl->picHeight = 2*margin + lineHeight * gl->lineCount;
     y = gl->picHeight - margin - lineHeight;
 
     /* Set pixel positions for sex chromosomes */
     for (ref = gl->bottomList; ref != NULL; ref = ref->next)
 	{
 	chrom = ref->val;
 	chrom->y = y;
 	chrom->width = round(chrom->size/basesPerPixel);
 	chrom->height = lineHeight;
 	if (ref == gl->bottomList)
 	    chrom->x = leftLabelWidth + margin;
 	else if (ref->next == NULL)
 	    chrom->x = picWidth - margin - rightLabelWidth - chrom->width;
 	else
 	    chrom->x = 2*spaceWidth+mgFontStringWidth(font,chrom->shortName) + pos;
 	pos = chrom->x + chrom->width;
 	}
     }
 return gl;
 }
 
 static void leftLabel(struct hvGfx *hvg, struct genoLay *gl,
 	struct genoLayChrom *chrom, int yOffset, int fontHeight,
 	int color)
 /* Draw a chromosome with label on left. */
 {
 hvGfxTextRight(hvg, gl->margin, chrom->y + yOffset, 
     chrom->x - gl->margin - gl->spaceWidth, fontHeight, color,
     gl->font, chrom->shortName);
 }
 
 static void rightLabel(struct hvGfx *hvg, struct genoLay *gl,
 	struct genoLayChrom *chrom, int yOffset, int fontHeight, 
 	int color)
 /* Draw a chromosome with label on left. */
 {
 hvGfxText(hvg, chrom->x + chrom->width + gl->spaceWidth,
 	chrom->y + yOffset, 
 	color, gl->font, chrom->shortName);
 }
 
 static void midLabel(struct hvGfx *hvg, struct genoLay *gl,
 	struct genoLayChrom *chrom, int yOffset, int fontHeight, 
 	int color)
 /* Draw a chromosome with label on left. */
 {
 MgFont *font = gl->font;
 int textWidth = mgFontStringWidth(font, chrom->shortName);
 hvGfxTextRight(hvg, chrom->x - textWidth - gl->spaceWidth, 
     chrom->y + yOffset, 
     textWidth, fontHeight, color,
     font, chrom->shortName);
 }
 
 void genoLayDrawChromLabels(struct genoLay *gl, struct hvGfx *hvg, int color)
 /* Draw chromosomes labels in image */
 {
 struct slRef *ref;
 struct genoLayChrom *chrom;
 int pixelHeight = mgFontPixelHeight(gl->font);
 if (gl->allOneLine)
     {
     int yOffset = gl->chromOffsetY + gl->chromHeight + 1;
 
     for (ref = gl->bottomList; ref != NULL; ref = ref->next)
 	{
 	chrom = ref->val;
 	hvGfxTextCentered(hvg, chrom->x, yOffset, chrom->width, pixelHeight, color, gl->font,
 		chrom->shortName);
 	}
     }
 else
     {
     int yOffset = gl->chromOffsetY + gl->chromHeight - pixelHeight;
 
     /* Draw chromosome labels. */
     for (ref = gl->leftList; ref != NULL; ref = ref->next)
 	leftLabel(hvg, gl, ref->val, yOffset, pixelHeight, color);
     for (ref = gl->rightList; ref != NULL; ref = ref->next)
 	rightLabel(hvg, gl, ref->val, yOffset, pixelHeight, color);
     for (ref = gl->bottomList; ref != NULL; ref = ref->next)
 	{
 	chrom = ref->val;
 	if (ref == gl->bottomList)
 	    leftLabel(hvg, gl, chrom, yOffset, pixelHeight, color);
 	else if (ref->next == NULL)
 	    rightLabel(hvg, gl, chrom, yOffset, pixelHeight, color);
 	else
 	    midLabel(hvg, gl, chrom, yOffset, pixelHeight, color);
 	}
     }
 }
 
 void genoLayDrawSimpleChroms(struct genoLay *gl,
 	struct hvGfx *hvg, int color)
 /* Draw boxes for all chromosomes in given color */
 {
 int height = gl->chromHeight;
 int yOffset = gl->chromOffsetY;
 struct genoLayChrom *chrom;
 for (chrom = gl->chromList; chrom != NULL; chrom = chrom->next)
     hvGfxBox(hvg, chrom->x, chrom->y + yOffset, 
 	chrom->width, height, color);
 
 }
 
 void genoLayDrawBandedChroms(struct genoLay *gl, struct hvGfx *hvg, char *db,
 	struct sqlConnection *conn, Color *shadesOfGray, int maxShade, 
 	int defaultColor)
 /* Draw chromosomes with centromere and band glyphs. 
  * Get the band data from the database.  If the data isn't
  * there then draw simple chroms in default color instead */
 {
 char *bandTable = "cytoBandIdeo";
 int yOffset = gl->chromOffsetY;
 genoLayDrawSimpleChroms(gl, hvg, defaultColor);
 if (sqlTableExists(conn, bandTable) && !gl->allOneLine)
     {
     int centromereColor = hCytoBandCentromereColor(hvg);
     double pixelsPerBase = 1.0/gl->basesPerPixel;
     int height = gl->chromHeight;
     int innerHeight = gl->chromHeight-2;
     struct genoLayChrom *chrom;
     boolean isDmel = hCytoBandDbIsDmel(db);
     boolean bColor = hvGfxFindColorIx(hvg, 200, 150, 150);
     int fontPixelHeight = mgFontPixelHeight(gl->font);
     for (chrom = gl->chromList; chrom != NULL; chrom = chrom->next)
 	{
 	struct sqlResult *sr;
 	char **row;
 	char query[256];
 	int cenX1=BIGNUM, cenX2=0;
 	int y = chrom->y + yOffset;
 
 	/* Fetch bands from database and draw them. */
 	sqlSafef(query, sizeof(query), "select * from %s where chrom='%s'",
 		bandTable, chrom->fullName);
 	sr = sqlGetResult(conn, query);
 	while ((row = sqlNextRow(sr)) != NULL)
 	    {
 	    struct cytoBand band;
 	    int x1, x2;
 	    cytoBandStaticLoad(row, &band);
 	    x1 = pixelsPerBase*band.chromStart;
 	    x2 = pixelsPerBase*band.chromEnd;
 	    if (sameString(band.gieStain, "acen"))
 		{
 		/* Centromere is represented as two adjacent bands.
 		 * We'll just record the extents of it here, and draw it
 		 * in one piece later. */
 		if (x1 < cenX1)
 		    cenX1 = x1;
 		if (x2 > cenX2)
 		    cenX2 = x2;
 		}
 	    else
 		{
 		/* Draw band */
 		hCytoBandDrawAt(&band, hvg, x1+chrom->x, y+1, x2-x1, innerHeight, 
 			isDmel, gl->font, fontPixelHeight, MG_BLACK, bColor,
 		    shadesOfGray, maxShade);
 		}
 	    }
 	sqlFreeResult(&sr);
 
 	/* Draw box around chromosome */
 	hvGfxBox(hvg, chrom->x, y, chrom->width, 1, MG_BLACK);
 	hvGfxBox(hvg, chrom->x, y+height-1, chrom->width, 1, MG_BLACK);
 	hvGfxBox(hvg, chrom->x, y, 1, height, MG_BLACK);
 	hvGfxBox(hvg, chrom->x+chrom->width-1, y, 1, height, MG_BLACK);
 
 	/* Draw centromere if we found one. */
 	if (cenX2 > cenX1)
 	    {
 	    hCytoBandDrawCentromere(hvg, cenX1+chrom->x, y, cenX2-cenX1, height,
 	       MG_WHITE, centromereColor);
 	    }
 	}
     }
 }