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?
Trying to create a new bash shell in C and bring it to the user, this is my code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
char* secretpass = "password";
char password[50];
printf("%s", "Password: ");
fgets(password, 50, stdin);
password[strcspn(password, "\n")] = 0;
if (!strcmp(password, secretpass)){
pid_t pid = fork();
if (pid == 0){
execl("/bin/bash", "bash", NULL);
}
}
return 0;
}
After running the code (ELF), i get a new bash shell in ps but it's not my shell because echo $$ brings the first shell, what can I do to get the new shell to screen? kernel module will help?
EDIT:
edited my code for more help, /dev/chardev is a char device that come up with the boot process, the driver is also 0666 (.rw.rw.rw.) writable for everyone, the system(cmd) says at there is no permission at console, even if I do the command myself after execve.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#define MAX 50
#define USERNAME 2
int main(int argc, char const *argv[])
{
// Declare variables.
const char* username = argv[USERNAME];
char* password = (char*)calloc(MAX, sizeof(char));
char* cmd = (char*)calloc(5 * MAX, sizeof(char));
char* secretpass = "password";
printf("%s", "Password: ");
fgets(password, MAX, stdin);
password[strcspn(password, "\n")] = 0;
if (!strcmp(password, secretpass)){
int err;
struct passwd* pw_user = getpwnam(username);
//printf("-%s-%s-%d-%d-%s-%s-%s-\n", pw_user->pw_name, pw_user->pw_passwd,
//pw_user->pw_uid, pw_user->pw_gid, pw_user->pw_gecos,
//pw_user->pw_dir, pw_user->pw_shell);
if ( (err = fchown(0, pw_user->pw_uid, pw_user->pw_gid) ) != 0)
printf("%s %d\n", "fchown error", err);
if ( (err = setpgid(0, 0) ) != 0)
printf("%s %d\n", "setpgid error", err);
if ( (err = tcsetpgrp(0, getpid()) ) != 0)
printf("%s %d\n", "tcsetpgrp error", err);
if ( (err = chdir(pw_user->pw_dir) ) != 0)
printf("%s %d\n", "chdir error", err);
if ( (err = setgid(pw_user->pw_gid) ) != 0)
printf("%s %d\n", "setgid error", err);
if ( (err = setuid(pw_user->pw_uid) ) != 0)
printf("%s %d\n", "setuid error", err);
sprintf(cmd, "%s \"%d %d %d\" %s", "echo", pw_user->pw_uid, pw_user->pw_gid, getpid(), "> /dev/chardev");
system(cmd);
const char *args[] = {"bash", "--rcfile", "/etc/bashrc", NULL};
char LOGNAME[MAX];
char HOME[MAX];
char USER[MAX];
sprintf(LOGNAME, "%s%s", "LOGNAME=", pw_user->pw_name);
sprintf(HOME, "%s%s", "HOME=",pw_user->pw_dir);
sprintf(USER, "%s%s", "USER=", pw_user->pw_name);
const char *env[] = {"SHELL=/bin/bash", LOGNAME, HOME, USER, "IFS= ","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin", "TTY=tty1", NULL}; /* need to generate these; TTY is passed to you */
execve("/bin/bash", args, env);
}
else
execl("/bin/login", "login", NULL);
return 0;
}
always setpgid error and if username isn't root there are also setuid and chdir errors.
From the comments: you're trying to write a login program.
Ok. That's a bit more, and you're going about this all the wrong way. We don't want to fork at all. Let init worry about waiting. Anyway, we get to write a long sequence here:
int targetuid = ... ; /* You need a strategy for getting this */
int targetgid = ... ; /* You need a strategy for getting this */
const char *homdir = ... ; /* You need a strategy for getting this */
if (!strcmp(password, secretpass)){
/* Start up the user's shell */
fchown(0, targetuid, targetgid);
setpgid(0, 0);
tcsetpgrp(0, getpid());
chdir(homedir);
setgid(targetgid);
setuid(targetuid);
const char *args[] = {"-bash", NULL};
const char *env[] = {"SHELL=/bin/bash", "LOGNAME=...", "HOME=...", "USER=...", IFS="...", PATH=/bin:/usr/bin", "TERM=...", NULL }; /* need to generate these; TERM is passed to you */
execve("/bin/bash", args, env);
}
This is very much involved and I actually don't recommend this unless you really have to. I learned a ton when I tried this but it took forever to get it working right.
Particular subpoints: 1) The tty device needs to be owned by the user after a successful login. Thus the fchown(0, ...) call to give ownership to the user. 2) The chdir() first is traditional; you could reverse the order if you wanted to but I don't see why. 3) Starting the shell with a leading - in argv0 tells the shell that it's a login shell. Check in ps -f and you can see this.
I picked up your new code; it actually looks pretty good. The only mistake I can spot is my own; the variable is TERM not TTY (now corrected in my sample above) and the best place to get its value is getenv(). On running your code I only had to make only one correction; that is putting the -bash back. The only error it spits out is the one about chardev; what is chardev?
I guess your failures aren't in this code at all but rather in your kernel.
Info from chat: OP has a custom kernel with a custom /dev/chardev; I can't explain the failures as the code works for me. There may or may not be other changes to the kernel.
the code compiles correctly, but although I run the code with elevated privileges, I still have access denied.
I run the program like this: runas.exe / user: "admin" FlushIpNetTable.exe
OS: Windows 10 Version 10.0.10240
Does anyone have any suggestions why, despite the increased privileges, I cannot clean this table? :) ?
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "IPHLPAPI.lib")
int main() {
DWORD res, dwIndex;
dwIndex=2;
res = FlushIpNetTable(dwIndex);
if (res == ERROR_ACCESS_DENIED) {
printf("Access is denied.\n");
getchar();
exit(1);
} else if (res == ERROR_INVALID_PARAMETER) {
printf("An input parameter is invalid, no action was taken.\n");
getchar();
exit(1);
} else if (res == ERROR_NOT_SUPPORTED) {
printf("The IPv4 transport is not configured on the local computer.\n");
getchar();
exit(1);
}else {
printf("Use FormatMessage to obtain the message string for the returned error.\n");
getchar();
exit(1);
}
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 working on a C application in which I need the name of the currently logged in user. I have tried using getlogin() and getlogin_r() with no success (tested on multiple systems with Ubuntu 16.04 LTS). The application will run as root so I cannot use the environment variables.
Both getlogin() and getlogin_r() work just fine on other Ubuntu 17.04/17.10/18.04(beta) so I don't understand why it doesn't work in 16.04.
Here is a code snippet that I used to test:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
int main(int argc, char *argv[])
{
char user[512] = {0};
int ret = getlogin_r(user, 512);
if ( ret != 0){
fprintf(stderr, "Unable to get User name. Return: %d\n", ret);
}
else{
fprintf(stdout, "Username: %s\n", user);
}
char *lgn;
struct passwd *pw;
if ((lgn = getlogin()) == NULL || (pw = getpwnam(lgn)) == NULL)
{
fprintf(stderr, "Get of user information failed.\n");
}
struct passwd *pwd = getpwuid(getuid());
if (pwd){
fprintf(stdout, "Success! Username: %s\n", pwd->pw_name);
}else
fprintf(stderr, "Failed");
return 0;
}
This is the output generated when I execute the code as root:
Unable to get User name. Return : 2
Get of user information failed.
Success! Username: root
getpwuid returns the details of the user running the process so it is not helpful.
I'm kind of stuck now and any help is highly appreciated.
Output using strerror()
getlogin_r() : No such process
getlogin() : No such file or directory
Success! Username: root