I'm trying to create a command based spotify client running on ubuntu/debian. But, I keep on getting in to a problem when trying to login.
The code:
int main() {
sp_session *sp;
sp_error err;
sp_session_callbacks callbacks;
sp_session_config config;
config.api_version = 10;
config.cache_location = "tmp";
config.settings_location = "tmp";
config.application_key = g_appkey;
config.application_key_size = g_appkey_size;
config.user_agent = "name";
config.callbacks = NULL;
err = sp_session_create(&config, &sp);
if (SP_ERROR_OK != err) {
fprintf(stderr, "Unable to create session: %s\n",
sp_error_message(err));
exit(1);
}
return 0;
}
And i get this:
"Unable to create session: Unable to open trace file"
Its error code 26.
Do anyone know what this error message means? Having a hard time finding a good answer for this.
Thx
Credentials are not put in before the call to sp_session_login() and the callback returned when that completes will tell you if the user entered bad credentials through an error code.
Also, in general libspotify will like it better if you provide zero for all unused fields in structs, like so:
memset(&config, 0, sizeof(sp_session_config));
// here goes setup of config struct
That said, sp_session_create() should never block and is not asynchronous.
The file paths (cache and settings) need to be absolute paths to a writable place on disk. Try replacing "tmp" with something like "/tmp/libSpotify" - make sure /tmp/libSpotify or whatever actually exists first.
try adding config.tracefile = NULL;
Related
Im trying to create a multithreaded namedpipe server as outlined in the msdn sample here https://learn.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server but Im trying to restrict the namedpipe to access by adminstrators group members only.
The example works correctly when no SECURITY_ATTRIBUTES structure is specified but when an SA is specified the first call is successful, but following calls to CreateNamedPipe fail as long as the first pipe is listening or communicating with a client. The create call fails, usually with ACCESS_DENIED, but sometimes with error 1305 The revision level is unknown. When the first pipe closes due to client disconnecting the following call will be successful for the next createnamedpipe call but will in turn fail once that pipe has a client.
I have tried multiple values for the grfInheritance field with no avail. This is my first adventure into explicitly specifying SECURITY so forgive me if I have missed something obvious. Note that in the Function that calls createnamedpipe I create a new SA structure with each create attempt but I have also tried creating one and sharing it outside the create loop.
Relevant code follows:
function that creates the pipe:
HRESULT DapiSettingsSvr::DapiSettingsListener()
{
while(m_run)
{
//find an unused control array member. If they are all used we have max connection so dont create a pipe.
UINT connectId = 0;
for (connectId; connectId < MAX_CONNECTIONS; connectId++)
{
if (m_controlArray[connectId].inuse == false)
break;
}
SECURITY_ATTRIBUTES sa;
HRESULT hr = InitializeSecurity(&sa);
if (FAILED(hr))
{
return hr;
}
if (connectId < MAX_CONNECTIONS)
{
HANDLE hpipe;
hpipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_BYTE | // byte bipe
PIPE_READMODE_BYTE | // read as bytes
PIPE_WAIT | // do not return until data is recieved
PIPE_REJECT_REMOTE_CLIENTS, // no remote connections
MAX_CONNECTIONS, // max. instances
OUTPUT_BUFFER_SIZE, // output buffer size
INPUT_BUFFER_SIZE, // input buffer size
0, // client time-out
&sa); // default security attribute
// CleanUpSecurityResources();
if (hpipe == INVALID_HANDLE_VALUE)
{
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"CreateNamedPipe failed, GLE=%d.\n", GetLastError());
DapiSettingLogger(logbuffer);
}
else
{
m_controlArray[connectId].inuse = true;
m_controlArray[connectId].pThis = this;
m_controlArray[connectId].connectId = connectId;
m_controlArray[connectId].pipehandle = hpipe;
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"\nPipe Server: Main thread awaiting client connection on %s\n", lpszPipename);
DapiSettingLogger(logbuffer);
// block until a client tries to connect.success is non zero. However a client can connect between the create call and ConnectNamedPipe call.
// In this case ConnectNamedPipe returns zero but GLE = ERROR_PIPE_CONNECTED and a valid connection exists. Check for this case.
fConnected = ConnectNamedPipe(hpipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
// Create a thread for this client.
m_controlArray[connectId].threadHandle = CreateThread(
NULL, // no security attribute
0, // default stack size
WorkerInstance, // thread proc
(LPVOID)&m_controlArray[connectId], // thread parameter
0, // not suspended
&m_controlArray[connectId].threadId); // returns thread ID
if (m_controlArray[connectId].threadHandle == NULL)
{
swprintf_s(logbuffer, ARRAYSIZE(logbuffer), L"CreateThread failed, GLE=%d.\n", GetLastError());
DapiSettingLogger(logbuffer);
CloseHandle(m_controlArray[connectId].pipehandle);
ZeroMemory(&m_controlArray[connectId], sizeof(WORKER_INFO));
}
}
else
{
// The client could not connect, so close the pipe.
CloseHandle(m_controlArray[connectId].pipehandle);
ZeroMemory(&m_controlArray[connectId], sizeof(WORKER_INFO));
}
} //else valid connection
}
else
{
DapiSettingLogger((LPWSTR) L"Max Connections reached\n");
}
}
return S_OK;
}
Function that creates the SA
HRESULT DapiSettingsSvr::InitializeSecurity(SECURITY_ATTRIBUTES* psa)
{
HRESULT result = S_OK;
DWORD res, error;
EXPLICIT_ACCESS ea[1];
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
// Create a SID for the BUILTIN\Administrators group.
if (!AllocateAndInitializeSid(&SIDAuthNT, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&m_pAdminSID))
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"AllocateAndInitializeSid Error %u\n", error);
DapiSettingLogger(logbuffer);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
ea[0].grfAccessPermissions = GENERIC_ALL;
ea[0].grfAccessMode = GRANT_ACCESS;
ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; //changing
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)m_pAdminSID;
// Create a new ACL that contains the new ACE.
res = SetEntriesInAcl(1, ea, NULL, &m_pACL);
if (ERROR_SUCCESS != res)
{
swprintf(logbuffer, ARRAYSIZE(logbuffer),L"SetEntriesInAcl Error %u\n", res);
DapiSettingLogger(logbuffer);
result = HRESULT_FROM_WIN32(res);
goto Cleanup;
}
// Initialize a descriptor Use localalloc as it allows memory moving without changing handle value
m_pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == m_pSD)
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"LocalAlloc Error %u\n", error);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
if (!InitializeSecurityDescriptor(m_pSD,
SECURITY_DESCRIPTOR_REVISION))
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"InitializeSecurityDescriptor Error %u\n", error);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(m_pSD,
TRUE, // bDaclPresent flag
m_pACL,
FALSE)) // not a default DACL
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"SetSecurityDescriptorDacl Error %u\n", error);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
Cleanup:
if (FAILED(result))
{
CleanUpSecurityResources();
}
else
{
// Initialize a security attributes structure.
psa->nLength = sizeof(SECURITY_ATTRIBUTES);
psa->lpSecurityDescriptor = m_pSD;
psa->bInheritHandle = TRUE; /// NOTE I have toyed with this value also
}
return result;
}
Any input on what Im doing incorrectly would be greatly appriciated!!
Thanks!
According to Named Pipe Security and Access Rights,
In addition to the requested access rights, the DACL must allow the
calling thread FILE_CREATE_PIPE_INSTANCE access to the named pipe.
Ok, I figured this out. Im going to mark YangXiaoPo's answer as correct as this pointed me in the right direction but for clarification GENERIC_ALL already includes the right to FILE_CREATE_PIPE_INSTANCE or at least thats what my testing indcates. So setting the EXPICIT_ACCESS structure field to ea[0].grfAccessPermissions = GENERIC_ALL | FILE_CREATE_PIPE_INSTANCE; does not resolve this issue.
The answer lies in the fact that I was running the PipeServer program from within visual studio ( debug ) and thus as a generic user. So the first time through the loop a pipe gets created and the SA with the local administrators group ACE is then applied to the pipe.
So we get a pipe created in the listening state. As soon as a client connects the working thread is created and then the the while(m_run) loop does another iteration and tries to create a new pipe instance. This attempt fails ( actually a looping fail ) because the security attribute with the administrators only ACL is now looked at and the program is not running as an administrator. As soon as the first client disconnects the working thread closes the pipe handle ( effectively destroying the pipe ) and then in the next iteration a pipe is again created.
Running the program as Administrator ( or starting Visual studio as Admin and then debugging ) resolves the issue, though I think a fully correct solution would be to create a second ACE that specified Creator Owner in addition to Admin for the SA DACL.
Thanks!!
I know that this question was asked by many other people, but my case has one important difference. I can't just open file handle with write option because I want to check if I can write in this file without elevated token.
For example, user can run my installer as administrator so I can write in almost all of folders, but after installation my program won't work.
I thought that I can just get the token of my process, disable all privileges and apply it to new thread. I did it but it doesn't work.
I don't want to include code that I wrote because there are a lot of insignificant stuff. Instead, I'll just describe order of functions that I use.
GetCurrentProcess
OpenProcessToken
DuplicateTokenEx - somebody told me that it removes the elevation
AdjustTokenPrivileges - I call it with DisableAllPriveleges = true
CreateThread - Suspend = true
SetThreadToken
CreateFile
I can still write to all folders. What am I doing wrong?
for create not elevated token from your existing token we can use CreateRestrictedToken function with LUA_TOKEN flag. this by fact what is UAC doing when create restricted version of an existing access token on interactive logon. and then we can do access via this token. also note that we not need use new thread - we can temporary impersonate current thread with this lua token and then revert back.
so code can look like:
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
ULONG CheckFileWriteAccess(PCWSTR FileName, ULONG& dwFileError)
{
HANDLE hToken, hLuaToken;
ULONG dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &hToken));
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(CreateRestrictedToken(hToken, LUA_TOKEN, 0, 0, 0, 0, 0, 0, &hLuaToken));
CloseHandle(hToken);
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(DuplicateToken(hLuaToken, ::SecurityImpersonation, &hToken));
CloseHandle(hLuaToken);
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(SetThreadToken(0, hToken));
CloseHandle(hToken);
if (dwError == NOERROR)
{
HANDLE hFile = CreateFileW(FileName, FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
dwFileError = NOERROR;
}
else
{
dwFileError = GetLastError();
NTSTATUS status = RtlGetLastNtStatus();
if (RtlNtStatusToDosError(status) == dwFileError)
{
dwFileError = HRESULT_FROM_NT(status);
}
}
SetThreadToken(0, 0);
}
}
}
}
return dwError;
}
note also snippet
dwFileError = GetLastError();
NTSTATUS status = RtlGetLastNtStatus();
if (RtlNtStatusToDosError(status) == dwFileError)
{
dwFileError = HRESULT_FROM_NT(status);
}
win32 error returned from CreateFileW api - frequently confused, because many different (by sense) NTSTATUS errors mapped to single win32 error. so always better check RtlGetLastNtStatus() instead GetLastError(). even more better of course use NtOpenFile (it documented, user mode, supported, will be not altered or removed) which direct return actual NTSTATUS.
note also that potential you can got error STATUS_SHARING_VIOLATION too. more releable open file with READ_CONTROL only access (this never give sharing violation) query it security descriptor and than use AccessCheck with LUA token, but this require more complex code
I'm currently doing a FTP download using MFC. Is a very simple program which takes 2 inputs from user and click a download button in order to download from server. Everything is fine and im able to download it from. But i realized this program can only be executed once. Either successful or fail user has to open the .exe again to download another file. I'm a beginner in C&C++ with a simple knowledge i put OnInitDialog() at the last line of the download function hopping it will loop back and initialize again. Of course it doesn't work. Below are my current codes for the download button
BOOL CFTPDOWNLOADDlg::Log_In(char* path, char* ID, char* password {
m_pFtpConnection = NULL;
try{
// path
// ID
// password
m_pFtpConnection = m_Session.GetFtpConnection(path,
ID,password,INTERNET_INVALID_PORT_NUMBER);
}
catch(CInternetException *pEx){
pEx->ReportError(MB_ICONEXCLAMATION);
m_pFtpConnection = NULL;
pEx->Delete();
return FALSE;
}
return TRUE;
}
BOOL CFTPDOWNLOADDlg::Download(){
m_Edit3.SetWindowText("Downloading..");
m_Session.EnableStatusCallback(TRUE);
if(m_pFtpConnection->GetFile(serv_Loc,host_Loc,
FALSE,FILE_ATTRIBUTE_NORMAL,FTP_TRANSFER_TYPE_BINARY,1) != 0){
MessageBox("Download Complete");
m_Edit3.SetWindowText("");}
else{
MessageBox("Download Fail");
return FALSE;
}
// Log_out Session
m_Session.Close();
m_pFtpConnection->Close();
if(m_pFtpConnection!=NULL) delete m_pFtpConnection;
else MessageBox("Download Complete");
return TRUE;
}
BOOL CFTPDOWNLOADDlg::get_Path(){
...
...
...
sprintf(serv_Loc,"soft\\%s\\%d\\%s.zip",s_No,r_Number,r_No);
sprintf(host_Loc,"%s\\%s.zip",buff2,r_No);
return TRUE;
}
void CFTPDOWNLOADDlg::OnCancel() {
// Log_out Session
m_Session.Close();
m_pFtpConnection->Close();
if(m_pFtpConnection!=NULL)
delete m_pFtpConnection;
CDialog::OnCancel();
}
void CFTPDOWNLOADDlg::OnDLButton() {
//get path from user input
get_Path();
// start download
Download();
}
I've tried to search online, i couldn't find anything which is close. Sorry for my poor explanation.
Thank you in advance for your kindness in replying
Here is what you need to do:
You should make CInternetSession m_Session; a member of your CWinApp-derived class.
You should call m_Session.Close() in ExitInstance() method of your CWinApp-derived class.
In your CDialog-derived class you should only deal with CFtpConnection related stuff. So when user clicks on Download button you should call GetFtpConnection() and initialize your m_pFtpConnection and do the rest. When download/upload is done call m_pFtpConnection->Close(); and delete m_pFtpConnection;
Please also use CString instead of char*. There are lots of benefits like automatic UNICODE support, etc.
Please also consider using CString::Format() method instead of sprintf().
You should also consider using threads to perform upload/download tasks in a separate worker thread. Use AfxBeginThread() to start the thread. This way you'll not affect Windows message pump that is a part of main application (GUI) thread. So your GUI wont lock up while you uploading/downloading files.
I'm currently creating a network application that uses the usrsctp library on windows and I'm having an odd problem with parameters appearing as null when they shouldn't be on a callback function. I'm not sure if this is a specific usrsctp issue or something I'm doing wrong so I wanted to check here first.
When creating a new sctp socket you pass a function as one of the parameters that you want to be called when data is received as shown in the code below
static int receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
{
if (data == NULL) {
printf("receive_cb - Data NULL, closing socket...\n");
done = 1;
usrsctp_close(sock);
}
else {
_write(_fileno(stdout), data, datalen);
free(data);
}
return (1);
}
...
//Create SCTP socket
if ((sctpsock = usrsctp_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, NULL)) == NULL) {
perror("usrsctp_socket");
return -1;
}
Tracing through the library I can see that before the call back is called all the parameters are correct
As soon as I step into it they become null
I've no idea what would cause this, the callback function was taken straight from the official examples so nothing should be wrong there.
Ok, worked out the issue, it seems that the parameter before 'union sctp_sockstore addr' was causing the stack to be pushed by 0x1c and moving the rest of the parameters away from where they should be. I've never come across this issue before but changing the parameter to a pointer fixed it.
I had the same Issue, in my case the reason was a missing define for INET.
Since the size of 'union sctp_sockstore' depends on this define.
So you have to ensure, that you use the same defines as you used when compiling the library.
I am trying to write a listener using the CoreAudio API for when the default audio output is changed (e.g.: a headphone jack is plugged in). I found sample code, although a bit old and using deprecated functions (http://developer.apple.com/mac/library/samplecode/AudioDeviceNotify/Introduction/Intro.html, but it didn't work. Re-wrote the code in the 'correct' way using AudioHardwareAddPropertyListener method, but still it doesn't seem to work. When I plug in a headphone the function that I registered is not triggered. I'm a bit of a loss here... I suspect the problem may lay some where else, but I can't figure out where...
The Listener Registration Code:
OSStatus err = noErr;
AudioObjectPropertyAddress audioDevicesAddress = { kAudioHardwarePropertyDefaultOutputDevice, KAudioObjectPropertyScopeGlobal, KAudioObjectPropertyElementMaster };
err = AudioObjectAddPropertyListener ( KAudioObjectAudioSystemObject, &AudioDevicesAddress, coreaudio_property_listener, NULL);
if (err) trace ("error on AudioObjectAddPropertyListener");
After a search in sourceforge for projects that used the CoreAudio API, I found the rtaudio project, and more importantly these lines:
// This is a largely undocumented but absolutely necessary
// requirement starting with OS-X 10.6. If not called, queries and
// updates to various audio device properties are not handled
// correctly.
CFRunLoopRef theRunLoop = NULL;
AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
if ( result != noErr ) {
errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";
error( RtError::WARNING );
}
After adding this code I didn't even need to register a listener myself.
Try CFRunLoopRun() - it has the same effect. i.e. making sure the event loop that is calling your listener is running.