Authenticate samba server using Windows API
Samba is an open-source service that runs on Linux/Unix based platforms while having the capability to communicate with Windows OS clients. Samba server offers services like:
In this tutorial, we will discuss about how to implement communication between Qt application and samba server using authentication. We do not go into the depth of setting up or configuring samba servers as it will be beyond the scope of our discussion.
A samba server without authentication is open to communicate with as many clients as possible if set up correctly. But communicating with a samba server with authentication can be challenging. Qt doesn’t have native support to mount network resources and deal with file protocols. So, we will use Windows APIs to get around the authentication issue. Of course, this would violate Qt’s cross-platform ability but this would be useful for anyone developing applications only for Windows platforms.
We will need the WNetAddConnection2A function from the Windows API to make the connection to a network resource as in our case samba server.
We need to set up 3 key components to achieving a successful connection:
Network resource or NETRESOURCE needs attributes to be setup like:
You can read more about NETRESOURCE here.
After setting up our NETRESOURCE we need to call WNetAddConnection2A function to establish a connection to the samba server. WNetAddConnection2A takes in 4 arguments:
WNetAddConnection2A returns with an error code which can be handled as you wish. Below is a sample function showing the creation of NETRESOURCE and add a new connection using WNetAddConnection2A.
#include <windows.h>
#include <Winnetwk.h>
#include <system_error>
#include <iostream>
// Need to link with Netapi32.lib and Mpr.lib
bool ServerConnection::create(const QString& remoteName, const QString& username, const QString& password)
{
DWORD dwRetVal;
NETRESOURCE nr;
DWORD dwFlags;
// assign a drive name
// avoid using commonly used names like C:, D:
LPSTR szLocalName = "Q:";
LPSTR szRemoteName = new TCHAR[remoteName.toStdString().size() + 1]; //define
std::strcpy(szRemoteName, remoteName.toStdString().c_str());
// Zero out the NETRESOURCE struct
memset(&nr, 0, sizeof (NETRESOURCE));
// Assign our values to the NETRESOURCE structure.
nr.dwType = RESOURCETYPE_ANY;
nr.lpLocalName = szLocalName;
nr.lpRemoteName = szRemoteName;
nr.lpProvider = NULL;
// Assign a value to the connection options
// this flag makes sure windows doesn't remember previous connections
dwFlags = CONNECT_TEMPORARY;
// Call the WNetAddConnection2 function to assign
// a drive letter to the share.
dwRetVal = WNetAddConnection2A(&nr, password.toStdString().c_str(), username.toStdString().c_str(), dwFlags);
// get the message string
std::string message = std::system_category().message(dwRetVal);
std::cout << message << std::endl;
// handle error statements
switch (dwRetVal)
{
case NO_ERROR:
case ERROR_ALREADY_ASSIGNED:
case ERROR_DEVICE_ALREADY_REMEMBERED:
return true;
default:
return false;
}
}
This implementation to communicate with samba server using Windows API has dependencies too. To make this work you will need to link your application to 2 different libraries:
These libs are usually found inside *C:\Program Files(x86)\Windows Kits\10*
To be able to communicate with the samba server beyond the authentication wall as a window client can be tricky. Using Windows API we learned how to mount the samba server locally as a network resource using WNetAddConnection2A function.
If this was helpful, please share this blog, and also feel free to add your thoughts or comments below.
Photo by FLY:D on Unsplash