For a project I am working on, I am trying to use libgit2.
For the moment, I am just trying to create a repo using git_repository_init but it fails with the following error message :
Error: -1/2: Failed to resolve path 'D:/Workspace/<project_name>/test/.git/': Invalid argument
The code is the following :
#include <iostream>
#include "git2.h"
int main(int argc, char *argv[])
{
git_libgit2_init();
git_repository *repo;
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.flags |= GIT_REPOSITORY_INIT_MKDIR;
int err = git_repository_init_ext(&repo, "D:/Workspace/<project_name>/test", &opts);
if(err < 0)
{
const git_error *e = giterr_last();
std::cerr << "Error: " << err << "/" << e->klass << ": " << e->message << std::endl;
}
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}
The .git directory in the test directory is still created but it's empty.
I have tried with relative and absolute path and also Unix and windows path but the result seem to always be the same.
Also, when executing libgit2_clar, a lot of test fail always with the same error : "error -1 - Failed to resolve path 'attr': Invalid argument".
libgit2 and the previous code has been compiled and executed on a Windows XP 32bit using MinGW with gcc 4.8.1.
Windows XP is not supported by libgit2. Support ended in v0.21.0 in 2014:
Top-level Improvements
We've dropped support for Windows XP. We're evil like that.
The repo_path parameter of git_repository_init_ext isn't legal because
it contains the chars '<' '>' .
Try to make new directory with the above chars and you get error message.
Related
I was taking a look at this Github project: https://github.com/LloydLabs/delete-self-poc
This project uses the SetFileInformationByHandle API (https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle) in a somewhat creative way to allow the deletion from disk of a locked file. I am attempting to implement this as part of a larger program, however I have ran into an issue when compiling for x86. I use mingw-w64 on a debian machine to compile my program and when doing compatibility checks for x86, I found a very strange issue.
#include "main.h"
static
HANDLE
ds_open_handle(
PWCHAR pwPath
)
{
return CreateFileW(pwPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
static
BOOL
ds_rename_handle(
HANDLE hHandle
)
{
FILE_RENAME_INFO fRename;
RtlSecureZeroMemory(&fRename, sizeof(fRename));
// set our FileNameLength and FileName to DS_STREAM_RENAME
LPWSTR lpwStream = DS_STREAM_RENAME;
fRename.FileNameLength = sizeof(lpwStream);
RtlCopyMemory(fRename.FileName, lpwStream, sizeof(lpwStream));
return SetFileInformationByHandle(hHandle, FileRenameInfo, &fRename, sizeof(fRename) + sizeof(lpwStream));
}
static
BOOL
ds_deposite_handle(
HANDLE hHandle
)
{
// set FILE_DISPOSITION_INFO::DeleteFile to TRUE
FILE_DISPOSITION_INFO fDelete;
RtlSecureZeroMemory(&fDelete, sizeof(fDelete));
fDelete.DeleteFile = TRUE;
return SetFileInformationByHandle(hHandle, FileDispositionInfo, &fDelete, sizeof(fDelete));
}
int
main(
int argc,
char** argv
)
{
WCHAR wcPath[MAX_PATH + 1];
RtlSecureZeroMemory(wcPath, sizeof(wcPath));
// get the path to the current running process ctx
if (GetModuleFileNameW(NULL, wcPath, MAX_PATH) == 0)
{
DS_DEBUG_LOG(L"failed to get the current module handle");
return 0;
}
HANDLE hCurrent = ds_open_handle(wcPath);
if (hCurrent == INVALID_HANDLE_VALUE)
{
DS_DEBUG_LOG(L"failed to acquire handle to current running process");
return 0;
}
// rename the associated HANDLE's file name
DS_DEBUG_LOG(L"attempting to rename file name");
if (!ds_rename_handle(hCurrent))
{
DS_DEBUG_LOG(L"failed to rename to stream");
return 0;
}
DS_DEBUG_LOG(L"successfully renamed file primary :$DATA ADS to specified stream, closing initial handle");
CloseHandle(hCurrent);
// open another handle, trigger deletion on close
hCurrent = ds_open_handle(wcPath);
if (hCurrent == INVALID_HANDLE_VALUE)
{
DS_DEBUG_LOG(L"failed to reopen current module");
return 0;
}
if (!ds_deposite_handle(hCurrent))
{
DS_DEBUG_LOG(L"failed to set delete deposition");
return 0;
}
// trigger the deletion deposition on hCurrent
DS_DEBUG_LOG(L"closing handle to trigger deletion deposition");
CloseHandle(hCurrent);
// verify we've been deleted
if (PathFileExistsW(wcPath))
{
DS_DEBUG_LOG(L"failed to delete copy, file still exists");
return 0;
}
DS_DEBUG_LOG(L"successfully deleted self from disk");
return 1;
}
When compiling the base code found in the linked repository (and shown above) as x86, attempting to run the program fails at the SetFileInformationByHandle call in the ds_rename_handle function. Calling GetLastError() returns 123:
ERROR_INVALID_NAME
123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
The very bizarre part is that the program succeeds when ran from an Administrator prompt. Even stranger, compiling the same code for x64 works both in a normal and an Administrator prompt.
As a sanity check I copied the code verbatim over to VS2019 and compiled there, and the resulting x86 program was able to run without Administrator privileges.
The only changes to the source code made on the debian system were made in the header file:
#pragma once
#pragma comment(lib, "Shlwapi.lib")
#include <Windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include <stdlib.h>
#define DS_STREAM_RENAME L":wtfbbq"
#define DS_DEBUG_LOG(msg) wprintf(L"[LOG] - %s\n", msg)
Where <Windows.h> was changed to <windows.h> and the DS_DEBUG_LOG line changed to %ls so that the entire log message would print.
The GCC command used to compile for x86 was:
i686-w64-mingw32-gcc main.c -o delete32.exe -s -DUNICODE -Os -lshlwapi
I have tried removing all switches and compiling and it still fails.
As a note, the shlwapi library is only required for the very last call in main(), PathFileExistsW. I have commented out that portion and removed shlwapi from imports and from the gcc command to no effect.
The x64 gcc command which succeeded was:
x86_64-w64-mingw32-gcc main.c -o delete32.exe -s -DUNICODE -Os -lshlwapi
In the issues tab of the github repo there are some mentions of errors in the code which I have looked at separately. However I would desperately like to know why mingw is causing an issue with the 32 bit version of this program. Unfortunately "just compile with VS" isn't an option, as I use a program to generate and compile the program that this bit of code will be part of on my linux machine.
Thanks for any insight.
RtlCopyMemory(fRename.FileName, lpwStream, sizeof(lpwStream)); writes 4 or 8 bytes into a 2 byte buffer! Who knows where the remaining bytes are going, the program behavior is probably undefined.
The concept of deleting a running exe like this might work but the code indicates that the author does not have a full understanding of Windows and C. You are better off rewriting it from scratch...
Edit:
After playing with your uploaded files I can with confidence say that it is the lack of a application manifest that causes it to fail when it is not elevated. Your vc file has a requestedExecutionLevel element which gives it Vista operating system context. If you remove the manifest resource in the vc exe it stops working. If you add a manifest to the mingw exe it starts working.
the ds_rename_handle function is wrong implemented.
the FILE_RENAME_INFO is variable size structure.
as result declaration
FILE_RENAME_INFO fRename;
almost always wrong (it will ok only if FileName containing 1 or 2 symbols)
really we need first calculate FileNameLength and then allocate PFILE_RENAME_INFO based on this
as example:
ULONG FileNameLength = (ULONG)wcslen(DS_STREAM_RENAME) * sizeof(WCHAR);
ULONG dwBufferSize = FIELD_OFFSET(FILE_RENAME_INFO, FileName) + FileNameLength;
PFILE_RENAME_INFORMATION fRename = (PFILE_RENAME_INFORMATION)alloca(dwBufferSize);
so complete code for ds_rename_handle can be next:
ULONG ds_rename_handle(HANDLE hHandle, PCWSTR DS_STREAM_RENAME)
{
ULONG FileNameLength = (ULONG)wcslen(DS_STREAM_RENAME) * sizeof(WCHAR);
ULONG dwBufferSize = FIELD_OFFSET(FILE_RENAME_INFO, FileName) + FileNameLength;
PFILE_RENAME_INFO fRename = (PFILE_RENAME_INFO)alloca(dwBufferSize);
fRename->ReplaceIfExists = TRUE;
fRename->RootDirectory = 0;
fRename->FileNameLength = FileNameLength;
memcpy(fRename->FileName, DS_STREAM_RENAME, FileNameLength);
return SetFileInformationByHandle(hHandle, FileRenameInfo,
fRename, dwBufferSize) ? NOERROR : GetLastError();
}
but documentation of FILE_RENAME_INFO is very bad. unclear - in what form - full pathname, file name or a relative pathname - must be FileName ?!
from my research - it must be full pathname only (not file name) or begin with a colon : ( The new name for the stream )
much more better use NtSetInformationFile with FileRenameInformation
compare description of FILE_RENAME_INFORMATION structure with FILE_RENAME_INFO !
here exist detailed description - in what form FileName it should be.
so i always use
NTSTATUS ds_rename_handle_nt(HANDLE hHandle, PCWSTR DS_STREAM_RENAME)
{
ULONG FileNameLength = (ULONG)wcslen(DS_STREAM_RENAME) * sizeof(WCHAR);
ULONG dwBufferSize = FIELD_OFFSET(FILE_RENAME_INFO, FileName) + FileNameLength;
PFILE_RENAME_INFORMATION fRename = (PFILE_RENAME_INFORMATION)alloca(dwBufferSize);
fRename->ReplaceIfExists = TRUE;
fRename->RootDirectory = 0;
fRename->FileNameLength = FileNameLength;
memcpy(fRename->FileName, DS_STREAM_RENAME, FileNameLength);
IO_STATUS_BLOCK iosb;
return NtSetInformationFile(
hHandle, &iosb, fRename, dwBufferSize, FileRenameInformation);
}
I want to try some C libraries that are only available in windows so i installed wine and install dev C++.
Unlike on windows, after i compile and run, it successfuly generate/compile into "exe" but the cmd is not showing up .
I found a way on how to run the exe by launching the terminal and putting
$wine cmd
$myc.exe
It works but it takes time to manually launch the "exe".
How can i make dev c++ to automatically find cmd in wine and execute the compiled code?
Thank you in advance.
UPDATE :
The time I posted this question, I'm new to Linux/Ubuntu that's why I'm looking/expecting for that functionality in wine. But now after 2 years amany months i figured out that codeblock running on wine which is for windows and cannot call ubuntu terminal once compiled.
Dev-C++, by default, relies on a simple file called ConsolePauser.exe. This file calls the compiled .exe file, and gives the familiar Process exited after 0.xxxxx seconds with return value x. notice after it exits.
However, ConsolePauser.exe is a native Windows binary, it cannot be executed in Ubuntu, unless called by Wine. Also, the ConsolePauser calls the bare name of the executable, instead of a call to Wine, which is required.
Therefore, what you need to do to make Dev-C++ to run .exe files automatically after you press F9 is to build your OWN ConsolePauser. This is quite simple, actually:
#include <chrono>
#include <iostream>
#include <string>
int main(int agrc, char ** argv)
{
using namespace std;
string s = argv[1];
string s1;
for (const auto & ss : s)
{
if ((ss == ' ') || (ss == '\\')) s1.push_back('\\');
s1.push_back(ss);
}
s = "wine " + s1;
auto begin = chrono::high_resolution_clock::now();
auto retVal = system(s.c_str());
auto end = chrono::high_resolution_clock::now();
cout << "-------------------------------------" << endl;
cout << "Process completed after " << chrono::duration_cast<chrono::milliseconds>(end - begin).count();
cout << " milliseconds with return value " << retVal << "." << endl;
cout << "Press any key to continue. . ." << endl;
cin.get();
return 0;
}
What it simply does is parsing the argument, escaping required characters, and pass it to Wine. It is a quick and dirty version, you start improving it by checking if argc == 1.
Compile it as ConsolePauser.exe with Ubuntu's compiler, put it anywhere in your computer's PATH and it should work.
Another problem exists, however. For unknown reasons, Ubuntu's executables don't get executed in a separate window, if called by an app like Dev-C++, unlike Windows. Therefore, you will have to find a way to bring the ConsolePauser.exe to a new window.
A simple approach is rename your file to ConsolePauser1.exe, and use this code for ConsolePauser.exe:
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char ** argv)
{
string s = argv[1];
//Opens new window through gnome-terminal:
string command = "gnome-terminal -e ";
command += string("\"") + "bash -c ";
command += string("\\\"") + "ConsolePauser1.exe ";
command += string("\\\\\\\"") + s;
command += string("\\\\\\\"");
command += string("\\\"");
command += string("\"");
system(command.c_str());
cerr << command << endl;
//Make sure that window lingers...
system("exec bash");
return 0;
}
Put these two files in the same folder in your PATH, and the familiar old Console Pauser will work like a charm.
I'd like to submit my approach, although it is not specific to Ubuntu. It can work with any distro with xterm installed.
Rename ConsolePauser.exe to ConsolePauserEngine.exe and create a new ConsolePauser.exe text file in the same dir with the following lines:
#! /bin/sh
CMD=$(printf "%q" $#) #https://stackoverflow.com/questions/2854655/command-to-escape-a-string-in-bash#answer-2856010
CONSOLE_PAUSER_PATH=$(printf "%q" "C:\Program Files (x86)\Dev-Cpp\ConsolePauserEngine.exe")
xterm -e "wine $CONSOLE_PAUSER_PATH $CMD"
EDIT: Don't forget to make the new ConsolePauser.exe executable.
I am building APT for macOS, I already did most of patches and added some compatibility headers I ported from Linux to macOS all, but I have been encountering the problem at the "15%" of the make process telling me:
use of undeclared identifier 'GetSrvRecords'
I have tried commenting that lines but it ends up in an error that is worse
static bool DoSrvLookup(CommandLine &CmdL) /*{{{*/
{
if (CmdL.FileSize() <= 1)
return _error->Error("Must specify at least one SRV record");
for(size_t i = 1; CmdL.FileList[i] != NULL; ++i)
{
std::vector<SrvRec> srv_records;
std::string const name = CmdL.FileList[i];
c0out << "# Target\tPriority\tWeight\tPort # for " << name << std::endl;
size_t const found = name.find(":");
if (found != std::string::npos)
{
std::string const host = name.substr(0, found);
size_t const port = atoi(name.c_str() + found + 1);
if(GetSrvRecords(host, port, srv_records) == false)
_error->Error(_("GetSrvRec failed for %s"), name.c_str());
}
else if(GetSrvRecords(name, srv_records) == false)
_error->Error(_("GetSrvRec failed for %s"), name.c_str());
for (SrvRec const &I : srv_records)
ioprintf(c1out, "%s\t%d\t%d\t%d\n", I.target.c_str(), I.priority, I.weight, I.port);
}
return true;
}
It should make without showing that problem, at all.
You are either:
Not importing the header file that includes GetSrvRecords class.
Not defining the GetSrvRecords class somewhere and then not importing it.
Not importing it correctly.
You never defined GetSrvRecords()
I'm struggling with creating a window with the GLFW 3 function, glfwCreateWindow.
I have set an error callback function, that pretty much just prints out the error number and description, and according to that the GLFW library have not been initialized, even though the glfwInit function just returned success?
Here's an outtake from my code
// Error callback function prints out any errors from GFLW to the console
static void error_callback( int error, const char *description )
{
cout << error << '\t' << description << endl;
}
bool Base::Init()
{
// Set error callback
/*!
* According to the documentation this can be use before glfwInit,
* and removing won't change anything anyway
*/
glfwSetErrorCallback( error_callback );
// Initialize GLFW
/*!
* This return succesfull, but...
*/
if( !glfwInit() )
{
cout << "INITIALIZER: Failed to initialize GLFW!" << endl;
return false;
}
else
{
cout << "INITIALIZER: GLFW Initialized successfully!" << endl;
}
// Create window
/*!
* When this is called, or any other glfw functions, I get a
* "65537 The GLFW library is not initialized" in the console, through
* the error_callback function
*/
window = glfwCreateWindow( 800,
600,
"GLFW Window",
NULL,
NULL );
if( !window )
{
cout << "INITIALIZER: Failed to create window!" << endl;
glfwTerminate();
return false;
}
// Set window to current context
glfwMakeContextCurrent( window );
...
return true;
}
And here's what's printed out in the console
INITIALIZER: GLFW Initialized succesfully!
65537 The GLFW library is not initialized
INITIALIZER: Failed to create window!
I think I'm getting the error because of the setup isn't entirely correct, but I've done the best I can with what I could find around the place
I downloaded the windows 32 from glfw.org and stuck the 2 includes files from it into minGW/include/GLFW, the 2 .a files (from the lib-mingw folder) into minGW/lib and the dll, also from the lib-mingw folder, into Windows/System32
In code::blocks I have, from build options -> linker settings, linked the 2 .a files from the download. I believe I need to link more things, but I can figure out what, or where I should get those things from.
I tried reinstalling codeblocks and mingw, which solved the issue.
Seems like GLFW3 doesn't like having previous versions installed at the same time for some reason, so if anyone else is having a similar problem, you might want to try that.
I experienced similar problems in Cocos 3.8.1 and 3.10.
I have never installed codeblocks or mingw, so it did not make sense to install them for me.
The GLFW.lib file in the cocos directory is out of date.
http://www.glfw.org/download.html, and replace the lib file in your project with the latest one, and it may resolve your error.
I would like to authenticate users of my C network application with PAM and I have a found a nice PAM example here on Stack, which I attach at the bottom. The problem is that in my development machine I have a fingerprint reader which PAM is set up to use, as in /etc/pam.d/common-auth:
#%PAM-1.0
#
# This file is autogenerated by pam-config. All changes
# will be overwritten.
#
# Authentication-related modules common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
auth required pam_env.so
auth sufficient pam_fprint.so
auth optional pam_gnome_keyring.so
auth required pam_unix2.so
pam_fprint.so is the fingerprint reader plugin. When you normally log in, the scan can fail and you are prompted for a password. However, sshd daemon does not initiate the fingerprint at all and I would like to understand how it skips it, because for example /etc/pam.d/sshd references the common-auth module so it must pull it ..
#%PAM-1.0
auth requisite pam_nologin.so
auth include common-auth
account requisite pam_nologin.so
account include common-account
password include common-password
session required pam_loginuid.so
session include common-session
session optional pam_lastlog.so silent noupdate showfailed
I have tried to reference the 'sshd' scheme from the C program but it still initiates the fingerprint reader. I want to skip the fingerprint reader somehow in C and retain my fingerprint reader default config.
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <security/pam_appl.h>
#include <unistd.h>
// To build this:
// g++ test.cpp -lpam -o test
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;
}
I doubt that sshd is actually skipping that module. Rather, I suspect that the fingerprint reader authentication module (sensibly) is checking whether the authenticating user appears to be on the local system or is coming over the network (which it can figure out from PAM data like rhost) and just silently does nothing if this is a network authentication. You could try looking at the source code to see if it has such a test, or try setting PAM_RHOST via pam_set_item and see if that changes the behavior.
To answer your actual question, I don't believe there is a way to tell PAM to run a particular PAM group except for one module. The expected way to do what you want to do is to create a new configuration file in /etc/pam.d that matches the application name you pass to pam_start that does not include common-auth but instead contains just the modules that you want to run.