I'm trying to retrieve the information from a share using the C Windows API. For compilation I'm using the MINGW64 flavor of MSYS2 (https://www.msys2.org/docs/environments/). But I'm having problems when I try to convert the SIDs in the security descriptor to plain text names. This is a simplified version of my code:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <lm.h>
#include <ntstatus.h>
#include <ntsecapi.h>
int main(int argc, char **argv) {
NET_API_STATUS res1;
NTSTATUS res2;
// Get info from share
SHARE_INFO_502 *info;
res1 = NetShareGetInfo(L"domain.tld", L"test", 502, (LPBYTE *)&info);
if (res1 != 0) {
fprintf(stderr,
"NetShareGetInfo failed with error %d\n",
res1);
exit(EXIT_FAILURE);
}
// Validate security descriptor
SECURITY_DESCRIPTOR *sd = info->shi502_security_descriptor;
if (IsValidSecurityDescriptor(sd) == 0) {
fprintf(stderr, "Security descriptor is not valid\n");
exit(EXIT_FAILURE);
}
// Open policy handle
LSA_HANDLE polHandle;
LSA_OBJECT_ATTRIBUTES polAttrs;
memset(&polAttrs, '\0', sizeof(polAttrs)); // must be zero according to docs
res2 = LsaOpenPolicy(NULL, &polAttrs, POLICY_EXECUTE, &polHandle);
if (res2 != STATUS_SUCCESS) {
fprintf(stderr,
"LsaOpenPolicy failed with error %d (converted from %lX)\n",
LsaNtStatusToWinError(res2), res2);
exit(EXIT_FAILURE);
}
// Translate owner SID
LSA_TRANSLATED_NAME *names;
LSA_REFERENCED_DOMAIN_LIST *domains;
res2 = LsaLookupSids2(polHandle, 0, 1, &sd->Owner, &domains, &names);
if (res2 != STATUS_SUCCESS) {
fprintf(stderr,
"LsaLookupSids2 failed with error %d (converted from %lX)\n",
LsaNtStatusToWinError(res2), res2);
exit(EXIT_FAILURE);
}
// do something here with names and domains
LsaFreeMemory(names);
LsaFreeMemory(domains);
return 0;
}
I then compile it and execute it:
C:\Users\myname\Desktop\c-tests\sdproblem>main.exe
LsaLookupSids2 failed with error 87 (converted from C000000D)
Error 87 means "The parameter is incorrect". It seems I'm not passing the arguments correctly to the LsaLookupSids2 function. But I'm not able to see what I'm doing wrong. I've tried passing some flags in the second argument instead of 0 to no avail. I've also tried to use LsaLookupSids (and remove the second argument) but still no luck. The share exists and the permissions can be retrieved by icacls:
C:\Users\myname\Desktop\c-tests\sdproblem>icacls \\domain.tld\test
\\domain.tld\test Everyone:(OI)(CI)(F)
Can someone help me with this issue?
Related
Is it possible for a c application using libwayland-client.so to get the name of the compositor / display server it opened a connection to (e.g. KWin, Sway, ...)? I fail to find it in the docs.
For reference, in X11 this is possible using XProps specified by EWMH: _NET_SUPPORTING_WM_CHECK to get the window id of the window manager and then using _NET_WM_NAME.
Im fine with anything giving me a way to identify it, for example a pretty name, the process name, the pid or similar.
Current solution is to detect which socket file wayland will be using (${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY:-wayland-0}), detecting which process are listening on it and picking the one which is most probably the compositor (similar to what neofetch does in bash). But since i need to open a connection anyway, and this method is very bug prone, i think you can see why i want to have a cleaner solution.
Requirements:
determine the PID of the peer compositor process for a display connection on the client side
must run under Linux
optionally determines the process name
Since this is not directly supported by the API, you can
get the file descriptor of the display context (wl_display_get_fd)
use the file descriptor to read the associated PID of the peer process (getsockopt with the SO_PEERCRED option, see e.g. this nice SO answer)
finally, you can get the process name by reading /proc/<pid>/comm.
You could also retrieve the process command line if you need more information.
However, the output of the following test program would look like this under Ubuntu 22.04 LTS:
pid: 1733, process name: gnome-shell
Self-contained Example in C
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-client.h>
#include <sys/socket.h>
#include <errno.h>
#define PROCESS_NAME_MAX_LENGTH 1024
static pid_t pid_from_fd(int fd) {
struct ucred ucred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) {
perror("getsockopt failed");
exit(-1);
}
return ucred.pid;
}
static char *process_name_from_pid(const pid_t pid) {
char *name = malloc(PROCESS_NAME_MAX_LENGTH);
if (!name) {
perror("malloc failed");
exit(-1);
}
char proc_buf[64];
sprintf(proc_buf, "/proc/%d/comm", pid);
FILE *fp;
if ((fp = fopen(proc_buf, "r")) == NULL) {
fprintf(stderr, "opening '%s' failed: %s\n", proc_buf, strerror(errno));
exit(-1);
}
if (fgets(name, PROCESS_NAME_MAX_LENGTH, fp) == NULL) {
fprintf(stderr, "reading '%s' failed\n", proc_buf);
exit(-1);
}
name[strcspn(name, "\n")] = 0;
fclose(fp);
return name;
}
int main(void) {
struct wl_display *display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "can't connect to display\n");
exit(-1);
}
int fd = wl_display_get_fd(display);
pid_t pid = pid_from_fd(fd);
char *process_name = process_name_from_pid(pid);
printf("pid: %d, process name: %s\n", pid, process_name);
free(process_name);
wl_display_disconnect(display);
return 0;
}
I've read some of the warnings against using the sysctl() call in C, and it seems if I cannot use sysctl() safely, the only other way I can find to make the needed change would be to use soemething like:
system("echo fs.inotify.max_user_watches=NEW_MAX_DIRECTORIES >> /etc/sysctl.conf");
system("sysctl -p");
(of course, this assumes ensuring the binary is running as root. However, I would rather NOT have to shell out using system calls.
Can someone point me in the correct and safe of using sysctl()?
here is a snippet of the code I am using.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
int main ()
{
int ret;
const char *LOGNAME="iNotifyMonitor";
logger(INFO, "================================================");
ret = startDaemon();
daemonRunning = ret;
if (ret == 0)
{
daemonRunning = 1;
FIRST_RUN = 0;
}
if(ret)
{
syslog(LOG_USER | LOG_ERR, "Error starting iNotifyMonitor");
logger(ERR, "Unable to start iNotifyMonitor");
closelog();
return EXIT_FAILURE;
}
signal(SIGINT, signalHandler);
signal(SIGHUP, signalHandler);
char *log_file_name = malloc(sizeof(char *) * sizeof(char *));
sprintf(log_file_name, "%s%s", INM_LOG_DIR, INM_LOG_FILE);
/* Try to open log file to this daemon */
if (INM_OPEN_LOG && INM_LOG_FILE)
{
log_stream = fopen(concatString(INM_LOG_DIR, INM_LOG_FILE), "a+");
if (log_stream == NULL)
{
char *errMsg;
sprintf(errMsg, "Cannot open log file %s, error: %s", concatString(INM_LOG_DIR, INM_LOG_FILE), strerror(errno));
log_stream = stdout;
}
}
else
{
log_stream = stdout;
}
while (daemonRunning == 1)
{
if (ret < 0)
{
logger(LOG_ERR, "Can not write to log stream: %s, error: %s", (log_stream == stdout) ? "stdout" : log_file_name, strerror(errno));
break;
}
ret = fflush(log_stream);
if (ret != 0)
{
logger(LOG_ERR, "Can not fflush() log stream: %s, error: %s",
(log_stream == stdout) ? "stdout" : log_file_name, strerror(errno));
break;
}
int curcount =countDirectory("/home/darrinw/Development/CrossRoads/");
directoryCount = curcount;
if(directoryCounrt > INM_MAX_DIRECTORIES)
{
int newVal = roundUp(directoryCount, 32768);
// call to sysctl() to modify fs.inotify.max_users_watches=newVal
}
sleep(INM_SCAN_INTERVAL);
}
My understanding is that the modern recommended approach to access sysctl variables is via the pseudo-files in /proc/sys. So just open /proc/sys/fs/inotify/max_user_watches and write there.
int fd = open("/proc/sys/fs/inotify/max_user_watches", O_WRONLY);
dprintf(fd, "%d", NEW_MAX_DIRECTORIES);
close(fd);
Error checking left as an exercise.
Modifying /etc/sysctl.conf would make the setting persist across reboots (assuming your distribution uses the file this way, I am not sure if all of them do). That's kind of rude to do automatically; probably better to use the documentation to advise the system administrator to do it themselves if it's needed.
I'm trying to write the simpliest client in RPC with this code:
#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
int main(int argc, char *argv[]){
int stat;
char out;
char in='f';
if(stat=callrpc(argv[1],0x20000001, 1, 1, (xdrproc_t)xdr_void, &in, (xdrproc_t)xdr_char, &out)!=0){
clnt_perrno(stat);
exit(1);
}
exit(0);
}
It compiles, but when I try to run it, it gives me a "RPC: Can't encode arguments"
EDIT: Actually the server do not recieve any argument neither it send back anything, that's why I put a xdr_void added &in and &out to avoid segmentation fault error.
You are missing some parentheses:
if (stat = callrpc(...) != 0)
is evaluated to
if (stat = (callrpc(...) != 0))
which always assigns 1 to stat in case of an error, which is RPC_CANTENCODEARGS. You need
if ((stat = callrpc(...)) != 0)
to get the real error code and message printed in
clnt_perrno(stat);
My SSH server uses double authtication. I do not know how its implemented. But initially its asks for a password, then again asks for another password to login to a separate console which is different from usual control.
My code is similar to the example code shown in the documentations,
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <libssh/libssh.h>
int main(int argc, char * argv[])
{
ssh_session my_ssh_session = ssh_new();
int rc;
char * password;
char * username = "admin";
// Check if ssh session exists.
if(my_ssh_session == NULL)
{
exit(-1);
}
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "x.x.x.x");
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error Connecting to Server: %s.\n", ssh_get_error(my_ssh_session));
exit(-1);
}
password = getpass("Password: ");
rc = ssh_userauth_password(my_ssh_session, username, password);
if (rc != SSH_AUTH_SUCCESS)
{
fprintf(stderr, "ERROR Authenticating: %s.\n", ssh_get_error(my_ssh_session));
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
}
else
{
printf("Authentication Successful.\n");
}
ssh_free(my_ssh_session);
}
How do i implement a double authtication in this ? can you kindly help me out ?
What version of
libssh do you have?
"versions 0.5.1 and above have a logical error in the handling of a SSH_MSG_NEWKEYS and SSH_MSG_KEXDH_REPLY package. A detected error did not set the session into the error state correctly and further processed the packet which leads to a null pointer dereference. This is the packet after the initial key exchange and doesn’t require authentication."
Ref libssh
I want to be able to check to see if a file could be opened on Linux (for read or for read and write). However I don't have control of the code which will be opening the file, so I can't do what I would normally do which is to open it and then handle the error.
I appreciate that there will always be race conditions on any check due to permissions changing after the call has returned but before the open call, but I'm trying to avoid some undesirable error logging from a library which I have no control over.
I'm aware of stat, but I'd prefer not to need to try to replicate the logic of checking user IDs and group IDs.
You can use:
access("filename", R_OK);
or
euidaccess("filename", R_OK);
To check if your UID or EUID have read access to a respective file. (UID and EUID will be different if your are running setuid)
Use euidaccess or access, although you almost certainly always want to use the former.
(edit: the reason for adding this was that with this approach you can ensure you can avoid the race conditions. That said, it is quite a tricky approach, so maybe just coping with potential race conditions is a better practical approach).
If your goal is to shield the code that you do not own from unhandled errors, using LD_PRELOAD to intercept the open call itself might be of use. An example of it with malloc is here: Overriding 'malloc' using the LD_PRELOAD mechanism
here my quick improvisation on how you could do it - basically an interceptor that will launch an interactive shell to you to correct the error.
WARNING: lots of open calls actually do fail for legit reasons, e.g. when the program is going over different directories in the path trying to find the file, so treat this code as an educational example only to be used with this example code - if you are any close to real world use, your code definitely will need to be smarter. With all this said, let's get to the meat.
First, the "offensive" program that you do not have the control over:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
int res = 0;
printf("About to try to open the file...\n");
res = open("/tmp/unreadable", O_RDONLY);
printf("The result after opening: %d\n", res);
if (res < 0) {
perror("Could not open, and here is what the errno says");
} else {
char buf[1024];
int fd = res;
res = read(fd, buf, sizeof(buf));
printf("Read %d bytes, here are the first few:\n", res);
buf[30] = 0;
printf("%s\n", buf);
close(fd);
}
}
Then the interceptor:
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#define __USE_GNU
#include <dlfcn.h>
static int (*real_open)(const char *pathname, int flags, ...)=NULL;
static void __open_trace_init(void)
{
real_open = dlsym(RTLD_NEXT, "open");
if (NULL == real_open) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
return;
}
}
int open(const char *pathname, int flags, ...)
{
if(real_open==NULL)
__open_trace_init();
va_list va;
int res = 0;
do {
if (flags & O_CREAT) {
int mode = 0;
va_start(va, flags);
mode = va_arg(va, int);
va_end(va);
fprintf(stderr, "open(%s, %x, %x) = ", pathname, flags, mode);
res = real_open(pathname, flags, mode);
fprintf(stderr, "%d\n", res);
} else {
fprintf(stderr, "open(%s, %x) = ", pathname, flags);
res = real_open(pathname, flags);
fprintf(stderr, "%d\n", res);
}
if (res < 0) {
printf("The open has returned an error. Please correct and we retry.\n");
system("/bin/sh");
}
} while (res < 0);
return res;
}
And here is how it looks like when running:
ayourtch#ayourtch-lnx:~$ echo This is unreadable >/tmp/unreadable
ayourtch#ayourtch-lnx:~$ chmod 0 /tmp/unreadable
ayourtch#ayourtch-lnx:~/misc/stackoverflow$ LD_PRELOAD=./intercept ./a.out
About to try to open the file...
open(/tmp/unreadable, 0) = -1
The open has returned an error. Please correct and we retry.
open(/dev/tty, 802) = 3
open(/dev/tty, 802) = 3
open(/home/ayourtch/.bash_history, 0) = 3
open(/home/ayourtch/.bash_history, 0) = 3
open(/lib/terminfo/x/xterm, 0) = 3
open(/etc/inputrc, 0) = 3
sh-4.1$ ls -al /tmp/unreadable
---------- 1 ayourtch ayourtch 19 2011-10-18 13:03 /tmp/unreadable
sh-4.1$ chmod 444 /tmp/unreadable
sh-4.1$ exit
open(/home/ayourtch/.bash_history, 401) = 3
open(/home/ayourtch/.bash_history, 0) = 3
open(/home/ayourtch/.bash_history, 201) = 3
open(/tmp/unreadable, 0) = 3
The result after opening: 3
Read 19 bytes, here are the first few:
This is unreadable
�0
ayourtch#ayourtch-lnx:~/misc/stackoverflow$
By the way this example also exposes an obvious bug in the first "test" code - I should have checked that the number of the chars read was at least 30 and put the null char accordingly.
Anyway, that code is supposed to be buggy and outside of the control, so it is kind of good to have a bug in it - else you would not need to use this kind of hack :-)