5e440312f10786dcc86c21399d3e2df1683436d4
galt
  Wed Aug 5 09:41:40 2015 -0700
adding ssl params crl and crlPath. also more cleanup, got rid of a separate function sqlProfileNew() since it was no longer needed.

diff --git src/hg/lib/jksql.c src/hg/lib/jksql.c
index 3179ca6..c7b9954 100644
--- src/hg/lib/jksql.c
+++ src/hg/lib/jksql.c
@@ -50,33 +50,35 @@
 struct sqlProfile
 /* a configuration profile for connecting to a server */
 {
     struct sqlProfile *next;
     char *name;         // name of profile
     char *host;         // host name for database server
     unsigned int port;  // port for database server
     char *socket;       // unix-domain socket path for database server
     char *user;         // database server user name
     char *password;     // database server password
     struct slName *dbs; // database associated with profile, can be NULL.
     // ssl
     char *key;       // path to ssl client key.pem
     char *cert;      // path to ssl client cert.pem
     char *ca;        // path to ssl certificate authority ca.pem
-    char *caPath;    // path to directory containing ssl .pem certs
+    char *caPath;    // path to directory containing ssl .pem certs (only OpenSSL)
     char *cipher;    // list of permissible ciphers to use
-    char *verifyServerCert;  // Client will check server cert Subject CN={host}.
+    char *crl;       // path to file containing certificate revocation lists in PEM format
+    char *crlPath;   // path to directory containing crl files (only OpenSSL)
+    char *verifyServerCert;  // Client will check server cert Subject CN={host}
                              //  Boolean connection flag, if NON-NULL and != "0" then it is on.
     };
 
 struct sqlConnection
 /* This is an item on a list of sql open connections. */
     {
     MYSQL *conn;		    /* Connection. Can be NULL if not connected yet. */
     struct sqlProfile *profile;     /* profile, or NULL if not opened via a profile */
     struct dlNode *node;	    /* Pointer to list node. */
     struct dlList *resultList;	    /* Any open results. */
     boolean hasHardLock;	    /* TRUE if table has a non-advisory lock. */
     boolean inCache;                /* debugging flag to indicate it's in a cache */
     boolean isFree;                /* is this connection free for reuse; alway FALSE
                                     * unless managed by a cache */
     int hasTableCache;              /* to avoid repeated checks for cache table name existence, 
@@ -110,68 +112,48 @@
 	char *query, ResGetter *getter, boolean abort);
 static void sqlConnectIfUnconnected(struct sqlConnection *sc, bool abort);
 bool sqlConnMustUseFailover(struct sqlConnection *sc);
 
 static char *envOverride(char *envName, char *defaultVal)
 /* look up envName in environment, if it exists and is non-empty, return its
  * value, otherwise return defaultVal */
 {
 char *val = getenv(envName);
 if (isEmpty(val))
     return defaultVal;
 else
     return val;
 }
 
-struct sqlProfile *sqlProfileNew(char *name, char *host, unsigned int port,
-					char *socket, char *user, char *password,
-	    		char *key, char *cert, char *ca, char *caPath, char *cipher, char *verifyServerCert)
-/* create a new profile object (does not include ->dbs) */
-{
-struct sqlProfile *sp;
-AllocVar(sp);
-sp->name = cloneString(name);
-sp->host = cloneString(host);
-sp->port = port;
-sp->socket = cloneString(socket);
-sp->user = cloneString(user);
-sp->password = cloneString(password);
-sp->key = cloneString(key);
-sp->cert = cloneString(cert);
-sp->ca = cloneString(ca);
-sp->caPath = cloneString(caPath);
-sp->cipher = cloneString(cipher);
-sp->verifyServerCert = cloneString(verifyServerCert);
-return sp;
-}
-
 static struct sqlProfile *sqlProfileClone(struct sqlProfile *o)
 /* clone profile object (does not include ->dbs) */
 {
 struct sqlProfile *sp;
 AllocVar(sp);
 sp->name = cloneString(o->name);
 sp->host = cloneString(o->host);
 sp->port = o->port;
 sp->socket = cloneString(o->socket);
 sp->user = cloneString(o->user);
 sp->password = cloneString(o->password);
 sp->key = cloneString(o->key);
 sp->cert = cloneString(o->cert);
 sp->ca = cloneString(o->ca);
 sp->caPath = cloneString(o->caPath);
 sp->cipher = cloneString(o->cipher);
+sp->crl = cloneString(o->crl);
+sp->crlPath = cloneString(o->crlPath);
 sp->verifyServerCert = cloneString(o->verifyServerCert);
 return sp;
 }
 
 struct sqlProfile *sqlProfileFromPairs(struct slPair *pairs)
 /* create a new profile object (does not include ->dbs) */
 {
 struct sqlProfile *sp;
 AllocVar(sp);
 struct slPair *p;
 for(p=pairs; p; p=p->next)
     {
     char *value = (char *)p->val;
     if (sameString(p->name,"name"))
 	sp->name = cloneString(value);
@@ -183,30 +165,34 @@
 	sp->socket = cloneString(value);
     if (sameString(p->name,"user"))
 	sp->user = cloneString(value);
     if (sameString(p->name,"password"))
 	sp->password = cloneString(value);
     if (sameString(p->name,"key"))
 	sp->key = cloneString(value);
     if (sameString(p->name,"cert"))
 	sp->cert = cloneString(value);
     if (sameString(p->name,"ca"))
 	sp->ca = cloneString(value);
     if (sameString(p->name,"caPath"))
 	sp->caPath = cloneString(value);
     if (sameString(p->name,"cipher"))
 	sp->cipher = cloneString(value);
+    if (sameString(p->name,"crl"))
+	sp->crl = cloneString(value);
+    if (sameString(p->name,"crlPath"))
+	sp->crlPath = cloneString(value);
     if (sameString(p->name,"verifyServerCert"))
 	sp->verifyServerCert = cloneString(value);
     }
 return sp;
 }
 
 
 static void sqlProfileAssocDb(struct sqlProfile *sp, char *db)
 /* associate a db with a profile.  If it is already associated with this
  * profile, don't do anything.*/
 {
 struct sqlProfile *sp2 = hashFindVal(dbToProfile, db);
 if ((sp2 != NULL) && (sp2 != sp))
     errAbort("databases %s already associated with profile %s, trying to associated it with %s",
              db, sp2->name, sp->name);
@@ -228,57 +214,76 @@
 static void sqlProfileAddProfIf(char *profileName)
 /* check if a config prefix is a profile, and if so, add a
  * sqlProfile object for it if doesn't already exist. */
 {
 char *host = cfgOption2(profileName, "host");
 char *portstr = cfgOption2(profileName, "port");
 char *socket = cfgOption2(profileName, "socket");
 char *user = cfgOption2(profileName, "user");
 char *password = cfgOption2(profileName, "password");
 // ssl
 char *key = cfgOption2(profileName, "key");
 char *cert = cfgOption2(profileName, "cert");
 char *ca = cfgOption2(profileName, "ca");
 char *caPath = cfgOption2(profileName, "caPath");
 char *cipher = cfgOption2(profileName, "cipher");
+char *crl = cfgOption2(profileName, "crl");
+char *crlPath = cfgOption2(profileName, "crlPath");
 char *verifyServerCert = cfgOption2(profileName, "verifyServerCert");
 
 unsigned int port = 0;
 
 if ((host != NULL) && (user != NULL) && (password != NULL) && (hashLookup(profiles, profileName) == NULL))
     {
     /* for the default profile, allow environment variable override */
     if (sameString(profileName, defaultProfileName))
         {
         host = envOverride("HGDB_HOST", host);
         portstr = envOverride("HGDB_PORT", portstr);
         socket = envOverride("HGDB_SOCKET", socket);
         user = envOverride("HGDB_USER", user);
         password = envOverride("HGDB_PASSWORD", password);
 	// ssl
 	key = envOverride("HGDB_KEY", key);
 	cert = envOverride("HGDB_CERT", cert);
 	ca = envOverride("HGDB_CA", ca);
 	caPath = envOverride("HGDB_CAPATH", caPath);
 	cipher = envOverride("HGDB_CIPHER", cipher);
-	verifyServerCert = envOverride("HGDB_CIPHER", verifyServerCert);
+	crl = envOverride("HGDB_CRL", crl);
+	crlPath = envOverride("HGDB_CRLPATH", crlPath);
+	verifyServerCert = envOverride("HGDB_VERIFY_SERVER_CERT", verifyServerCert);
         }
 
     if (portstr != NULL)
 	port = atoi(portstr);
 
-    struct sqlProfile *sp = sqlProfileNew(profileName, host, port, socket, user, password, key, cert, ca, caPath, cipher, verifyServerCert);
+    struct sqlProfile *sp;
+    AllocVar(sp);
+    sp->name = cloneString(profileName);
+    sp->host = cloneString(host);
+    sp->port = port;
+    sp->socket = cloneString(socket);
+    sp->user = cloneString(user);
+    sp->password = cloneString(password);
+    sp->key = cloneString(key);
+    sp->cert = cloneString(cert);
+    sp->ca = cloneString(ca);
+    sp->caPath = cloneString(caPath);
+    sp->cipher = cloneString(cipher);
+    sp->crl = cloneString(crl);
+    sp->crlPath = cloneString(crlPath);
+    sp->verifyServerCert = cloneString(verifyServerCert);
     sqlProfileCreate(sp);
     }
 }
 
 static void sqlProfileAddProfs(struct slName *cnames)
 /* load the profiles from list of config names */
 {
 struct slName *cname;
 for (cname = cnames; cname != NULL; cname = cname->next)
     {
     char *dot1 = strchr(cname->name, '.'); // first dot in name
     if ((dot1 != NULL) && sameString(dot1, ".host"))
         {
         *dot1 = '\0';
         sqlProfileAddProfIf(cname->name);
@@ -435,30 +440,32 @@
 {
 struct sqlProfile *spIn = sqlProfileFromPairs(pairs);
 struct sqlProfile *sp = sqlProfileGet(spIn->name, NULL);
 if (sp == NULL)
     return sqlProfileCreate(spIn);
 replaceStr(&sp->host, spIn->host);
 replaceStr(&sp->socket, spIn->socket);
 sp->port = spIn->port;
 replaceStr(&sp->user, spIn->user);
 replaceStr(&sp->password, spIn->password);
 replaceStr(&sp->key, spIn->key);
 replaceStr(&sp->cert, spIn->cert);
 replaceStr(&sp->ca, spIn->ca);
 replaceStr(&sp->caPath, spIn->caPath);
 replaceStr(&sp->cipher, spIn->cipher);
+replaceStr(&sp->crl, spIn->crl);
+replaceStr(&sp->crlPath, spIn->crlPath);
 replaceStr(&sp->verifyServerCert, spIn->verifyServerCert);
 }
 
 void sqlProfileConfigDefault(struct slPair *pairs)
 /* Set configuration for the default profile.  This overrides an existing
  * profile in hg.conf or defines a new one.  Results are unpredictable if a
  * connect cache has been established for this profile. */
 {
 struct slPair *found = slPairFind(pairs, "name");
 if (found)
     found->val = defaultProfileName;
 else
     slPairAdd(&pairs, "name", defaultProfileName);
 sqlProfileConfig(pairs);
 }
@@ -480,30 +487,37 @@
     dyStringPrintf(dy, "password=%s\n", sp->password);
 if (sp->port)
     dyStringPrintf(dy, "port=%d\n", sp->port);
 if (sp->socket)
     dyStringPrintf(dy, "socket=%s\n", sp->socket);
 if (sp->key)
     dyStringPrintf(dy, "ssl-key=%s\n", sp->key);
 if (sp->cert)
     dyStringPrintf(dy, "ssl-cert=%s\n", sp->cert);
 if (sp->ca)
     dyStringPrintf(dy, "ssl-ca=%s\n", sp->ca);
 if (sp->caPath)
     dyStringPrintf(dy, "ssl-capath=%s\n", sp->caPath);
 if (sp->cipher)
     dyStringPrintf(dy, "ssl-cipher=%s\n", sp->cipher);
+if (mysql_get_client_version() >= 50603) // mysql version "5.6.3"
+    {
+    if (sp->crl)
+	dyStringPrintf(dy, "ssl-crl=%s\n", sp->crl);
+    if (sp->crlPath)
+	dyStringPrintf(dy, "ssl-crlpath=%s\n", sp->crlPath);
+    }
 if (sp->verifyServerCert && !sameString(sp->verifyServerCert,"0"))
     dyStringPrintf(dy, "ssl-verify-server-cert\n");
 return dyStringCannibalize(&dy);
 }
 
 
 static void monitorInit(void)
 /* initialize monitoring on the first call */
 {
 unsigned flags = 0;
 char *val;
 
 /* there is special code in cheap.cgi to pass these from cgiOption to env */
 
 val = getenv("JKSQL_TRACE");
@@ -1057,31 +1071,41 @@
 
 if ((sc->conn = conn = mysql_init(NULL)) == NULL)
     // no need for monitorLeave here
     errAbort("Couldn't connect to mySQL.");
 // Fix problem where client LOCAL setting is disabled by default for security
 mysql_options(conn, MYSQL_OPT_LOCAL_INFILE, NULL);
 
 // Boolean option to tell client to verify that the host server certificate Subject CN equals the hostname.
 // If turned on this can defeat Man-In-The-Middle attacks.
 if (sp->verifyServerCert && !sameString(sp->verifyServerCert,"0"))
     {
     my_bool flag = TRUE;
     mysql_options(conn, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &flag);
     }
 
-// TODO GALT should be optional based on some mysql variable setting?
+if (mysql_get_client_version() >= 50603) // mysql version "5.6.3"
+    {
+    // If certificate revocation list file provided, set mysql option
+    if (sp->crl)
+	mysql_options(conn, MYSQL_OPT_SSL_CRL, &sp->crl);
+
+    // If path to directory with crl files provided, set mysql option
+    if (sp->crlPath)
+	mysql_options(conn, MYSQL_OPT_SSL_CRLPATH, &sp->crlPath);
+    }
+
 if (sp->key || sp->cert || sp->ca || sp->caPath || sp->cipher)
     mysql_ssl_set(conn, sp->key, sp->cert, sp->ca, sp->caPath, sp->cipher); 
 
 if (mysql_real_connect(
 	conn,
 	sp->host, /* host */
 	sp->user,	/* user name */
 	sp->password,	/* password */
 	database, /* database */
 	sp->port,	/* port */
 	sp->socket,	/* socket */
 	0)	/* flags */  == NULL)
     {
     monitorLeave();
     monitorEnterTime = oldTime;
@@ -1124,50 +1148,50 @@
 /* Connect to database somewhere as somebody. Database maybe NULL to just
  * connect to the server.  If abort is set display error message and abort on
  * error. */
 {
 struct sqlConnection *sc;
 AllocVar(sc);
 return sqlConnRemoteFillIn(sc, sp, database, abort, TRUE);
 }
 
 struct sqlConnection *sqlConnectRemote(char *host, char *user, char *password,
                                        char *database)
 /* Connect to database somewhere as somebody. Database maybe NULL to
  * just connect to the server. Abort on error. 
  * This only takes limited connection parameters. Use Full version for access to all.*/
 {
-struct sqlProfile* sp = sqlProfileNew(
-    NULL,
-    host, 0, NULL, user, password, 
-    NULL, NULL, NULL, NULL, NULL, NULL	// ssl params
-    );
+struct sqlProfile *sp;
+AllocVar(sp);
+sp->host = cloneString(host);
+sp->user = cloneString(user);
+sp->password = cloneString(password);
 return sqlConnRemote(sp, database, TRUE);
 }
 
 
 struct sqlConnection *sqlMayConnectRemote(char *host, char *user, char *password,
                                           char *database)
 /* Connect to database somewhere as somebody. Database maybe NULL to
  * just connect to the server.  Return NULL if can't connect. 
  * This only takes limited connection parameters. Use Full version for access to all.*/
 {
-struct sqlProfile* sp = sqlProfileNew(
-    NULL,
-    host, 0, NULL, user, password, 
-    NULL, NULL, NULL, NULL, NULL, NULL  // ssl params
-    );
+struct sqlProfile *sp;
+AllocVar(sp);
+sp->host = cloneString(host);
+sp->user = cloneString(user);
+sp->password = cloneString(password);
 return sqlConnRemote(sp, database, FALSE);
 }
 
 struct sqlConnection *sqlConnectRemoteFull(struct slPair *pairs, char *database)
 /* Connect to database somewhere as somebody. Database maybe NULL to
  * just connect to the server. Abort on error. 
  * Connection parameter pairs contains a list of name/values. */
 {
 struct sqlProfile *sp = sqlProfileFromPairs(pairs);
 return sqlConnRemote(sp, database, TRUE);
 }
 
 struct sqlConnection *sqlMayConnectRemoteFull(struct slPair *pairs, char *database)
 /* Connect to database somewhere as somebody. Database maybe NULL to
  * just connect to the server.