setxattr fails with Operation not supported - c

I am trying to set the file attributes as follows:
create file foo.txt with 0644 permissions
when I am trying to setxattr for this as
if (setxattr("foo.txt", "user.test", "test", 4, XATTR_CREATE) == -1)
perror("");
I am getting the error as Operation not supported
Is there any thing to enable?
How to resolve this?

From setxattr
RETURN VALUE
On success, zero is returned. On failure, -1 is returned and errno is set
appropriately.
...
If extended attributes are not supported by the file system, or are disabled,
errno is set to ENOTSUP.
So, either your file system doesn't support extended attributes (ext[234], cifs, btrfs do, for example) or they are disabled at the kernel build or at mount time.
For NFS there is no separate switch to enable extended attributes in the kernel config. From the source fs/nfs/dir.c, it seems to be enabled, when you enable support for CONFIG_NFS_V3 or CONFIG_NFS_V4. But NFS still depends on the underlying file system. So you must enable extended attributes on the server side as well.
From man mount
Mount options for ext2
...
user_xattr|nouser_xattr
Support "user." extended attributes (or not).

Related

Can Win32 applications open the system's settings from code?

Is it possible to open Windows' settings dialogs using Win32 API calls from C? Such as the monitor settings (the one that allows you to set the monitor's resolution), and the network settings (the one that allows you to set the Wifi settings).
If it is possible, how to do that?
Or, is this not possible at all, and the user has to manually open them?
Launch the Windows Settings app explains how to pull up the Windows Settings app using the ms-settings: URI scheme. It also lists the supported URIs, including the ones this question is asking for (ms-settings:network-wifi and ms-settings:display).
While the documentation proposes using the Windows Runtime API Launcher.LaunchUriAsync this is a fair bit complex with C (as opposed to C++). Since the URIs can be invoked from the command prompt using the start command (e.g. start ms-settings:display), it's reasonable to assume that ShellExecuteExW can handle the ms-settings: URI scheme as well.
And indeed, this does appear to work:
#include <Windows.h>
#include <stdio.h>
int main() {
SHELLEXECUTEINFOW sei = {
.cbSize = sizeof(sei),
.hwnd = NULL,
.lpVerb = L"open",
.lpFile = L"ms-settings:display",
//.lpFile = L"ms-settings:network-wifi",
.nShow = SW_SHOWNORMAL,
};
if (!ShellExecuteExW(&sei))
{
printf("Failed with error code %d", GetLastError());
}
}
I wasn't able to find any documentation that specifies this behavior, so this may well be an unsupported implementation detail. I will also mention that while SHELLEXECUTEINFOW has an lpClass field that can be used to specify a URI protocol scheme, none of my iterations to use it worked for the ms-settings: URI scheme.

Kernel module check if file exists

I'm making some extensions to the kernel module nandsim, and I'm having trouble finding the correct way to test if a file exists before opening it. I've read this question, which covers how the basic open/read/write operations go, but I'm having trouble figuring out if and how the normal open(2) flags apply here.
I'm well aware that file reading and writing in kernel modules is bad practice; this code already exists in the kernel and is already reading and writing files. I am simply trying to make a few adjustments to what is already in place. At present, when the module is loaded and instructed to use a cache file (specified as a string path when invoking modprobe), it uses filp_open() to open the file or create it if it does not exist:
/* in nandsim.c */
...
module_param(cache_file, charp, 0400);
...
MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
...
struct file *cfile;
cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
You might ask, "what do you really want to do here?" I want to include a header for the cache file, such that it can be reused if the system needs to be reset. By including information about the nand page geometry and page count at the beginning of this file, I can more readily simulate a number of error conditions that otherwise would be impossible within the nandsim framework. If I can bring down the nandsim module during file operations, or modify the backing file to model a real-world fault mode, I can recreate the net effect of these error conditions.
This would allow me to bring the simulated device back online using nandsim, and assess how well a fault-tolerant file system is doing its job.
My thought process was to modify it as follows, such that it would fail trying to force creation of a file which already exists:
struct file *cfile;
cfile = filp_open(cache_file, O_CREAT | O_EXCL | O_RDWR | O_LARGEFILE, 0600);
if(IS_ERR(cfile)){
printk(KERN_INFO "File didn't exist: %ld", PTR_ERR(cfile));
/* Do header setup for first-time run of NAND simulation */
}
else{
/* Read header and validate against system parameters. Recover operations */
}
What I'm seeing is an error, but it is not the one I would have expected. It is reporting errno 14, EFAULT (bad address) instead of errno 17 EEXIST (File exists). I don't want to run with this because I would like this to be as idiomatic and correct as possible.
Is there some other way I should be doing this?
Do I need to somehow specify that the file path is in user address space? If so, why is that not the case in the code as it was?
EDIT: I was able to get a reliable error by trying to open with only O_RDWR and O_LARGEFILE, which resulted in ENOENT. It is still not clear why my original approach was incorrect, nor what the best way to accomplish my goal is. That said, if someone more experienced could comment on this, I can add it as a solution.
Indeed, filp_open expects a file path which is in kernel address space. Proof is the use of getname_kernel. You can mimic this for your use case with something like this:
struct filename *name = getname(cache_file);
struct file *cfile = ERR_CAST(name);
if (!IS_ERR(name)) {
cfile = file_open_name(name, O_CREAT | O_EXCL | O_RDWR | O_LARGEFILE, 0600);
if (IS_ERR(cfile))
return PTR_ERR(cfile);
putname(name);
}
Note that getname expects a user-space address and is the equivalent of getname_kernel.

Permission denied when trying to create message queue using POSIX Message Queues

I am creating a message queue with the following snippet by following The Linux Programming Interface.
if((mq_open("/my_message_queue", O_CREAT, O_RDWR, NULL)) == -1) {
perror("mq creation failed");
}
Running this snippet I get an error: "permission denied". I wanted to check and see if I had created the queue previously and not destroyed it, so I used ipcs. However, ipcs does not show any active message queues. I have never used the POSIX IPC libraries in my development environment before (Ubuntu 18.04). Is some set up I must do to allow my user process to create a message queue? Am I using the API incorrectly?
From the man page:
The oflag argument specifies flags that control the operation of the call. (Definitions of the flags values can be obtained by including <fcntl.h>.) Exactly one of the following must be specified in oflag:
O_RDONLY Open the queue to receive messages only.
O_WRONLY Open the queue to send messages only.
O_RDWR Open the queue to both send and receive messages.
You have none of those three values in your code. Or rather you do, but it's in the mode argument, not the oflag one, where the corresponding number has a completely different meaning. That third argument is the filesystem permission bits used when creating the queue (just like the third argument to open() when creating a new file), not the mode the queue is opened in.
EACCES: The queue exists, but the caller does not have permission to
open it in the specified mode.
ipcs won't show you queues that you can't read. That it doesn't show you the queue is consistent with mq_open returning a permission error.
TLPI describes mount -t mqueue to a directory of your choosing. You can then use ls(1) on that directory to see the queues, and even interrogate the queues' states by reading the "files" in that directory.
My guess is the queue exists and belongs to root....
POSIX states :
... The name argument conforms to the construction rules for a pathname, except that the interpretation of <slash> characters other than the leading <slash> character in name is implementation-defined ...
On Linux, the name /my/message_queue is incorrect. Linux requires the name to start with /, but it can contain no other / characters.
Per the Linux mq_overview.7 man page:
Message queues are created and opened using mq_open(3); this function
returns a message queue descriptor (mqd_t), which is used to refer to
the open message queue in later calls. Each message queue is
identified by a name of the form /somename; that is, a null-
terminated string of up to NAME_MAX (i.e., 255) characters consisting
of an initial slash, followed by one or more characters, none of
which are slashes.

SHCreateItemFromParsingName return FILE_NOT_FOUND when filename specified

I try get IShellItem for a file to copy it with IFileOperation COM interface from system directory to another directory. I must use exactly IFileOperation COM interface for this purpose.
When I specify full filename - return value from SHCreateItemFromParsingName() was ERROR_FILE_NOT_FOUND, but file present in the directory. When I delete filename from path below and use only folder path - all seems good, return value is S_OK.
//...
CoInitialize(NULL);
//...
WCHAR szSourceDll[MAX_PATH * 2];
wcscpy_s(szSourceDll, MAX_PATH, L"C:\\Windows\\System32\\sysprep\\cryptbase.dll");
r = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_HANDLER, &IID_IFileOperation, &FileOperation1);
if (r != S_OK) return;
FileOperation1->lpVtbl->SetOperationFlags(FileOperation1, FOF_NOCONFIRMATION | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION);
r = SHCreateItemFromParsingName(szSourceDll, NULL, &IID_IShellItem, &isrc);
//...
CoUninitialize();
//...
Why this code, written in C, not working with filenames. How can I create IShellItem instance for file in system folder to copy it?
P.S.
Windows 7 x64, C, Visual Studio 2015, v140 platform toolset, additional dependencies: Msi.lib;Wuguid.lib;ole32.lib;ntdll.lib
P.P.S
It's properly work with files in user`s directories...
Assuming your application is compiled as a 32-bit application and running on a 64-bit OS, a file not found error is probably correct because your application is redirected to the 32-bit system directory (%WinDir%\SysWoW64).
In most cases, whenever a 32-bit application attempts to access %windir%\System32, %windir%\lastgood\system32, or %windir%\regedit.exe, the access is redirected to an architecture-specific path.
For more information, see File System Redirector on MSDN.
You could temporarily turn off redirection in your thread but it is not really safe to do this when calling shell functions, only functions in kernel32. If the API you are calling internally uses LoadLibrary and/or COM then the API might fail because it will be unable to load from system32 while redirection is disabled.
You can also access the native system32 directory with the %WinDir%\SysNative backdoor. This only works in 32-bit applications on 64-bit Vista+ so you must do some version detection.

write custom timestamp into syslog using syslog.h

my program get events from remote systems, every event contains an timestamp.
I want to log this events to syslog using the event timestamp instead of systemtime.
Is there any way to send a custom header to syslog deamon ?
I'm using rsyslog on debian
EDIT:
The "events" are generated by some "bare-metal" devices.
My application is a gateway between a realtime-ethernet (EthernetPOWERLINK) and a normal network.
I want to save them in micro-second precision, because its important to know in wich sequence they are occoured.
So i need the exact timestamp created by the bare-metal devices.
I'like to put this events into syslog.
I did not found any lib (except syslog.h) to write into syslog).
I really need to build the packages myself and send them to rsyslog deamon ?
No, don't open that can of worms.
If you allow the sender to specify the timestamp, you allow an attacker to spoof the timestamps of events they wish to hide. That kind of defeats the entire purpose (security-wise) of using a separate machine for logging.
What you can do, however, is compare the current time and the timestamp, and include that at the start of every logged message, using something like
struct timespec now;
struct timespec timestamp;
double delta;
int priority = facility | level;
const char *const message;
delta = difftime(timestamp.tv_sec, now.tv_sec)
+ ((double)timestamp.tv_nsec - now.tv_nsec) / 1000000000.0;
syslog(priority, "[%+.0fs] %s\n", delta, message);
On a typically configured Linux machine, that should produce something similar to
Jan 18 08:01:02 hostname service: [-1s] Original message
assuming the message took at least half a second to arrive. If hostname has its clock running fast, the delta would be positive. Normally, the delta is zero. In the case of a very slow network, the delta is negative, since the original event happened in the past relative to the timestamp shown.
If you already have infrastructure in place to monitor the logged messages, you can have a daemon or a cron script read the log files, and generate new log files (not via syslog(), but simply with string and file operations) with the timestamps adjusted by the specified delta. However, that must be done with extreme care, recognizing unacceptable or unexpectedly changing deltas, or maybe flagging them somehow.
If you write your log file monitoring/display widgets, then you can very easily let the user switch between "actual" (syslog) or "derived" (syslog + delta) timestamps, as the delta is trivial to extract from the logged lines if always present; even then, you must be careful to let the user know if a delta is out of bounds or changes unexpectedly, as such a change is most always informative to the user. (If it is not nefarious, it does mean there is something iffy with the machine timekeeping; time should not just jump around. Even NTP adjustments should be quite smooth.)
If you insist on opening that can of worms, just produce your own log files. Many applications do. It's not like syslog() was a magic bullet or a strict requirement for reliable logging, after all.
If your log-receiving application runs as a specific user and group, you can create /var/log/yourlogs/ owned by root user and that group, and save your log files there. Set the directory mode to 02770 (drwxrws--- or u=rwx,g=rwxs,o=), and all files created in that directory will automatically be owned by the same group (that's what the setgid bit, s, does for directories). You just need to make sure your service sets umask to 002 (and uses 0666 or 0660 mode flags when creating log files), so that they stay group-readable and group-writable.
Log rotation (archiving and/or deleting old log files, mailing logs) is usually a separate service, provided by the logrotate package, and configured by dropping a service-specific configuration file in /etc/logrotate.d/ at installation time. In other words, even if you write your own log files, do not rotate them; use the existing service for this. It makes life much easier for your users, us system administrators. (Note: Setting umask 002 at the start of the log rotate scripts is very useful in the above directory case; created files will then be group-writable. umask 022 will make them group-read-only.)
Ok've solved this, by enabling networking support (TCP) and micro seconds timer in rsyslog configuration.
Accroding to RFC 5424 my application build raw syslog messages and sends them via TCP (port 514) to the deamon.
Thanks to Nominal Animal, but i've no choice...
You can write a raw log message to the /dev/log file. This is a Unix domain socket from where the syslog server reads the messages, as they are written with the syslog() function.
I'm not sure about portability since the message format written by syslog() does not seem to follow the RFC 5424. I can only share my findings with busybox and its syslogd and nc utilities.
syslog() function writes messages as datagrams in the form <PRI>Mon DD HH:MM:SS message, where PRI is a priority, i.e. a decimal number computed as facility | severity, followed by a timestamp and a message.
With nc -u local:/dev/log, you can write UDP datagrams to the domain socket directly. For example, writing <84>Apr 3 07:27:20 hello world results in a Apr 3 07:27:20 hostname authpriv.warn hello world line in /var/log/messages.
Then you are free to extend the timestamp with the microseconds precision. Anyway, you need to make sure your syslog server implementation accepts such form. In case of busybox, I had to modify the source code.
Note: Busybox needs to be configured with enabled CONFIG_NC_EXTRA, CONFIG_NC_110_COMPAT and CONFIG_FEATURE_UNIX_LOCAL options to allow for opening /dev/log with nc.

Resources