slowcheetah.transformtask task failed unexpectedly.system.unauthorizedaccessexception - visual-studio-2017

Getting following error when using custom json configuration file.
Severity Code Description Project File Line Suppression State
Error The "SlowCheetah.TransformTask" task failed unexpectedly.
System.UnauthorizedAccessException: Access to the path 'D:\Data\…\Settings.Release.json' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at Microsoft.VisualStudio.Jdt.JsonTransformation..ctor(String transformFile, IJsonTransformationLogger logger)
at Microsoft.VisualStudio.SlowCheetah.JsonTransformer.Transform(String sourcePath, String transformPath, String destinationPath)
at Microsoft.VisualStudio.SlowCheetah.TransformTask.Execute()
at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
at Microsoft.Build.BackEnd.TaskBuilder.d__26.MoveNext() OzCruisingHangfireAgent.Program
Best Regards,
Damodar

This is a known issue.
The JSON transformer in SlowCheetah v3.1.66 doesn't support the source or transform files being read-only yet.
See the following issues:
https://github.com/Microsoft/slow-cheetah/issues/86
https://github.com/Microsoft/json-document-transforms/issues/16
The merged PR#17 has a fix for Microsoft.VisualStudio.Jdt, but it hasn't been released yet.
Here are a few work arounds:
Make all files writeable when checking out of source control.
Call the Attrib MSBuild task before the transformation to remove the read-only file attribute.
For example:
<Attrib Files="D:\Data\…\Settings.Release.json" Normal="true"/>
Call the Exec MSBuild task before the transformation to remove the read-only file attribute.
For example:
<Exec Command="attrib -R "D:\Data\…\Settings.Release.json""/>

Related

Not able to create ZIP file through Lambda function

I have small lambda function which donwload files from s3 buckets, create zip of it and upload on S3 bucket again.
My lambda function use .net core3.1.
I can write text file but not create zip file.
Zip File Code in C# (as it deployed in linux system, hence I tried to create zip file in Tmp direcotry)
ZipFile.CreateFromDirectory(#"/tmp/", "test.zip");
Lambda function return below error.
Error :
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
at System.IO.Compression.ZipFile.Open(String archiveFileName, ZipArchiveMode mode, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.DoCreateFromDirectory(String sourceDirectoryName, String destinationArchiveFileName, Nullable`1 compressionLevel, Boolean includeBaseDirectory, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.CreateFromDirectory(String sourceDirectoryName, String destinationArchiveFileName)
at XXX.DownloadService.CreateZip(DownloadRequest downloadRequest) in D:\Projects\DownloadService.cs:line 133
I don't know what did I wrong. or what is alternative to create zip file if this approach is wrong.
Help me.
Thanks in advance.
I suspect that it is trying to create the Zip file in a read-only directory. The second parameter can include the path of the destination Zip file:
public static void CreateFromDirectory (string sourceDirectoryName, string destinationArchiveFileName);
destinationArchiveFileName: The path of the archive to be created, specified as a relative or absolute path. A relative path is interpreted as relative to the current working directory.
However, in an AWS Lambda function, only the /tmp/ directory can be written to. This might conflict with the fact that you are zipping the entire /tmp/ directory. You might need to put your files in a sub-directory of the /tmp/ directory:
ZipFile.CreateFromDirectory(#"/tmp/files_to_zip/", "/tmp/test.zip");

Create accessible file from root privilege process

I'm having a bunch of processes from different privileges, all running a shared code that open (and create if needed) a file for write using fopen_s with "a+" flag.
However, since no permissions that supplied to this command, and a root process create the file first, than other non-root processes couldn't access this file.
I could use int open(const char *pathname, int flags, mode_t mode); and thus control the file permissions (represented by mode_t) to allow access for everyone, but I need the file descriptor (FILE *) and not fileID. so I can use FILE *fdopen(int fd, const char *mode); in order to make the conversion.
Perhaps there's a more straight forward way to do it ?
No. The technique you described (open followed by fdopen) is the correct way to achieve what you want to do. As Some programmer dude pointed out, you could call chmod from your program to change the file permissions after it's created, but that's a more roundabout way to do it.
I could use int open(const char *pathname, int flags, mode_t mode); and thus control the file permissions (represented by mode_t)
Not really. Unless you set your process's umask setting. Because the permissions passed to open() are not the permissions the created file is necessarily created with.
Per POSIX open() (bolding mine):
the access permission bits (see <sys/stat.h>) of the file mode shall be set to the value of the argument following the oflag argument taken as type mode_t modified as follows: a bitwise AND is performed on the file-mode bits and the corresponding bits in the complement of the process' file mode creation mask. Thus, all bits in the file mode whose corresponding bit in the file mode creation mask is set are cleared.
So
int fd = open( someFileName, O_CREAT | O_RDWR, 0644 );
is NOT guaranteed to set the file permissions to 0644.
If your file creation mask is set to 0077, then the file will actually be created with permissions set to 0600.
Note that the umask() setting is a process-wide property, and it's not really a good idea to change it much. And if you're trying to write general-purpose code that has no side effects, it's a bad idea to change it at all. For example, changing the umask() setting in a multithreaded process in order to allow wider access to files being created can cause
security problems if another thread creates a file at the same time.
The best way to set file permissions to be exactly what you want is to set file permissions to be exactly what you want with fchmod():
FILE *f = fopen(...);
fchmod( fileno( f ), 0644 );
In fact, since the umask() setting is a process-wide property, it's always possible in general that it can be changed by another thread at any time, so setting the permissions explicitly via chmod() or fchmod() is the only guaranteed way to get exactly the permissions specified in all circumstances.

Convert local HTML file to PDF with wkhtmltopdf C library

I am using the wkhtmltopdf C library to convert a local HTML file to PDF, but no matter what I've tried, it does not successfully convert the file. Using an external URI (like google.com) works fine, however any local files will fail, either with no error message or with HTTP error codes 1003 or 1302.
Here is the code I am using:
wkhtmltopdf_global_settings *globalSettings;
wkhtmltopdf_object_settings *objectSettings;
wkhtmltopdf_converter *converter;
wkhtmltopdf_init(1);
globalSettings = wkhtmltopdf_create_global_settings();
wkhtmltopdf_set_global_setting(globalSettings, "size.paperSize", "A4");
wkhtmltopdf_set_global_setting(globalSettings, "orientation", "Portrait");
wkhtmltopdf_set_global_setting(globalSettings, "colorMode", "Color");
wkhtmltopdf_set_global_setting(globalSettings, "size.paperSize", "A4");
wkhtmltopdf_set_global_setting(globalSettings, "out", "output.pdf");
converter = wkhtmltopdf_create_converter(globalSettings);
objectSettings = wkhtmltopdf_create_object_settings();
wkhtmltopdf_set_object_setting(objectSettings, "load.blockLocalFileAccess", "false");
wkhtmltopdf_set_object_setting(objectSettings, "page", "inputfile.html");
wkhtmltopdf_add_object(converter, objectSettings, NULL);
if (wkhtmltopdf_convert(converter) != 1)
{
qWarning(qPrintable("Error code: " + QString::number(wkhtmltopdf_http_error_code(converter))));
}
wkhtmltopdf_destroy_converter(converter);
wkhtmltopdf_deinit();
I am using QT, and the input file is within a resource file of mine. I have tried many variation to get wkhtmltopdf to load the file, but none of the following have worked (some liberties have been taken with the below source, but you should get the idea):
I tried to copy the contents of the input file into a QTemporaryFile, and load that file:
QTemporaryFile temp;
if (temp.open())
{
temp.write(inputFile.readAll());
wkhtmltopdf_set_object_setting(objectSettings, "page", temp.fileName());
}
I tried using the resource file path directly:
wkhtmltopdf_set_object_setting(objectSettings, "page", ":templates/input.html");
I've also tried adding in file:// for the above attempts. Does anyone have any idea why it may not be working, and if so, how to fix it?
The Qt resource paths will most likely not work. The resource paths are only visible to APIs that internally use QFile and use the same copy of the Qt library as your code is using.
The approach with temporary files is a decent workaround.
But this line can't really work:
wkhtmltopdf_set_object_setting(objectSettings, "page", temp.fileName());
The type that you pass (a QString) is wrong. Unfortunately, the interface is C-like and there's no type safety, so you're lulled into complacency. You need to pass it a utf8-encoded file path:
wkhtmltopdf_set_object_setting(objectSettings, "page",
temp.fileName().toUtf8().constData());

Resetting file security to inherit AFTER a MoveFile() operation

Windows/C++
Looking for some recommendations on how to reset the security attributes on a file after it's been moved to a new folder.
Our standard way of creating files (and download from the server) is to create the file in a temporary folder, then as the file streams down, the file is appended. Once the download is completed, we move the file to it's final destination.
MoveFile() will transfer the security on the file when the file is moved. In certain configuration this causes a problem -- where the security defaults of final folder don't match the original folder. We cannot mess with folder security....
So, ultimately, I would like to perform an operation on the file after I move it. My current thinking is that I should fetch the security attributes of the folder it goes into, and then apply to the file after the move is completed.
To expand on Harry's answer, here is the full code:
// blank acl used to restore permissions after a file move
ACL g_null_acl = { 0 };
InitializeAcl(&g_null_acl, sizeof(g_null_acl), ACL_REVISION);
DWORD error = SetNamedSecurityInfo(file_path, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION,
NULL, NULL, (PACL)&g_null_acl, NULL);
Keep in mind that calling SetNamedSecurityInfo (in this instance) requires SE_RESTORE_NAME privileges, so it cannot be called from a service running as Network Service (or Local Service), as they have limited permissions.
Use SetNamedSecurityInfo with the UNPROTECTED_DACL_SECURITY_INFORMATION flag. Just pass an empty ACL to remove the entries the file got from its previous parent. This would look something like this:
error = SetNamedSecurityInfo(
path_to_file,
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION,
NULL,
NULL,
empty_acl,
NULL);

How to give 'Everybody' full rights to a file (programmatically)

I'm modifying an old C++ program to run on Vista. It does not require Admin privileges.
I've changed the code to put logfiles in \ProgramData\MyApp\. These logfiles are written with the stdio functions (fopen, fprintf, fclose).
Here's the problem:
UserA runs the program first, it creates \ProgramData\MyApp\MyLogFile.txt using CreateFile()
UserB runs the program next, it tries to append to MyLogFile.txt and gets access denied.
I tried creating a null SECURITY_DESCRIPTOR and passing that to CreateFile(). That does create a file with "no permissions assigned", but it seems as if the first user to write to the file takes ownership and afterwards all the other non-admin users are out of luck.
It's important that all users share the same logfiles, but it's also important that I change as little code as possible.
Edited to add:
\ProgramData\MyApp is created by a standard Visual Studio installer. (I don't see any place to set directory security.) When it creates \MyApp it grants Users these permissions:
Read & execute
List folder contents
Read
Special permissions
Under Advanced I see that Special permissions includes:
Create files / write data
Create folders / append data
Write attributes
Write extended attributes
+1 to everyone for trying, but eventually I found the answer here:
how to change the ACLs from c++?
I did have to change one line of that solution, from this:
ea[0].grfAccessMode = DENY_ACCESS;
to this:
ea[0].grfAccessMode = GRANT_ACCESS;
Probably that your application uses an installer. When the installer creates your folder "MyApp", assign read/write rights for everyone. This will probably fix your problem. There are different ways of doing this, but it depends on the type of the setup that you use.
Added custom action info.
If after install the folder does not have the required permissions you could add for example a custom action as a visual basic script on the install sequence, that will set the required permissions.
VBS Examble:
Function SetPermissions()
Dim strHomeFolder, strHome, strUser
Dim intRunError, objShell, objFSO
strHomeFolder = "C:\Test"
Set objShell = CreateObject("Wscript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FolderExists(strHomeFolder) Then
intRunError = objShell.Run("%COMSPEC% /c Echo Y| cacls " _
& strHomeFolder & " /t /c /g everyone:F ", 2, True)
If intRunError <> 0 Then
Wscript.Echo "Error assigning permissions for user " _
& strUser & " to home folder " & strHomeFolder
End If
End If
End Function
You need to add an allow rule for the user "Everyone" if that is what you truly want.
A null descriptor will defer to the directory's security if memory serves...
You must definetely use CreateFile. See more about security and access rights. I am sure that functions from the standard C library use CreateFile (it can't use anything else on Windows) but with default security parameters which are not helpful in your case.
I tried also to look inside SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR structures but it's not very easy to understand how to do it, though it may be a chance.