Second setuid not permitted - c++

If I call setuid in a loop to become root and reset the uid, this works only once.
I have the following code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int my_func(int i) {
int current_uid = getuid();
int ret;
fprintf(stderr,
"### i=%d ###: My UID is: %d. My GID is: %d, before 'system(id)'\n",
i, current_uid, getgid());
system("/usr/bin/id");
fprintf(stderr,"\n\n### i=%d ###: before 'setuid(0)'\n", i);
if (setuid(0)) {
perror("setuid");
return 1;
}
fprintf(stderr,"after 'setuid(0)'\n\n");
//I am now root!
fprintf(stderr,
"### i=%d ###: I an now root: My UID is: %d. My GID is: %d, before 'system(id)'\n",
i, getuid(), getgid());
system("/usr/bin/id");
//Time to drop back to regular user priviledges
fprintf(stderr,"\n\nbefore 'setuid(%d)'\n",current_uid);
ret=setuid(current_uid);
fprintf(stderr,
"### i=%d ###: My UID is: %d. My GID is: %d, before 'system(id)\n",
i, getuid(), getgid());
system("/usr/bin/id");
}
int main(void) {
int i;
for (i=0;i<3;i++) {
my_func(i);
sleep(5);
fprintf(stderr,"\n\n");
}
return 0;
}
I set the SUID bit and run this program as ordinary user rose. The output is:
rose#condor:/home/rose/Txt/src/Test/C/Setuid(5)$ ll /usr/local/bin/multiple_setuid_test
-rws--x--x 1 root root 13589 11. Dez 08:41 /usr/local/bin/multiple_setuid_test*
rose#condor:/home/rose/Txt/src/Test/C/Setuid(6)$ /usr/local/bin/multiple_setuid_test
i=0 ###: My UID is: 1203. My GID is: 100, before 'system(id)'
uid=1203(rose) gid=100(users) Gruppen=100(users),4(adm),6(disk),7(lp),10(wheel),14(uucp),18(audio),19(cdrom),27(video),35(games),60(mysql),250(portage),1001(haldaemon),1002(plugdev),1008(scanner),1027(vboxusers),1028(kvm),1029(qemu),1036(gsm),1039(pulse-access),1040(pulse),1041(tuntap)
i=0 ###: before 'setuid(0)'
after 'setuid(0)'
i=0 ###: I an now root: My UID is: 0. My GID is: 100, before 'system(id)'
uid=0(root) gid=100(users) Gruppen=0(root),4(adm),6(disk),7(lp),10(wheel),14(uucp),18(audio),19(cdrom),27(video),35(games),60(mysql),100(users),250(portage),1001(haldaemon),1002(plugdev),1008(scanner),1027(vboxusers),1028(kvm),1029(qemu),1036(gsm),1039(pulse-access),1040(pulse),1041(tuntap)
before 'setuid(1203)'
i=0 ###: My UID is: 1203. My GID is: 100, before 'system(id)
uid=1203(rose) gid=100(users) Gruppen=100(users),4(adm),6(disk),7(lp),10(wheel),14(uucp),18(audio),19(cdrom),27(video),35(games),60(mysql),250(portage),1001(haldaemon),1002(plugdev),1008(scanner),1027(vboxusers),1028(kvm),1029(qemu),1036(gsm),1039(pulse-access),1040(pulse),1041(tuntap)
i=1 ###: My UID is: 1203. My GID is: 100, before 'system(id)'
uid=1203(rose) gid=100(users) Gruppen=100(users),4(adm),6(disk),7(lp),10(wheel),14(uucp),18(audio),19(cdrom),27(video),35(games),60(mysql),250(portage),1001(haldaemon),1002(plugdev),1008(scanner),1027(vboxusers),1028(kvm),1029(qemu),1036(gsm),1039(pulse-access),1040(pulse),1041(tuntap)
i=1 ###: before 'setuid(0)'
setuid: Operation not permitted
i=2 ###: My UID is: 1203. My GID is: 100, before 'system(id)'
uid=1203(rose) gid=100(users) Gruppen=100(users),4(adm),6(disk),7(lp),10(wheel),14(uucp),18(audio),19(cdrom),27(video),35(games),60(mysql),250(portage),1001(haldaemon),1002(plugdev),1008(scanner),1027(vboxusers),1028(kvm),1029(qemu),1036(gsm),1039(pulse-access),1040(pulse),1041(tuntap)
i=2 ###: before 'setuid(0)'
setuid: Operation not permitted
rose#condor:/home/rose/Txt/src/Test/C/Setuid(7)$ uname -a
Linux condor 3.12.4 #1 SMP Mon Dec 9 11:37:38 CET 2013 x86_64 Intel(R) Core(TM)2 CPU 6600 # 2.40GHz GenuineIntel GNU/Linux
Any hint is appreciated.

Linux (just like other unixes) store two values: your real user id, which is set by setuid, corresponds to your login, and is not changed by the s-bit, and your effective user id, which is set by seteuid, and gets changed when you execute a program that has the s-bit set. To be allowed to use setuid(), either your real or your effective user id need to be zero, but if you use setuid() to drop privileges (change from 0 to anything else), your effective user id will be changed as well. So your first setuid(1203) sets the effective user id to 1203 as well, which prevents you from regaining privileges later.
To change from and to root several times, you have to use the setreuid() call to swap both - setreuid(1203, 0) would change your real user id to 1203, and the effective user id to 0, thus allowing you to set the uid to 0 later.
Note that, as long as either of the two uids is 0, you have root privileges. With uid=1203 and euid=0, files you create will belong to you (user id 1203), but you'll still have root access. So check your program for security implications very carefully.
If you need to have root access every now and then throughout your program, it's much safer to create a pipe(), fork() off a child process that keeps root privileges, drop privileges in the parent process, and send some command down the pipe for the child to execute when you need something done as root. That way, you have to security audit only the child process, which is presumably much smaller than your whole program.

Once you give up root privileges by using setuid to change to a non-root user, you no longer have the privileges necessary to use setuid to become root once again.

Related

opensnoop with follow children mode

opensnoop from DTrace can show which files are opened by a program/pid. It does not trace opens by forked/vforked children though. Related dtruss has this follow functionality.
Is there a way to tell opensnoop to also follow children?
-p option actually adds PID == pid check into generated script where pid is built in variable, representing current process id and PID is a -p option value.
There is an action in DTrace called progenyof which checks that current process is a child (not necessary direct) of a process, so simply replace that check in opensnoop:
--- /usr/dtrace/DTT/opensnoop Wed Jun 25 01:34:47 2014
+++ opensnoop Fri Jan 13 17:43:41 2017
## -199,7 +199,7 ##
/* check each filter */
(OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1;
- (OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1;
+ (OPT_pid == 1 && progenyof(PID)) ? self->ok = 1 : 1;
/* OPT_file is checked on return to ensure pathp is mapped */
}

How do I change the creation time of a file to a newer date in Mac OS X?

On Mac OS X, using C and/or C++, I want to change the creation time of a file to an arbitrary date/time. I have found a number of solutions, notably this StackOverflow answer, that allow to set the creation time to an older date, but this is not sufficient for me - I also want to be able to set a newer date. Using the utimes() function therefore is not the solution I am looking for.
I know that setting a newer creation time must be possible somehow, because the SetFile utility from Apple's developer command line tools can do it, but so far my search-fu has failed to uncover any hints that bring me closer to a solution.
Does anyone know of a way how I can achieve my goal?
Why do I want to do this myself, why can't I use SetFile?
The SetFile command line utility is deprecated (see man SetFile), so it's bound to go away some time in the future
I want to create a utility that allows me to specify a time delta to add to/subtract from the current creation time. The SetFile utility does not have any convenient command line arguments to do this.
Last but not least: Curiosity!
Haven't tried it, but according to the docs, the NSURL resource value under the key NSURLCreationDateKey is read-write. Since you specified C or C++, you'd use the corresponding CFURL API. So, you'd call:
CFURLRef url = /* ... */
CFDateRef date = /* ... */
CFErrorRef error;
if (!CFURLSetResourcePropertyForKey(url, kCFURLCreationDateKey, date, &error))
/* handle error */;
EDIT: A minimal example
const char* fileName = "/path/to/file";
size_t fileNameStringLength = strlen(fileName);
Boolean isDirectory = false;
CFURLRef url = CFURLCreateFromFileSystemRepresentation(
kCFAllocatorDefault,
(const UInt8*)fileName,
fileNameStringLength,
isDirectory);
// Seconds since 1 January, 2001 00:00:00 GMT
CFAbsoluteTime absTime = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime adjustedCreationTime = absTime - 3600;
CFDateRef date = CFDateCreate(
kCFAllocatorDefault,
adjustedCreationTime);
CFErrorRef error;
if (!CFURLSetResourcePropertyForKey(url, kCFURLCreationDateKey, date, &error))
{
fprintf(stderr, "an error occurred\n");
exit(1);
}
CFRelease(url);
CFRelease(date);
BTW, I have no idea if this is safe, secure, whatever. So, do this at your own risk.
On OS X, you can sort of do this by setting the time of the day to the future and then copying the file (and renaming it back). It is not the same file with its creation time modified; it is a copy with the creation time you set.
Some code (I got the code to set the time of the day from here):
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <copyfile.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
struct timeval tv_now, tv_set;
copyfile_state_t s;
struct stat st;
// retrieve original stat
if (stat(argv[2], &st) < 0)
perror("stat");
// get current time of day
if (gettimeofday(&tv_now, 0) == -1)
perror("gettimeofday");
// set time of day to +argv[1] days
tv_set = tv_now;
tv_set.tv_sec += 86400 * atoi(argv[1]);
if (settimeofday(&tv_set, 0) == -1)
perror("settimeofday to future");
// copy the file to a temporary, copy everythig except stat
s = copyfile_state_alloc();
if (copyfile(argv[2], ".eighty_eight_miles_per_hour", s, COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_DATA) < 0)
perror("copy file");
copyfile_state_free(s);
// rename it back to original name
if (rename(".eighty_eight_miles_per_hour", argv[2]) < 0)
perror("rename file");
// restore file owner, group, and mode
if (chown(argv[2], st.st_uid, st.st_gid) < 0)
perror("chown");
if (chmod(argv[2], st.st_mode) < 0)
perror("chmod");
// reset current time of day
if (settimeofday(&tv_now, 0) == -1)
perror("settimeofday back to now");
return 0;
}
I call this program the flux_capacitor. The first command line argument is the number of days forward to set the file's creation date, and the second argument is the file name. You have to run this program as root to set the time.
Observe, as I send the delorean forward in time by 2 days.
[ronin:~/Documents/CPP] aichao% touch delorean
[ronin:~/Documents/CPP] aichao% ls -l delorean
-rw-r--r-- 1 aichao staff 0 Aug 10 11:43 delorean
[ronin:~/Documents/CPP] aichao% su
Password:
sh-3.2# ./flux_capacitor 2 delorean
sh-3.2# exit
exit
[ronin:~/Documents/CPP] aichao% ls -l delorean
-rw-r--r-- 1 aichao staff 0 Aug 12 2016 delorean
[ronin:~/Documents/CPP] aichao% date
Wed Aug 10 11:43:47 EDT 2016
and in the Finder:
Note that I only restore the original owner, group, and mode from the stat for the file. I don't think you can or want to do more than that, but I don't know. Obviously, links to the file will be broken.

select() from other thread not handle incoming data

I have multithread applications. In one thread I want to waiting for data, and if this datas will not appear through some time, I just close whole application. Function select() is runs in another thread and thread is detach
A piece sorce some class
#define STDIN 0
A::A(){
runFunction1();
runFunction2();
thread listen(&A::isData , this);
listen.detach();
}
// and function with select
void A::isData{
struct timeval tv;
fd_set readfds;
tv.tv_sec = 50; // wait to 50 seconds
tv.tv_usec = 500000;
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
for(;;) {
select(STDIN+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &readfds)){
cout << "I something catch :)" << endl;
// reset time
}else{
cout << "I nothing catch ! By By :(" << endl;
exit(1);
break;
}
}
}
If my program run then I get pid, so I have tryed write to file descriptor some datas in below way:
$ cd /proc/somePID/fd
$ echo 1 >> 0
Then I should be get info I something catch :) but in console IDE I only get 1 , however if time is out I get I nothing catch ! By By :( to console in IDE.
EDIT: SOLVED
#Vladimir Kunschikov gave me correct tip. Basic on this I show how I do it in C/C++
It will be posible send something to process using command echo we must create pipe. Pipe using function
A::A(){
fd[2]; //two file descriptor for pipes write/read
pipe(fd); // c function to create pipes
runFunction1();
runFunction2();
thread listen(&A::isData , this);
listen.detach();
}
Then in our proces will create other two new file descriptor as below:
lrwx------ 1 user user 64 gru 15 14:02 0 -> /dev/pts/0
lrwx------ 1 user user 64 gru 15 14:02 1 -> /dev/pts/0
lrwx------ 1 user user 64 gru 15 14:02 2 -> /dev/pts/1
lr-x------ 1 user user 64 gru 15 14:02 3 -> pipe:[1335197]
lrwx------ 1 user user 64 gru 15 14:02 4 -> socket:[1340788]
l-wx------ 1 user user 64 gru 15 14:02 5 -> pipe:[1335197]
pipe:[1335197] is descriptor to read in this proces. Now command echo will be works if we will write some to descriptor 3. Using is simply:
$ cd /proc/PID/fd
$ echo 1 > 3
Then we also can using this in select() function but descriptor number is 3 so define should be looks like .
#define STDIN 3
And works
You have wrong assumption that writing to the /proc/pidof application/fd/0 will put data to the stdin stream of the application.
Just read answers to this question: Sending command to java -jar using stdin via /proc/{pid}/fd/0

ACE C++ Log in multiple files

I'm diving through ACE and, I'm logging message in a file using the ACE_ERROR macro.
And AFAIK, ACE_ERROR logs all the messages in the same file, regardless of their error level.
However, I actually need to write messages, according to their error level.
I did see the ACE_LOG_MSG->open() function however, what i understand is that when you already calling this function twice, the second time it will close the file you opened when you called the function at the beginning.
Suppose I have a list and I want to log it and, in this list, two adjacent items don't have the same error level.
Then I would be opening and closing files, wouldn't than affect my apps performance ?
So is there a way to keep those files open ?
Thanks !
Not closing the files you log to is particularly bad in debugging. If the application crashes with an open file, its contents may (and that happens rather often) get corrupted, leaving you with absolutely no information.
If you close the file properly, though, you're guaranteed to find at least some info there, possibly closer to the real issue. If you are concerned with performance, you should simply reduce log level, or if it's not feasible, you could perhaps offload the logging to the other process via (for example) TCP connection.
Anyway, don't optimize until you've measured! It might just be there'll be no impact, performance is a complicated problem which depends on lot of factors.
Another example to re-direct logging as per their logging priority, using a simple wrapper class.
Hope this is useful to someone.
Example program
#include "ace/Log_Msg.h"
#include "ace/streams.h"
// #Author: Gaurav A
// #Date: 2019OCT11
//
// Log each logging statement
// in file based on its priority
//
// eg: INFO logs goes to INFO.log
// DEBUG logs goes to DEBUG.log
class Logger
{
private:
ACE_OSTREAM_TYPE* m_infolog=nullptr;
ACE_OSTREAM_TYPE* m_debuglog=nullptr;
public:
Logger(void)
: m_infolog (new std::ofstream ("INFO.log")),
m_debuglog (new std::ofstream ("DEBUG.log"))
{
}
~Logger(void)
{
delete m_infolog;
delete m_debuglog;
}
int log (ACE_Log_Priority p,
const ACE_TCHAR* fmt,
...)
{
ssize_t final_result=0;
if (p == LM_DEBUG)
{
va_list argp;
va_start (argp, fmt);
ACE_LOG_MSG->msg_ostream (m_debuglog);
ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
final_result = ACE_LOG_MSG->log (fmt, LM_DEBUG, argp);
va_end (argp);
}
else if (p == LM_INFO)
{
va_list argp;
va_start (argp, fmt);
ACE_LOG_MSG->msg_ostream (m_infolog);
ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
final_result = ACE_LOG_MSG->log (fmt, LM_INFO, argp);
va_end (argp);
}
return final_result;
}
};
int
ACE_TMAIN (void)
{
Logger logger;
logger.log (LM_DEBUG, "I am a debug message no %d\n", 1);
logger.log (LM_INFO, "I am a info message no %d\n", 2);
logger.log (LM_DEBUG, "I am a debug message no %d\n", 3);
logger.log (LM_INFO, "I am a info message no %d\n", 4);
return 0;
}
Sample Output
[07:59:10]Host#User:~/acedir
$: ./logging_each_priority_in_its_own_file
I am a debug message no 1
I am a info message no 2
I am a debug message no 3
I am a info message no 4
[07:59:10]Host#User:~/acedir
$: ls -lrth
total 464K
-rw-r--r-- 1 aryaaur devusers 231 Oct 11 07:09 logging_each_priority_in_its_own_file.mpc
-rw-r--r-- 1 aryaaur devusers 5.6K Oct 11 07:29 GNUmakefile.logging_each_priority_in_its_own_file
-rw-r--r-- 1 aryaaur devusers 1.5K Oct 11 07:47 main_logging_each_priority_in_its_own_file_20191011.cpp
-rwxr-xr-x 1 aryaaur devusers 65K Oct 11 07:47 logging_each_priority_in_its_own_file
-rw-r--r-- 1 aryaaur devusers 50 Oct 11 07:59 INFO.log
-rw-r--r-- 1 aryaaur devusers 52 Oct 11 07:59 DEBUG.log
[07:59:10]Host#User:~/acedir
$: cat INFO.log
I am a info message no 2
I am a info message no 4
[07:59:10]Host#User:~/acedir
$: cat DEBUG.log
I am a debug message no 1
I am a debug message no 3
[07:59:10]Host#User:~/acedir
$:

GSSAPI get username password and build credential not working for non logged in user

I am developing a C++ client that uses GSSAPI to login to a server. For the credentials I am using gss methods to build a credential object(explained in code below). My code for this part is
#include <gssapi.h>
#include <gssapi_krb5.h>
#include <gssapi/gssapi_generic.h>
#include <gssapi/gssapi_ext.h>
gss_cred_id_t method_to_get_cred(){
char *username = "asanyal#DOMAIN.COM";
char *password = "correctpassword";
gss_buffer_desc send_tok;
OM_uint32 maj_stat, min_stat;
gss_cred_id_t cred;
gss_name_t gss_username;
gss_OID_set_desc mechs, *mechsp = GSS_C_NO_OID_SET;
gss_buffer_desc pwbuf;
send_tok.value = username;
send_tok.length = strlen(username);
maj_stat = gss_import_name(&min_stat, &send_tok,(
gss_OID) gss_nt_user_name,&gss_username);
if (maj_stat != GSS_S_COMPLETE) {
printf("parsing client name %d %d \n ", maj_stat, min_stat);
return -1;
}
printf("Maj stat after gss_import_name: %d \n", maj_stat);
printf("Acquired username \n");
//getting username complete
//getting password
pwbuf.value = password;
pwbuf.length = strlen(password);
maj_stat = gss_acquire_cred_with_password(&min_stat,
gss_username,
&pwbuf, 0,
mechsp, GSS_C_INITIATE,
&cred, NULL, NULL);
printf("Acquired password \n");
//getting password complete
printf("Maj stat and min stat after gss_acquire_cred_with_password: %d %d\n", maj_stat, min_stat);
return(cred);
}
Now i am printing the major status(gssapi level status) and minor status(mechanism level status)- which is Kerberos in this case. When i am giving the logged in user(i.e. asanyal) the status printf message gives 0 for both values(all goes well)
However when I use a different username(this one is registered in the Active Directory but I am not logged in as him) I am getting
majstat = 851968 and minstat = -1765328243
Further investigation revealed that this minor status message corresponds to the error
KRB5_CC_NOTFOUND Matching credential not found
I am certain I am passing correct credentials(username password) for the non logged in users)
Is this something wrong with GSSAPI internally(maybe its unable to get a ticket or something) or am I making some mistake?
Configuration used : Windows Active Directory (Windows Server 2008) and MIT kerberos libraries - version 4.0.1
Ok i figured it out, the GSS-API does not include any API calls to directly obtain TGT, ST. For that you need the krb api(in case of underlying kerberos mechanism). Typically you would need a function like:-
krb5_get_init_creds_password(context,&creds,principal,conn->passwd,NULL,NULL,NULL,NULL,opts)) //these are the arguments i specified in my program
along with certain context, credential cache and principal initialization parts.