How to send C++ and mysql dynamic mysql queries - c++

Working with Visual Studio, Windows 7 and mysql.h library.
What I want to do is send a MySQL query like this:
mysql_query(conn, "SELECT pass FROM users WHERE name='Leo Tolstoy'");
The only thing I can't get working is sending a query where the name would be not a constant as it's shown above, but a variable taken from a text field or anything else. So how should I work with a variable instead of a constant?
Hope I made my question clear.

Use a prepared statement, which lets you parameterize values, similar to how functions let you parameterize variables in statement blocks. If using MySQL Connector/C++:
// use std::unique_ptr, boost::shared_ptr, or whatever is most appropriate for RAII
// Connector/C++ requires boost, so
std::unique_ptr<sql::Connection> db;
std::unique_ptr<sql::PreparedStatement> getPassword
std::unique_ptr<sql::ResultSet> result;
std::string name = "Nikolai Gogol";
std::string password;
...
getPassword = db->prepareStatement("SELECT pass FROM users WHERE name=? LIMIT 1");
getPassword->setString(1, name);
result = getPassword->execute();
if (result->first()) {
password = result->getString("pass");
} else {
// no result
...
}
// smart pointers will handle deleting the sql::* instances
Create classes to handle database access and wrap that in a method, and the rest of the application doesn't even need to know that a database is being used.
If you really want to use the old C API for some reason:
MYSQL *mysql;
...
const my_bool yes=1, no=0;
const char* getPassStmt = "SELECT password FROM users WHERE username=? LIMIT 1";
MYSQL_STMT *getPassword;
MYSQL_BIND getPassParams;
MYSQL_BIND result;
std::string name = "Nikolai Gogol";
std::string password;
if (! (getPassword = mysql_stmt_init(mysql))) {
// error: couldn't allocate space for statement
...
}
if (mysql_stmt_prepare(getPassword, getPassStmt, strlen(getPassStmt))) {
/* error preparing statement; handle error and
return early or throw an exception. RAII would make
this easier.
*/
...
} else {
unsigned long nameLength = name.size();
memset(&getPassParams, 0, sizeof(getPassParams));
getPassParams.buffer_type = MYSQL_TYPE_STRING;
getPassParams.buffer = (char*) name.c_str();
getPassParams.length = &nameLength;
if (mysql_stmt_bind_param(getPassword, &getPassParams)) {
/* error binding param */
...
} else if (mysql_stmt_execute(getPassword)) {
/* error executing query */
...
} else {
// for mysql_stmt_num_rows()
mysql_stmt_store_result(getPassword);
if (mysql_stmt_num_rows(getPassword)) {
unsigned long passwordLength=0;
memset(&result, 0, sizeof(result));
result.length = &passwordLength;
mysql_stmt_bind_result(getPassword, &result);
mysql_stmt_fetch(getPassword);
if (passwordLength > 0) {
result.buffer = new char[passwordLength+1];
memset(result.buffer, 0, passwordLength+1);
result.buffer_length = passwordLength+1;
if (mysql_stmt_fetch_column(getPassword, &result, 0, 0)) {
...
} else {
password = static_cast<const char*>(result.buffer);
}
}
} else {
// no result
cerr << "No user '" << name << "' found." << endl;
}
}
mysql_stmt_free_result(getPassword);
}
mysql_stmt_close(getPassword);
mysql_close(mysql);
As you see, Connector/C++ is simpler. It's also less error prone; I probably made more mistakes using the C API than Connector/C++.
See also:
Developing Database Applications Using MySQL Connector/C++
Connector C++ in the MySQL Forge wiki

Wouldn't you just build the query-string, using sprint or concatenating strings or whatever, so that by the time it gets to MySQL, MySQL just sees the SQL and has no idea where the constant came from? Or am I missing something?

here is an example:
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
/// ...
string name_value = "Leo Tolstoy";
ostringstream strstr;
strstr << "SELECT pass FROM users WHERE name='" << name_value << "'";
string str = strstr.str();
mysql_query(conn, str.c_str());

Related

How to use a string in a Sql argument?

How should go about inserting a string into a SQL argument?
Something like this:
string clas = "Computer Science";
sql = "SELECT * from STUDENTS where CLASS='clas'";
There are two ways of doing this:
This is the preferred and more secure way. You can use prepared statements like this
string clas = "Computer Science";
sql = "SELECT * FROM Students WHERE Class=?";
// Prepare the request right here
preparedStatement.setString(1, clas);
// Execute the request down here
A simpler but much less secure option (it's vulnerable to SQL-Injections)
string clas = "Computer Science";
sql = "SELECT * FROM Students WHERE Class='" + clas + "'";
Simple answer:
You can just do as follows:
string clas = "Computer Science";
sql = "SELECT * FROM Students WHERE Class='" + clas + "'";
Good answer:
But, we can do better than that. What if multiple value replacement needed, then what? See the code below, it can replace multiple strings. And also, you can write sql injection check if needed. And the best thing, you just have to call the prepare() function and you're done.
Usage Instructions:
Use ? where you need to put a string. If there are multiple string replacement needed, put all the strings in order(as parameters) when calling prepare function. Also, notice prepare function call prepare(sql, {param_1, param_2, param_3, ..., param_n}).
[Note: it'll work with c++11 and higher versions. It won't work with c++11 pre version. So, while compile it, use -std=c++11 flag with g++]
#include <iostream>
#include <string>
#include <initializer_list>
using namespace std;
// write code for sql injection if you think
// it necessary for your program
// is_safe checks for sql injection
bool is_safe(string str) {
// check if str is sql safe or not
// for sql injection
return true; // or false if not sql injection safe
}
void prepare(string &sql, initializer_list<string> list_buf) {
int idx = 0;
int list_size = (int)list_buf.size();
int i = 0;
for(string it: list_buf) {
// check for sql injection
// if you think it's necessary
if(!is_safe(it)) {
// throw error
// cause, sql injection risk
}
if(i >= list_size) {
// throw error
// cause not enough params are given in list_buf
}
idx = sql.find("?", idx);
if (idx == std::string::npos) {
if(i < list_size - 1) {
// throw error
// cause not all params given in list_buf are used
}
}
sql.replace(idx, 1, it);
idx += 1; // cause "?" is 1 char
i++;
}
}
// now test it
int main() {
string sql = "SELECT * from STUDENTS where CLASS=?";
string clas = "clas";
prepare(sql, {clas});
cout << sql << endl;
string sql2 = "select name from class where marks > ? or attendence > ?";
string marks = "80";
string attendence = "40";
prepare(sql2, {marks, attendence});
cout << sql2 << endl;
return 0;
}
[P.S.]: feel free to ask, if anything is unclear.

How can I write a file with containing a lua table using sol2

I've settled on using lua as my config management for my programs after seeing posts like this and loving the syntax, and sol2 recently got released so I'm using that.
So my question is, how can I grab all the variables in my lua state and spit them out in a file?
say,
sol::state lua;
lua["foo"]["bar"] = 2;
lua["foo"]["foobar"] = lua.create_table();
would, in turn, eventually spit out
foo = {
bar = 2
foobar = {}
}
Is this at all possible and if so, how?
I used this serializer to serialize my table and print it out, really quite easy!
This is what I came up with
std::string save_table(const std::string& table_name, sol::state& lua)
{
auto table = lua["serpent"];
if (!table.valid()) {
throw std::runtime_error("Serpent not loaded!");
}
if (!lua[table_name].valid()) {
throw std::runtime_error(table_name + " doesn't exist!");
}
std::stringstream out;
out << table_name << " = ";
sol::function block = table["block"];
std::string cont = block(lua[table_name]);
out << cont;
return std::move(out.str());
}

how to pass data from terminal to a program?

i am using a GPS reciever that will print GPS message contiuously in terminal using a C++ program like this
Latitude:13.3 Longitude:80.25
Latitude:13.4 Longitude:80.27
Latitude:13.5 Longitude:80.28
I want to take this data inside my c++ program (QT Application)
Below is my full program code
void QgsGpsPlotPluginGui::on_buttonBox_accepted()
{
QString myPluginsDir = "usr/lib/qgis/plugins";
QgsProviderRegistry::instance(myPluginsDir);
QgsVectorLayer * mypLayer = new QgsVectorLayer("/home/mit/Documents/Dwl/GIS DataBase/india_placename.shp","GPS","ogr");
QgsSingleSymbolRenderer *mypRenderer = new
QgsSingleSymbolRenderer(mypLayer->geometryType());
QList <QgsMapCanvasLayer> myLayerSet;
mypLayer->setRenderer(mypRenderer);
if (mypLayer->isValid())
{
qDebug("Layer is valid");
}
else
{
qDebug("Layer is NOT valid");
}
// Add the Vector Layer to the Layer Registry
QgsMapLayerRegistry::instance()->addMapLayer(mypLayer, TRUE);
// Add the Layer to the Layer Set
myLayerSet.append(QgsMapCanvasLayer(mypLayer, TRUE));
QgsMapCanvas * mypMapCanvas = new QgsMapCanvas(0, 0);
mypMapCanvas->setExtent(mypLayer->extent());
mypMapCanvas->enableAntiAliasing(true);
mypMapCanvas->setCanvasColor(QColor(255, 255, 255));
mypMapCanvas->freeze(false);
QgsFeature * mFeature = new QgsFeature();
QgsGeometry * geom = QgsGeometry::fromPoint(*p);
QGis::GeometryType geometryType=QGis::Point;
QgsRubberBand * mrub = new QgsRubberBand (mypMapCanvas,geometryType);
QgsPoint * p = new QgsPoint();
double latitude =13.3;
double longitude = 80.25;
p->setX(latitude);
p->setY(longitude);
mrub->setToGeometry(geom,mypLayer);
mrub->show()
}
In the above code i have manually entered the value for Latitude and Longitude like this,
double latitude =13.3;
double longitude = 80.25;
p->setX(latitude);
p->setY(longitude);
but i need to get these value from terminal.
Both program are written in c++ but they belong to different framework.
I assume that your library doesn't have an API you can use.
Then one fairly straight forward way to integrate them would be to use pipes.
You can quickly do something like
gps_program | qt_program
And now you get the coordinates via stdin.
The more complex way to set it up is using exec and fork. You create pipe objects, then fork and run using exec the gps_programon one of the branches. This you can do entirely in your code without depending on bash or something like it. You still have to parse the data coming from the pipe the same way.
Just create a pipe:
#include <cstdio>
#include <iostream>
#define WWRITER 0
#if WWRITER
int main() {
while (true) {
std::cout << "Latitude:13.3 Longitude:80.25";
}
return 0;
}
#else
int main() {
FILE* fp = popen("Debug/Writer", "r");
if(fp == 0) perror(0);
else {
const std::size_t LatitudeLength = 9;
const std::size_t LongitudeLength = 10;
char latitude_name[LatitudeLength+1];
char longitude_name[LongitudeLength+1];
double latitude;
double longitude;
while(fscanf(fp, "%9s%lf%10s%lf",
latitude_name,
&latitude,
longitude_name,
&longitude) == 4)
{
std::cout << "Values: " << latitude << ", " << longitude << std::endl;
}
pclose(fp);
}
return 0;
}
#endif
Note: The example runs endlessly.
+1 to Sorin's answer, makes this nice and easy passing stdout to stdin :) but assuming you are running in linux / cigwin?
But if you have access to both program codes then a nicer solution is to use UdpSockets (or maybe Tcp, but Udp is simpler) and pass the data between programs in this way... not sure how big/long-term your solution needs to be but if you want to integrate them in a "long-term" and more maintainable way this would be a better approach.

PAM Authentication for a Legacy Application

I have a legacy app that receives a username/password request asynchronously over the wire. Since I already have the username and password stored as variables, what would be the best way to authenticate with PAM on Linux (Debian 6)?
I've tried writing my own conversation function, but I'm not sure of the best way of getting the password into it. I've considered storing it in appdata and referencing that from the pam_conv struct, but there's almost no documentation on how to do that.
Is there a simpler way to authenticate users without the overkill of a conversation function? I'm unable to use pam_set_data successfully either, and I'm not sure that's even appropriate.
Here's what I'm doing:
user = guiMessage->username;
pass = guiMessage->password;
pam_handle_t* pamh = NULL;
int pam_ret;
struct pam_conv conv = {
my_conv,
NULL
};
pam_start("nxs_login", user, &conv, &pamh);
pam_ret = pam_authenticate(pamh, 0);
if (pam_ret == PAM_SUCCESS)
permissions = 0xff;
pam_end(pamh, pam_ret);
And initial attempts at the conversation function resulted in (password is hard-coded for testing):
int
my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *data)
{
struct pam_response *aresp;
if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((aresp = (pam_response*)calloc(num_msg, sizeof *aresp)) == NULL)
return (PAM_BUF_ERR);
aresp[0].resp_retcode = 0;
aresp[0].resp = strdup("mypassword");
*resp = aresp;
return (PAM_SUCCESS);
}
Any help would be appreciated. Thank you!
This is what I ended up doing. See the comment marked with three asterisks.
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <security/pam_appl.h>
#include <unistd.h>
// To build this:
// g++ test.cpp -lpam -o test
// if pam header files missing try:
// sudo apt install libpam0g-dev
struct pam_response *reply;
//function used to get user input
int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
*resp = reply;
return PAM_SUCCESS;
}
int main(int argc, char** argv)
{
if(argc != 2) {
fprintf(stderr, "Usage: check_user <username>\n");
exit(1);
}
const char *username;
username = argv[1];
const struct pam_conv local_conversation = { function_conversation, NULL };
pam_handle_t *local_auth_handle = NULL; // this gets set by pam_start
int retval;
// local_auth_handle gets set based on the service
retval = pam_start("common-auth", username, &local_conversation, &local_auth_handle);
if (retval != PAM_SUCCESS)
{
std::cout << "pam_start returned " << retval << std::endl;
exit(retval);
}
reply = (struct pam_response *)malloc(sizeof(struct pam_response));
// *** Get the password by any method, or maybe it was passed into this function.
reply[0].resp = getpass("Password: ");
reply[0].resp_retcode = 0;
retval = pam_authenticate(local_auth_handle, 0);
if (retval != PAM_SUCCESS)
{
if (retval == PAM_AUTH_ERR)
{
std::cout << "Authentication failure." << std::endl;
}
else
{
std::cout << "pam_authenticate returned " << retval << std::endl;
}
exit(retval);
}
std::cout << "Authenticated." << std::endl;
retval = pam_end(local_auth_handle, retval);
if (retval != PAM_SUCCESS)
{
std::cout << "pam_end returned " << retval << std::endl;
exit(retval);
}
return retval;
}
The way standard information (such as a password) is passed for PAM is by using variables set in the pam handle with pam_set_item (see the man page for pam_set_item).
You can set anything your application will need to use later into the pam_stack. If you want to put the password into the pam_stack you should be able to do that immediately after calling pam_start() by setting the PAM_AUTHTOK variable into the stack similar to the pseudo code below:
pam_handle_t* handle = NULL;
pam_start("common-auth", username, NULL, &handle);
pam_set_item( handle, PAM_AUTHTOK, password);
This will make the password available on the stack to any module that cares to use it, but you generally have to tell the module to use it by setting the standard use_first_pass, or try_first_pass options in the pam_configuration for the service (in this case /etc/pam.d/common-auth).
The standard pam_unix module does support try_first_pass, so it wouldn't hurt to add that into your pam configuration on your system (at the end of the line for pam_unix).
After you do this any call to pam_authenticate() that are invoked from the common-auth service should just pick the password up and go with it.
One small note about the difference between use_first_pass and try_first_pass: They both tell the module (in this case pam_unix) to try the password on the pam_stack, but they differ in behavior when their is no password/AUTHTOK available. In the missing case use_first_pass fails, and try_first_pass allows the module to prompt for a password.
Fantius' solution worked for me, even as root.
I originally opted for John's solution, as it was cleaner and made use of PAM variables without the conversation function (really, there isn't a need for it here), but it did not, and will not, work. As Adam Badura alluded to in both posts, PAM has some internal checks to prevent direct setting of PAM_AUTHTOK.
John's solution will result in behaviour similar to what is mentioned here, where any password value will be allowed to login (even if you declare, but do not define, the pam_conv variable).
I would also recommend users be aware of the placement of the malloc, as it will likely differ in your application (remember, the code above is more of a test/template, than anything else).
struct pam_conv {
int (*conv)(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata_ptr);
void *appdata_ptr;
};
The second field(appdata_ptr) of the struct pam_conv is passed to the conversation function,
therefore we can use it as our password pointer.
static int convCallback(int num_msg, const struct pam_message** msg,
struct pam_response** resp, void* appdata_ptr)
{
struct pam_response* aresp;
if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((aresp = (pam_response*)calloc(num_msg, sizeof * aresp)) == NULL)
return (PAM_BUF_ERR);
aresp[0].resp_retcode = 0;
aresp[0].resp = strdup((char*)appdata_ptr);
*resp = aresp;
return (PAM_SUCCESS);
}
int main()
{
....
pam_handle_t* pamH = 0;
char *password = strdup("foopassword");
struct pam_conv conversation = {convCallback, password};
int retvalPam = pam_start("check_user", "foousername", &conversation, &pamH);
//Call pam_authenticate(pamH, 0)
//Call pam_end(pamH, 0);
...
...
free(password);
}

MySQL Transactions using C++?

How would I go about wrapping an amount of queries in a transaction in C++? I'm working on Ubuntu 10, using this file:
#include "/usr/include/mysql/mysql.h"
with C++ to interact with a MySQL database.
EDIT: Right now I'm running queries through a small wrapper class, like so:
MYSQL_RES* PDB::query(string query)
{
int s = mysql_query(this->connection, query.c_str());
if( s != 0 )
{
cout << mysql_error(&this->mysql) << endl;
}
return mysql_store_result(this->connection);
}
MYSQL_ROW PDB::getarray(MYSQL_RES *res)
{
return mysql_fetch_row( res );
}
// example one
MYSQL_RES res = db->query( "SELECT * FROM `table` WHERE 1" );
while( MYSQL_ROW row = db->getarray( res ) )
{
cout << row[0] << endl;
}
If you use MySQL++, you get RAII transaction behavior with Transaction objects:
mysqlpp::Connection con( /* login parameters here */ );
auto query = con.query("UPDATE foo SET bar='qux' WHERE ...");
mysqlpp::Transaction trans(con);
if (auto res = query.execute()) {
// query succeeded; optionally use res
trans.commit(); // commit DB changes
}
// else, commit() not called, so changes roll back when
// 'trans' goes out of scope, possibly by stack unwinding
// due to a thrown exception.
You could always just run START TRANSACTION / COMMIT / ... manually.
Another way would be to create a wrapper class which runs START TRANSACTION in the constructor, provides commit/rollback functions and, depending on your use case, does a rollback upon destruction.