// Copyright (c) 2000-2005 David Muse // See the file COPYING for more information #include #include #include #include #include #include sqlrconfigfile::sqlrconfigfile() : xmlsax() { addresses=new char *[1]; addresses[0]=charstring::duplicate("0.0.0.0"); addresscount=1; port=charstring::toInteger(DEFAULT_PORT); listenoninet=(port)?true:false; unixport=charstring::duplicate(DEFAULT_SOCKET); listenonunix=(unixport[0])?true:false; dbase=charstring::duplicate(DEFAULT_DBASE); connections=charstring::toInteger(DEFAULT_CONNECTIONS); maxconnections=charstring::toInteger(DEFAULT_MAXCONNECTIONS); maxqueuelength=charstring::toInteger(DEFAULT_MAXQUEUELENGTH); growby=charstring::toInteger(DEFAULT_GROWBY); ttl=charstring::toInteger(DEFAULT_TTL); endofsession=charstring::duplicate(DEFAULT_ENDOFSESSION); endofsessioncommit=!charstring::compare(endofsession,"commit"); sessiontimeout=charstring::toUnsignedInteger(DEFAULT_SESSIONTIMEOUT); runasuser=charstring::duplicate(DEFAULT_RUNASUSER); runasgroup=charstring::duplicate(DEFAULT_RUNASGROUP); cursors=charstring::toInteger(DEFAULT_CURSORS); authtier=charstring::duplicate(DEFAULT_AUTHTIER); authonlistener=charstring::contains(authtier,"listener"); authonconnection=charstring::contains(authtier,"connection"); authondatabase=!charstring::compare(authtier,"database"); handoff=charstring::duplicate(DEFAULT_HANDOFF); passdescriptor=!charstring::compare(handoff,"pass"); allowedips=charstring::duplicate(DEFAULT_DENIEDIPS); deniedips=charstring::duplicate(DEFAULT_DENIEDIPS); debug=charstring::duplicate(DEFAULT_DEBUG); debuglistener=charstring::contains(debug,"listener"); debugconnection=charstring::contains(debug,"connection"); maxquerysize=charstring::toInteger(DEFAULT_MAXQUERYSIZE); maxstringbindvaluelength=charstring::toInteger( DEFAULT_MAXSTRINGBINDVALUELENGTH); maxlobbindvaluelength=charstring::toInteger( DEFAULT_MAXLOBBINDVALUELENGTH); idleclienttimeout=charstring::toInteger(DEFAULT_IDLECLIENTTIMEOUT); currentuser=NULL; firstconnect=NULL; currentconnect=NULL; connectstringcount=0; metrictotal=0; sidenabled=DEFAULT_SID_ENABLED; sidhost=charstring::duplicate(DEFAULT_SID_HOST); sidport=DEFAULT_SID_PORT; sidsocket=charstring::duplicate(DEFAULT_SID_SOCKET); siduser=charstring::duplicate(DEFAULT_SID_USER); sidpassword=charstring::duplicate(DEFAULT_SID_PASSWORD); maxlisteners=charstring::toInteger(DEFAULT_MAXLISTENERS); listenertimeout=charstring::toUnsignedInteger(DEFAULT_LISTENERTIMEOUT); currentroute=NULL; inrouter=false; ignoreconnections=false; } sqlrconfigfile::~sqlrconfigfile() { for (uint64_t index=0; indexgetData(); un=un->getNext(); } connectstringnode *csn=connectstringlist.getNodeByIndex(0); while (csn) { delete csn->getData(); csn=csn->getNext(); } delete[] sidhost; delete[] sidsocket; delete[] siduser; delete[] sidpassword; routenode *rn=routelist.getNodeByIndex(0); while (rn) { delete rn->getData(); rn=rn->getNext(); } } const char * const * sqlrconfigfile::getAddresses() { return addresses; } uint64_t sqlrconfigfile::getAddressCount() { return addresscount; } uint16_t sqlrconfigfile::getPort() { return port; } const char *sqlrconfigfile::getUnixPort() { return unixport; } bool sqlrconfigfile::getListenOnInet() { return listenoninet; } bool sqlrconfigfile::getListenOnUnix() { return listenonunix; } const char *sqlrconfigfile::getDbase() { return dbase; } uint32_t sqlrconfigfile::getConnections() { return connections; } uint32_t sqlrconfigfile::getMaxConnections() { return maxconnections; } uint32_t sqlrconfigfile::getMaxQueueLength() { return maxqueuelength; } uint32_t sqlrconfigfile::getGrowBy() { return growby; } uint32_t sqlrconfigfile::getTtl() { return ttl; } bool sqlrconfigfile::getDynamicScaling() { return (maxconnections>connections && growby>0 && ttl>0 && maxqueuelength<=maxlisteners); } const char *sqlrconfigfile::getEndOfSession() { return endofsession; } bool sqlrconfigfile::getEndOfSessionCommit() { return endofsessioncommit; } uint32_t sqlrconfigfile::getSessionTimeout() { return sessiontimeout; } const char *sqlrconfigfile::getRunAsUser() { return runasuser; } const char *sqlrconfigfile::getRunAsGroup() { return runasgroup; } uint16_t sqlrconfigfile::getCursors() { return cursors; } const char *sqlrconfigfile::getAuthTier() { return authtier; } bool sqlrconfigfile::getAuthOnListener() { return authonlistener; } bool sqlrconfigfile::getAuthOnConnection() { return authonconnection; } bool sqlrconfigfile::getAuthOnDatabase() { return authondatabase; } const char *sqlrconfigfile::getHandOff() { return handoff; } bool sqlrconfigfile::getPassDescriptor() { return passdescriptor; } const char *sqlrconfigfile::getAllowedIps() { return allowedips; } const char *sqlrconfigfile::getDeniedIps() { return deniedips; } const char *sqlrconfigfile::getDebug() { return debug; } bool sqlrconfigfile::getDebugListener() { return debuglistener; } bool sqlrconfigfile::getDebugConnection() { return debugconnection; } uint32_t sqlrconfigfile::getMaxQuerySize() { return maxquerysize; } uint32_t sqlrconfigfile::getMaxStringBindValueLength() { return maxstringbindvaluelength; } uint32_t sqlrconfigfile::getMaxLobBindValueLength() { return maxlobbindvaluelength; } int32_t sqlrconfigfile::getIdleClientTimeout() { return idleclienttimeout; } int64_t sqlrconfigfile::getMaxListeners() { return maxlisteners; } uint32_t sqlrconfigfile::getListenerTimeout() { return listenertimeout; } bool sqlrconfigfile::getSidEnabled() { return sidenabled; } const char *sqlrconfigfile::getSidHost() { return sidhost; } uint16_t sqlrconfigfile::getSidPort() { return sidport; } const char *sqlrconfigfile::getSidUnixPort() { return sidsocket; } const char *sqlrconfigfile::getSidUser() { return siduser; } const char *sqlrconfigfile::getSidPassword() { return sidpassword; } linkedlist< usercontainer * > *sqlrconfigfile::getUserList() { // if there are no users in the list, add a default user/password if (!userlist.getLength()) { currentuser=new usercontainer(); currentuser->setUser(DEFAULT_USER); currentuser->setPassword(DEFAULT_PASSWORD); userlist.append(currentuser); } return &userlist; } linkedlist< connectstringcontainer * > *sqlrconfigfile::getConnectStringList() { return &connectstringlist; } connectstringcontainer *sqlrconfigfile::getConnectString( const char *connectionid) { connectstringnode *csn=connectstringlist.getNodeByIndex(0); while (csn) { if (!charstring::compare(connectionid, csn->getData()->getConnectionId())) { return csn->getData(); } csn=csn->getNext(); } return NULL; } uint32_t sqlrconfigfile::getConnectionCount() { return connectstringlist.getLength(); } uint32_t sqlrconfigfile::getMetricTotal() { // This is tallied here instead of whenever the parser runs into a // metric attribute because people often forget to include metric // attributes. In that case, though each connection has a metric, // metrictotal=0, causing no connections to start. if (!metrictotal) { connectstringnode *csn= connectstringlist.getNodeByIndex(0); while (csn) { metrictotal=metrictotal+csn->getData()->getMetric(); csn=csn->getNext(); } } return metrictotal; } linkedlist< routecontainer * > *sqlrconfigfile::getRouteList() { return &routelist; } bool sqlrconfigfile::tagStart(const char *name) { // don't do anything if we're already done // or have not found the correct id if (done || !correctid) { return true; } // set the current tag if (!charstring::compare(name,"user")) { currentuser=new usercontainer(); userlist.append(currentuser); } else if (!charstring::compare(name,"connection")) { if (!ignoreconnections) { currentconnect= new connectstringcontainer(connectstringcount); connectstringlist.append(currentconnect); } } else if (!charstring::compare(name,"router")) { inrouter=true; currentconnect=new connectstringcontainer(connectstringcount); connectstringlist.append(currentconnect); currentconnect->setConnectionId(DEFAULT_CONNECTIONID); ignoreconnections=true; } else if (!charstring::compare(name,"route")) { currentroute=new routecontainer(); } else if (!charstring::compare(name,"filter")) { currentroute=new routecontainer(); currentroute->setIsFilter(true); } return true; } bool sqlrconfigfile::attributeName(const char *name) { // don't do anything if we're already done if (done) { return true; } // set the current attribute if (!charstring::compare(name,"id")) { currentattribute=ID_ATTRIBUTE; } else if (!charstring::compare(name,"addresses")) { currentattribute=ADDRESSES_ATTRIBUTE; } else if (!charstring::compare(name,"port")) { if (!inrouter) { currentattribute=PORT_ATTRIBUTE; } else { currentattribute=ROUTER_PORT_ATTRIBUTE; } } else if (!charstring::compare(name,"socket") || !charstring::compare(name,"unixport")) { if (!inrouter) { currentattribute=SOCKET_ATTRIBUTE; } else { currentattribute=ROUTER_SOCKET_ATTRIBUTE; } } else if (!charstring::compare(name,"dbase")) { currentattribute=DBASE_ATTRIBUTE; } else if (!charstring::compare(name,"connections")) { currentattribute=CONNECTIONS_ATTRIBUTE; } else if (!charstring::compare(name,"maxconnections")) { currentattribute=MAXCONNECTIONS_ATTRIBUTE; } else if (!charstring::compare(name,"maxqueuelength")) { currentattribute=MAXQUEUELENGTH_ATTRIBUTE; } else if (!charstring::compare(name,"growby")) { currentattribute=GROWBY_ATTRIBUTE; } else if (!charstring::compare(name,"ttl")) { currentattribute=TTL_ATTRIBUTE; } else if (!charstring::compare(name,"endofsession")) { currentattribute=ENDOFSESSION_ATTRIBUTE; } else if (!charstring::compare(name,"sessiontimeout")) { currentattribute=SESSIONTIMEOUT_ATTRIBUTE; } else if (!charstring::compare(name,"runasuser")) { currentattribute=RUNASUSER_ATTRIBUTE; } else if (!charstring::compare(name,"runasgroup")) { currentattribute=RUNASGROUP_ATTRIBUTE; } else if (!charstring::compare(name,"cursors")) { currentattribute=CURSORS_ATTRIBUTE; } else if (!charstring::compare(name,"authtier") || !charstring::compare(name,"authentication")) { currentattribute=AUTHTIER_ATTRIBUTE; } else if (!charstring::compare(name,"handoff")) { currentattribute=HANDOFF_ATTRIBUTE; } else if (!charstring::compare(name,"deniedips")) { currentattribute=DENIEDIPS_ATTRIBUTE; } else if (!charstring::compare(name,"allowedips")) { currentattribute=ALLOWEDIPS_ATTRIBUTE; } else if (!charstring::compare(name,"debug")) { currentattribute=DEBUG_ATTRIBUTE; } else if (!charstring::compare(name,"maxquerysize")) { currentattribute=MAXQUERYSIZE_ATTRIBUTE; } else if (!charstring::compare(name,"maxstringbindvaluelength")) { currentattribute=MAXSTRINGBINDVALUELENGTH_ATTRIBUTE; } else if (!charstring::compare(name,"maxlobbindvaluelength")) { currentattribute=MAXLOBBINDVALUELENGTH_ATTRIBUTE; } else if (!charstring::compare(name,"idleclienttimeout")) { currentattribute=IDLECLIENTTIMEOUT_ATTRIBUTE; } else if (!charstring::compare(name,"sidenabled")) { currentattribute=SID_ENABLED_ATTRIBUTE; } else if (!charstring::compare(name,"sidhost")) { currentattribute=SID_HOST_ATTRIBUTE; } else if (!charstring::compare(name,"sidport")) { currentattribute=SID_PORT_ATTRIBUTE; } else if (!charstring::compare(name,"sidsocket")) { currentattribute=SID_SOCKET_ATTRIBUTE; } else if (!charstring::compare(name,"siduser")) { currentattribute=SID_USER_ATTRIBUTE; } else if (!charstring::compare(name,"sidpassword")) { currentattribute=SID_PASSWORD_ATTRIBUTE; } else if (!charstring::compare(name,"user")) { if (!inrouter) { currentattribute=USER_ATTRIBUTE; } else { currentattribute=ROUTER_USER_ATTRIBUTE; } } else if (!charstring::compare(name,"password")) { if (!inrouter) { currentattribute=PASSWORD_ATTRIBUTE; } else { currentattribute=ROUTER_PASSWORD_ATTRIBUTE; } } else if (!charstring::compare(name,"connectionid")) { currentattribute=CONNECTIONID_ATTRIBUTE; } else if (!charstring::compare(name,"string")) { currentattribute=STRING_ATTRIBUTE; } else if (!charstring::compare(name,"metric")) { currentattribute=METRIC_ATTRIBUTE; } else if (!charstring::compare(name,"behindloadbalancer")) { currentattribute=BEHINDLOADBALANCER_ATTRIBUTE; } else if (!charstring::compare(name,"host")) { currentattribute=ROUTER_HOST_ATTRIBUTE; } else if (!charstring::compare(name,"pattern")) { currentattribute=ROUTER_PATTERN_ATTRIBUTE; } else if (!charstring::compare(name,"maxlisteners")) { currentattribute=MAXLISTENERS_ATTRIBUTE; } else if (!charstring::compare(name,"listenertimeout")) { currentattribute=LISTENERTIMEOUT_ATTRIBUTE; } else { currentattribute=(attribute)0; } return true; } bool sqlrconfigfile::attributeValue(const char *value) { // don't do anything if we're already done if (done) { return true; } if (!correctid) { // if we haven't found the correct id yet, check for it if (currentattribute==ID_ATTRIBUTE) { if (value && !charstring::compare(value,id)) { correctid=true; } } } else { // if we have found the correct id, process the attribute if (currentattribute==ADDRESSES_ATTRIBUTE) { for (uint64_t index=0; indexsetUser((value)?value:DEFAULT_USER); } else if (currentattribute==PASSWORD_ATTRIBUTE) { currentuser->setPassword((value)?value: DEFAULT_PASSWORD); } else if (currentattribute==CONNECTIONID_ATTRIBUTE) { if (currentconnect) { if (charstring::length(value)> MAXCONNECTIONIDLEN) { fprintf(stderr,"error: connectionid \"%s\" is too long, must be %d characters or fewer.\n",value,MAXCONNECTIONIDLEN); return false; } currentconnect->setConnectionId((value)?value: DEFAULT_CONNECTIONID); } } else if (currentattribute==STRING_ATTRIBUTE) { if (currentconnect) { currentconnect->setString((value)?value: DEFAULT_CONNECTSTRING); currentconnect->parseConnectString(); } } else if (currentattribute==METRIC_ATTRIBUTE) { if (currentconnect) { currentconnect->setMetric( atouint32_t(value,DEFAULT_METRIC,1)); } } else if (currentattribute==BEHINDLOADBALANCER_ATTRIBUTE) { if (currentconnect) { currentconnect->setBehindLoadBalancer( !charstring::compareIgnoringCase( value,"yes")); } } else if (currentattribute==ROUTER_HOST_ATTRIBUTE) { currentroute->setHost((value)?value: DEFAULT_ROUTER_HOST); } else if (currentattribute==ROUTER_PORT_ATTRIBUTE) { currentroute->setPort(atouint32_t(value, DEFAULT_ROUTER_PORT,1)); } else if (currentattribute==ROUTER_SOCKET_ATTRIBUTE) { currentroute->setSocket((value)?value: DEFAULT_ROUTER_SOCKET); } else if (currentattribute==ROUTER_USER_ATTRIBUTE) { currentroute->setUser((value)?value: DEFAULT_ROUTER_USER); } else if (currentattribute==ROUTER_PASSWORD_ATTRIBUTE) { currentroute->setPassword((value)?value: DEFAULT_ROUTER_PASSWORD); } else if (currentattribute==ROUTER_PATTERN_ATTRIBUTE) { regularexpression *re= new regularexpression( (value)?value:DEFAULT_ROUTER_PATTERN); re->study(); currentroute->getRegexList()->append(re); } else if (currentattribute==MAXLISTENERS_ATTRIBUTE) { maxlisteners=charstring::toInteger( (value)?value:DEFAULT_MAXLISTENERS); if (maxlisteners<-1) { maxlisteners=-1; } } else if (currentattribute==LISTENERTIMEOUT_ATTRIBUTE) { listenertimeout= charstring::toUnsignedInteger( (value)?value:DEFAULT_LISTENERTIMEOUT); } } return true; } uint32_t sqlrconfigfile::atouint32_t(const char *value, const char *defaultvalue, uint32_t minvalue) { uint32_t retval=charstring::toUnsignedInteger( (value)?value:defaultvalue); if (retvalgetData(); if (!charstring::compare(rc->getHost(), cur->getHost()) && rc->getPort()==cur->getPort() && !charstring::compare(rc->getSocket(), cur->getSocket()) && !charstring::compare(rc->getUser(), cur->getUser()) && !charstring::compare(rc->getPassword(), cur->getPassword())) { return rc; } rn=rn->getNext(); } return NULL; } void sqlrconfigfile::moveRegexList(routecontainer *cur, routecontainer *existing) { linkedlistnode< regularexpression * > *re=cur->getRegexList()-> getNodeByIndex(0); while (re) { existing->getRegexList()->append(re->getData()); re=re->getNext(); } cur->getRegexList()->clear(); } bool sqlrconfigfile::parse(const char *config, const char *id) { return parse(config,id,0); } bool sqlrconfigfile::parse(const char *config, const char *id, uint16_t connectstringcount) { // init some variables this->connectstringcount=connectstringcount; this->id=id; correctid=false; done=false; // parse the file bool retval=true; if (!parseFile(config)) { fprintf(stderr,"Couldn't parse config file %s.\n",config); retval=false; } // parse the user's .sqlrelay.conf file const char *homedir=getenv("HOME"); char *filename; if (homedir && homedir[0]) { size_t filenamelen=charstring::length(homedir)+15+1; filename=new char[filenamelen]; snprintf(filename,filenamelen,"%s/.sqlrelay.conf",homedir); } else { filename=charstring::duplicate("~/.sqlrelay.conf"); } // see if the file exists before trying to parse it, don't worry about // an error message here parseFile(filename); delete[] filename; // if the specified instance wasn't found, warn the user if (!done) { fprintf(stderr,"Couldn't find id %s.\n",id); retval=false; } return retval; } usercontainer::usercontainer() { user=NULL; password=NULL; } usercontainer::~usercontainer() { delete[] user; delete[] password; } void usercontainer::setUser(const char *user) { this->user=charstring::duplicate(user); } void usercontainer::setPassword(const char *password) { this->password=charstring::duplicate(password); } const char *usercontainer::getUser() { return user; } const char *usercontainer::getPassword() { return password; } connectstringcontainer::connectstringcontainer(uint16_t connectstringcount) { this->connectstringcount=connectstringcount; connectionid=NULL; string=NULL; metric=charstring::toInteger(DEFAULT_METRIC); behindloadbalancer=!charstring::compareIgnoringCase( DEFAULT_BEHINDLOADBALANCER,"yes"); } connectstringcontainer::~connectstringcontainer() { delete[] string; delete[] connectionid; } void connectstringcontainer::setConnectionId(const char *connectionid) { this->connectionid=charstring::duplicate(connectionid); } void connectstringcontainer::setString(const char *string) { this->string=charstring::duplicate(string); } void connectstringcontainer::setMetric(uint32_t metric) { this->metric=metric; } void connectstringcontainer::setBehindLoadBalancer(bool behindloadbalancer) { this->behindloadbalancer=behindloadbalancer; } const char *connectstringcontainer::getConnectionId() { return connectionid; } const char *connectstringcontainer::getString() { return string; } uint32_t connectstringcontainer::getMetric() { return metric; } bool connectstringcontainer::getBehindLoadBalancer() { return behindloadbalancer; } void connectstringcontainer::parseConnectString() { if (!connectstringcount) { return; } connectstring.parse(string); } const char *connectstringcontainer::getConnectStringValue( const char *variable) { return connectstring.getValue(variable); } routecontainer::routecontainer() { isfilter=false; host=NULL; port=0; socket=NULL; user=NULL; password=NULL; } routecontainer::~routecontainer() { delete[] host; delete[] socket; delete[] user; delete[] password; linkedlistnode< regularexpression * > *re=regexlist.getNodeByIndex(0); while (re) { delete re->getData(); re=re->getNext(); } } void routecontainer::setIsFilter(bool isfilter) { this->isfilter=isfilter; } void routecontainer::setHost(const char *host) { this->host=charstring::duplicate(host); } void routecontainer::setPort(uint16_t port) { this->port=port; } void routecontainer::setSocket(const char *socket) { this->socket=charstring::duplicate(socket); } void routecontainer::setUser(const char *user) { this->user=charstring::duplicate(user); } void routecontainer::setPassword(const char *password) { this->password=charstring::duplicate(password); } bool routecontainer::getIsFilter() { return isfilter; } const char *routecontainer::getHost() { return host; } uint16_t routecontainer::getPort() { return port; } const char *routecontainer::getSocket() { return socket; } const char *routecontainer::getUser() { return user; } const char *routecontainer::getPassword() { return password; } linkedlist< regularexpression * > *routecontainer::getRegexList() { return ®exlist; }