Server Fails on Openssl Initialization - c++

I am working on a win32 file server that was coded using Visual Studio 6.0. It had SSL configured and working back in 2000, but hasn't been used since.
Now, we want to use SSL (Opensll), so I've updated the libraries, etc and have the server working with SSLv3 and TLS when the server is run as a console app.
As soon as I run the server as a windows service, the ssl initialization routine crashes without any error messages. Here is the code that is causing all of the grief.
int SwiftSSL::Initialize()
{
SSLeay_add_ssl_algorithms();
SSL_load_error_strings();
ctx_ = SSL_CTX_new( SSLv23_server_method() );
if(!ctx_) {
LogEvent( "SSL_CTX is bad.");
return false;
}
LogEvent( "Before using cert and private key file.");
if ( SSL_CTX_use_certificate_file( ctx_, CERT_FILE, SSL_FILETYPE_PEM ) == 1 ) {
LogEvent( "SUCCESS SSL_CTX_use_certificate_file." );
}
else {
LogEvent( "FAILED SSL_CTX_use_certificate_file." );
return false;
}
if ( SSL_CTX_use_PrivateKey_file( ctx_, KEY_FILE, SSL_FILETYPE_PEM ) == 0 ) {
LogEvent( "Failed SSL_CTX_use_PrivateKey_file." );
return false;
}
else {
LogEvent( "SUCCESSFUL SSL_CTX_use_PrivateKey_file." );
}
if ( SSL_CTX_check_private_key( ctx_ ) == 0 ) {
ERR_print_errors_fp( stderr );
LogEvent( "Failed SSL_CTX_check_private_key" );
return false;
}
LogEvent( "Successfully used cert and private key file.");
return true;
}
When run as a Windows Service, the only message logged is:
"Before using cert and private key file."
Nothing else is logged. That, to me, means that the command
SSL_CTX_use_certificate_file( ctx_, CERT_FILE, SSL_FILETYPE_PEM ) is crashing.
But why would it work with no issues when the same program is run as a console?
This is the information that I found in event viewer:
The description for Event ID ( 0 ) in Source ( OPENSSL ) cannot be found. The
local computer may not have the necessary registry information or message DLL
files to display messages from a remote computer. The following information is
part of the event: OPENSSL_Uplink(00341000,08): no OPENSSL_Applink
Any help will be appreciated.

Ok. I woke up this morning with the solution to this situation. As it turns out, the Windows Service did not know where to find the CERT_FILE or the KEY_FILE. Apps running as a Windows Service will look for files in the %WinDir%\System32 directory. I have the files in the app directory, so I simply had to add the actual path to the files when calling SSL_CTX_use_certificate_file and SSL_CTX_use_PrivateKey_file.
It now works fine.

Related

QSerialPort only reads correctly after second open

I have a program that uses serial input. It's installed on quite a few machines with both Win7 and Win10. On some machines I have the strange issue that when opening the serial port at first it reads strange/incorrect values, mostly 0xff. When I close the port and reopen it, it works correctly.
m_port = new QSerialPort( info ); // some info from QSerialPortInfo::availablePorts();
if( m_port->open( QIODevice::ReadOnly ) )
{
m_port->setBaudRate( m_baudRate );
m_port->setDataBits( m_dataBits );
m_port->setParity( m_parity );
m_port->setStopBits( m_stopBits );
m_port->setFlowControl( QSerialPort::FlowControl::HardwareControl );
m_port->clear();
}
}
So am I just lucky that it works on like 90% of my installations and it's missing some explicit setting or might it be a bug in Qt? (5.6.0 msvc 2013)
Most likely what the problem here is that you're setting the settings on the serial port after you have opened it. Therefore, there's a small period of time where your settings could be in an odd state. It works the second time you open the port because the settings have been correctly set from the first time you opened the port.
QSerialPort will apply the serial port settings when open is called.
m_port = new QSerialPort( info ); // some info from QSerialPortInfo::availablePorts();
m_port->setBaudRate( m_baudRate );
m_port->setDataBits( m_dataBits );
m_port->setParity( m_parity );
m_port->setStopBits( m_stopBits );
m_port->setFlowControl( QSerialPort::FlowControl::HardwareControl );
if( m_port->open( QIODevice::ReadOnly ) )
{
m_port->clear();
}

Deezer native API under linux: Unanble to create simple app

I tried to create simple app which will connect to deezer and play single song. I got access token and wrote this program.
Target machine: linux x86_64
API version: v1.0.1
#include <iostream>
#include <deezer-api.h>
#include <deezer-player.h>
#define ACCESS_TOKEN "ACCESS TOKEN HERE"
int main(int argc, char **argv)
{
dz_connect_configuration cfg = {0};
cfg.app_id = "APP ID HERE";
cfg.product_id = "product_id";
cfg.product_build_id = "0.0.0";
dz_connect_handle dz_handle = dz_connect_new(&cfg);
if (dz_handle == nullptr)
{
return 100;
}
auto err_code = dz_connect_activate(dz_handle, nullptr);
if (err_code > DZ_ERROR_NO_ERROR_ASYNC)
{
return err_code;
}
err_code = dz_connect_set_access_token(dz_handle, nullptr, nullptr, ACCESS_TOKEN);
if (err_code > DZ_ERROR_NO_ERROR_ASYNC)
{
return err_code;
}
auto dz_player_handle = dz_player_new(dz_handle);
if (dz_player_handle == nullptr)
{
return 200;
}
err_code = dz_player_activate(dz_player_handle, nullptr);
if (err_code > DZ_ERROR_NO_ERROR_ASYNC)
{
return err_code;
}
err_code = dz_player_load(dz_player_handle, nullptr, nullptr, "dzmedia:///track/3135556");
if (err_code > DZ_ERROR_NO_ERROR_ASYNC)
{
return err_code;
}
err_code = dz_player_play(dz_player_handle, nullptr, nullptr, DZ_PLAYER_PLAY_CMD_START_TRACKLIST, DZ_TRACKLIST_AUTOPLAY_MANUAL, DZ_INDEX_IN_PLAYLIST_CURRENT);
if (err_code > DZ_ERROR_NO_ERROR_ASYNC)
{
return err_code;
}
std::cin.get();
return 0;
}
Suddenly i ran into problems.
First run shows me this output:
398748:201417 dz_bufferevent: [dz_bufferevent_on_activation:561] could not open /var/tmp/settings.dat
I created this file, but I suspect that it shouldn't be empty.
After second run with /var/tmp/settings.dat created i got this output:
399206:328658 dz_crash_handler: [dz_crash_handler_init:284] Crash Handler available
399206:329404 dzcrashreport-server-disk: [dz_crashreport_server_url_on_read_data:436] ERROR - Open failure err: 7
399206:329533 dzcrashreport-server-disk: [dz_crashreport_server_url_on_read_data:436] ERROR - Open failure err: 7
399206:329590 dzcrashreport-server-disk: [dz_crashreport_server_url_on_read_data:436] ERROR - Open failure err: 7
399206:329664 dzcrashreport-server-disk: [dz_crashreport_server_url_on_read_data:436] ERROR - Open failure err: 7
399206:329726 dzcrashreport-server-disk: [dz_crashreport_server_url_on_read_data:436] ERROR - Open failure err: 7
399206:329736 dzcrashreport-sender: [dz_crash_report_sender_retrieve_server_url_on_result:213] Error - couldn't read URL server err:0
399206:336505 pulseaudio-engine: [dz_audioengine_set_output_gain:1184] not init
399206:336520 pulseaudio-engine: [dz_audioengine_set_output_gain:1184] not init
399206:336577 player: [dz_player_play_licence:1756] unknown error 131079
I can't understand, what i did wrong?
UPDATE:
Deezer Native API: v1.0.1-v00349200
Still no luck. Tried different variations of "user_profile_path":
.
./
./user - was created in working dir with 777 rights
/var/tmp
There were no files in the folder created by API.
Still got errors:
[dz_crashreport_server_url_on_read_data:436] ERROR - Open failure err: 7
[dz_crash_report_sender_retrieve_server_url_on_result:213] Error - couldn't read URL server err:0
After adding implementation of callbacks i see this:
dz_connect_set_access_token calls callback dz_activity_operation_callback with status DZ_ERROR_CONNECT_SESSION_OFFLINE_MODE
dz_player_play calls callback dz_player_onevent_cb with event DZ_PLAYER_EVENT_PLAYLIST_TRACK_NO_RIGHT
Well, i checked that i have rights to play this track.
the "could not open" message is just informative.
The file will be automatically created (or updated if detected corrupted).
The issue seems more linked to the dz_connect_configuration, you have to set the "user_profile_path" to a valid path. This is where user temporary files will be stored.
Regards,
Cyril
UPDATE:
Few tips that could also help:
My mistake, one call seems missing:
dz_connect_cache_path_set(dz_handle, NULL, NULL, <user_profile_path>);
The DZ_INDEX_IN_PLAYLIST_CURRENT must be replaced by 0. I do agree this one is not obvious...
Check that the access_token you have created has the offline_access enable when calling https://connect.deezer.com/oauth/auth.php?app_id=YOUR_APP_ID&redirect_uri=YOUR_REDIRECT_URI&perms=basic_access,email,offline_access (cf: http://developers.deezer.com/api/oauth and http://developers.deezer.com/api/permissions)
UPDATE 2:
Since my last answer I have released a sample code on Github:
https://github.com/deezer/native-sdk-samples
I suggest that you have a quick look :)
What I have noticed in your full code you sent me in private is that:
You are not calling dz_connect_offline_mode(...,false); It will actually trigger the login process of the Native SDK.
You are not waiting the DZ_CONNECT_EVENT_USER_LOGIN_OK to load and play the track.
Best regards,
Cyril

Using pipes in Boost unit tests

I'm trying to write Boost unit tests for my server.
I want to launch my server - start() launches the server in a thread - open a client, connect it and try to download a file.
I'm doing this this way:
tftp_server* my_test_server;
BOOST_AUTO_TEST_SUITE (tftptest) // name of the test suite is tftptest
BOOST_AUTO_TEST_CASE (test1)
{
my_test_server = new tftp_server(69);
my_test_server->start();
FILE *in;
char buff[512];
if(!(in = popen("tftp", "w"))){
exit(1);
}
fputs ( "connect xx.xx.xx.xx\n", in );
fputs ( "mode binary\n", in );
fputs ( "mode\n", in );
fputs ( "get truc.txt\n", in );
while(fgets(buff, sizeof(buff), in)!=NULL)
printf("%s", buff);
sleep(10);
BOOST_CHECK(true);
}
1) Creating and launching the server,
2) using the system TFTP client (I'm on OSX),
3) waiting 10 seconds.
It doesn't work : It only executes the client after the test is done.
Running 1 test case...
Server started on port 69
Server running.
*** No errors detected
$ Using octet mode to transfer files.
Transfer timed out.
Any idea how I could solve my problem ?
Thanks !
EDIT
void tftp_server::start()
{
LOG_INFO("Server running.", 0);
boost::thread bt(boost::bind(&boost::asio::io_service::run, &_io_service));
}
I've added close, and it works.
Thanks to Arne Mertz.
if(!(in = popen("tftp", "w"))){
exit(1);
}
//...
while(fgets(buff, sizeof(buff), in)!=NULL)
printf("%s", buff);
pclose(in);

exec functions not working from linux daemon

I have been writing a linux daemon which listens on TCP/IP for a request and launches an application on receiving that request. My problem is when I run this daemon from command prompt or IDE (eclipse 3.7) everything works fine and my executable launches. But when i use
sudo service <myservicename> start
It will receive request on socket but its not launching that executable.
here is the standard code I am using for daemonizing the process
/// Linux Daemon related stuff
/// Create the lock file as the current user
int lfp = open( "/var/lock/subsys/LauncherService", O_RDWR|O_CREAT, 0640);
if ( lfp < 0 )
{
LOG_ERROR ("Unable to open lockfile");
LOG_ERROR ( strerror(errno) );
}
/// All
/// Our process ID and Session ID
pid_t pid, sid;
/// Fork off the parent process
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/// If we got a good PID, then
/// we can exit the parent process.
if (pid > 0)
{
exit(EXIT_SUCCESS);
}
/// Change the file mode mask
umask(0);
/// Create a new SID for the child process
sid = setsid();
if (sid < 0)
{
LOG_ERROR ("Error Setting sid");
exit(EXIT_FAILURE);
}
LOG_INFO ("sid set");
/// Change the current working directory
if ( (chdir("/usr/local/<mylocaldir>/bin")) < 0 )
{
LOG_ERROR ("Error changing Directory");
exit(EXIT_FAILURE);
}
LOG_INFO ("chdir successful");
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
here is function in which i am launching my binary which needs to be launched. This function is called in forked child process.
std::string configFile = "/usr/local/<mydir>/config/Settings.config";
std::string binary = "<binaryname>";
std::string path ="/usr/local/<mydir>/bin/<binaryname>";
//char *argv[] = { "<binaryname>", "/usr/local/<mydir>/config/Settings.config", (char *)0 };
LOG_INFO("Calling Process" );
if ( execlp( path.c_str(), binary.c_str(), configFile.c_str(), (char *)0 ) == -1 )
//if ( execv("/usr/local/<mydir>/bin/<binaryname>", argv) == -1 )
//if ( execvp("/usr/local/<mydir>/bin/<binaryname>", argv) == -1 )
{
LOG_ERROR("System call failed !!")
std::string errString = strerror(errno);
LOG_ERROR (errString );
}
else
{
LOG_INFO("System call successful");
}
So after discussion with Casey I investigated more into my called program and I found that my program indeed is getting called. Also I found out that environment variables are not the issue child process is taking environment from parent itself. I am creating QApplication (qt gui application) in my main program. Its some issue with that and linux system daemon. I will try to figure that out and will ask separate question if needed.
Edit: Final Solution
It was a qt GUI application which was not able to connect to XServer. I had to changes suggested by Casey and given in this post
Cannot connect to X server :0.0 with a Qt application
after that it started launching.

Printing Raw Data in Terminal Server

Here is the scenario:
I have a Windows Server 2008 with Terminal Server (No Domain Controller, No join to Domain)
I have a client machine with Windows XP SP3 updated (.NET 3.0 SP1 and .NET 4.0)
I'm Using Embarcadero C++Builder (BCB6)
I have a ticket printer (Thermal Printer, POS Printer, Epson, Zebra, etc.)
When I connect to the terminal server, the printer works OK. I tested printing a test page.
When I use my software to send the raw data in the terminal server on the local computer, I get this error:
Windows Presentation Foundation terminal server print W has encountered a
problem and needs to close. We are sorry for the inconvenience.
I followed the advice from this support page with no luck.
I used to print directly to LPT1:, but with Windows Server 2008 it's getting harder to make this work, so we have to change the way we print to this kind of printer.
Here is the code that I'm using. I tested locally and it works fine, but in the terminal server doesn't work:
bool TForm1::RawDataToPrinter(char* szPrinterName, char* lpData, unsigned int dwCount )
{
int BytesWritten;
HANDLE hPrinter;
TDocInfo1 DocInfo;
bool bStatus = false;
int dwJob = 0;
unsigned long dwBytesWritten = 0;
// Open a handle to the printer.
bStatus = OpenPrinter( szPrinterName, &hPrinter, NULL );
if( bStatus )
{
// Fill in the structure with info about this "document."
DocInfo.pDocName = "My Document";
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = "RAW";
// to indicate that the application will be sending document data to the printer.
dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo );
if ( dwJob > 0 )
{
// Start a page.
bStatus = StartPagePrinter( hPrinter );
bStatus = true;
if( bStatus )
{
// Send the data to the printer.
bStatus = WritePrinter( hPrinter, lpData, dwCount, &dwBytesWritten );
EndPagePrinter ( hPrinter );
}
// Inform the spooler that the document is ending.
EndDocPrinter( hPrinter );
}
// Close the printer handle.
ClosePrinter( hPrinter );
}
// Check to see if correct number of bytes were written.
if (!bStatus || (dwBytesWritten != dwCount))
bStatus = false;
else
bStatus = true;
return bStatus;
}
I copied this code from a example in Microsoft's Support. I also tried changing the "RAW" to "TEXT" but I get the same error.
I tried this code, because it uses the GDI to print:
long pageline;
char prueba[255];
Printer()->SetPrinter(ListBox1->Items->Strings[ListBox1->ItemIndex].c_str(), "WINSPOOL", "", NULL);
Printer()->BeginDoc();
pageline = 0;
while(pageline < Memo1->Lines->Count)
{
Printer()->Canvas->TextOut(10, (10 + Printer()->Canvas->TextHeight("Hi! There")) * pageline, Memo1->Lines->Strings[pageline]);
pageline++;
}
Printer()->EndDoc();
This is a example that I found in the Embarcadero Forum.
I also verified TsWpfWrp.exe. I tried replacing it by the one in the server, but it does nothing, doesn't send the error, but also won't send any data.
There is another way to do this? Do I have something wrong in the code?
I appreciated any help or insight.
I found the problem, is the Easy Print driver, it expect in RAW Mode the XPS specification, but I was sending only text.
I disabled the Easy Print to put the printer in Fallback mode( something like that), this is where the Terminal Server, first it look for the installed driver then for the Easy Print (this can be verified in the properties of the printer in advanced options).
Now it works, thanks.