How do I change linux user within C code? - c

How do I change the user that my c program identifies itself as?
A command-line tool I want to invoke automatically requires to be run as a specific user and won't work otherwise.
I have tried using setuid(0) but I still don't get the desired results.
The user I want to imitate is not 'root', but a normal unprivileged, shell-less user. I want to be able to run the binary logged in as the user nobody. I was able to concoct a solution as 'root' using:
su -ls /bin/bash -c /binary (superuser)
However I want to be able to achieve the same logged in as user nobody
Is there something I'm missing?

If anyone could just become root by putting setuid(0); in their program, Unix would be, well, Windows.
Some thoughts:
Running external command line tools from C is almost always a mistake.
If you really need this command line tool, does the tool really need root permission to work? If not, fix the tool (or go back to step 1 and incorporate the functionality into your own program).
If you really need the tool and it really needs root, consider setting up sudo permissions for it and running it via sudo.
Given the very basic question you're asking, you should not even attempt to write code that will run as root, so I've omitted any details about how to setup root permissions for your program.

You don't need to do anything on the C side. Just change the binary to be owned by the user you want to use, enable the setuid bit in the binary (chmod u+s), and you're all set!
(If you don't want any user to be able to run as your designated user willy-nilly, consider using sudo.)

To change the current userid:
Firstly, lookup the new userid using getpwnam(). This returns a struct passwd *pw and a NULL value will indicate that user doesn't exit. The struct contains the userid (pw_uid) and the group id (pw_gid) which are needed to perform the change.
if((pw = getpwnam(userid)) == NULL)
sprintf(error_msg "Userid '%s' does not exist", userid);
Then set the group id for the new user
if (setgid(pw->pw_gid) != 0)
sprintf(error_msg "setgid() to %d failed", pw->pw_gid);
Finally, set the user id for the new user
if (setuid(pw->pw_uid) != 0)
sprintf(error_msg "setuid() to %d failed", pw->pw_uid);
Error recovery during this process is messy. The easiest way is to simply abort if either setgid() or setuid() fails. The real problem occurs if changing the group succeeds, but changing the user fails.

Related

How to set the SUID bit to grant root privileges?

my question is super beginner! In my C program, I want to set the SUID bit (root permission) before creating a raw socket and then I want to switch back to normal permission after I have created it. Before I used to run my code using command sudo ./client which gave the whole executable root permissions. I want to give root permissions only to the point where I create the socket, so that I can run my code using simply ./client.
EDIT: Realized that I have to set the SUID bit and not the sticky bit for how I want the executable to behave.
The original version of the question was confusing the sticky bit (S_ISVTX) with the SUID or set UID bit (S_ISUID). It has since been updated.
To make the program run with root privileges while creating the raw socket, you would create your executable by compiling it as normal, and then have root take ownership of the executable (chown root ./client) and set the permissions (chmod 4555 ./client). Note that the permissions are carefully chosen and do not allow either group or others to write to the program (modify the executable). The fact that the owner, root, has no write permission does not stop root from writing to the file — though root won't want to change it often. Normally, root would copy the program to some directory where ordinary users cannot make changes. That might conceivably be /usr/local/bin, or it might be somewhere else.
Note that the permissions are set on the executable, not the source code (see the original version of the question), and must be set before the program is run.
Inside the program, after creating the raw socket, you could remove the root privileges, thereby avoiding many security issues in the code after that, by executing: setuid(getuid()). This changes the effective UID back to the same as the real UID. Note that the POSIX specification for setuid()
says:
If the process has appropriate privileges, setuid() shall set the real user ID, effective user ID, and the saved set-user-ID of the calling process to uid.
A program that is SUID to root has 'appropriate privileges'; there is no going back. Using seteuid()
(as originally suggested) would not be as safe as using setuid().

How to create a file inside the `/etc` folder in Linux with C?

I'm writing a program in C that will have to check a configuration file every time it starts to set some variables.
At the first start of the program I suppose there won't be any configuration file, so I need to create it (with default settings).
I've been said configurations files of program belongs to the folder /etc, more specifically to a particular folder created on purpose for the program itself (i.e. /etc/myprog). Here comes the first question I should have asked: is it true? Why /etc?
In any case I tried to create that file using this:
open("/etc/myprog/myprog.conf", O_WRONLY | O_CREAT, 0644);
the open returns -1 and sets errno global variable to 2 (i.e. folder does not exist).
If I try to create the file straight inside /etc (therefore "/etc/myprog.conf" as first argument of the open) I get instead an errno set to 13 (i.e. permission denied).
Is there a way to grant my program permissions to write in /etc?
EDIT: I see most users are suggesting to use sudo. If possible I would have preferred to avoid this option as this file has to be created just once (at the first start). Maybe I should make 2 different executables? (e.g. myprog_bootstrap and myprog, having to run only the first one with sudo)
You need root privileges to create a file in /etc. Run your executable with sudo in front:
sudo executable_name
Another possibility might be to make your executable setuid. Your program would then call very appropriately the setreuid(2) system call.
However, be very careful. Programs like /bin/login (or /usr/bin/sudo itself) are coded this way, but any subtle error in your program opens a can of worms of security holes. So please be paranoid when writing such a code, and get it reviewed by someone else.
Perhaps a better approach might be to have your installation procedure make /etc/yourfile some symlink (created once at installation time to some writable file elsewhere) ....
BTW, you might create a group for your program, and make -at installation time- the /etc/yourfile writable to the group, and make your program setgid.
Or even, dedicate a user for your program, and have this /etc/yourfile belonging to that user.
Or, at installation time, have the /etc/myprog/ directory created and belonging to the appropriate user (or group) and being writable to that user (or group).
PS. Read also Advanced Linux Programming, capabilities(7), credentials(7) and execve(2)

Allow non-root application modify read-only file in /etc

I am trying to have an almost idiotproof configurator for network and some other stuff for embedded device running on linux. Application is saving to /etc/network/interfaces without problem when run by root, but returns "segmentation fault" when run by standard user. strace returned:
open("/etc/network/interfaces", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1 EACCES (Permission denied)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0} ---
How can I allow it to be launched by anyone and write to /etc/network/interfaces ?
Code for saving to file:
FILE *saveFile;
saveFile = fopen("/etc/network/interfaces","w");
// loopback
fprintf(saveFile, "auto lo \niface lo inet loopback\n\n");
// eth0
fprintf(saveFile, "auto eth0\niface eth0 inet static\n\taddress %s\n\tnetmask %s\n\tgateway %s\n",
address,netmask,gateway);
fclose(saveFile);
How can I allow it to be launched by anyone and write to /etc/network/interfaces ?
Mmmmm... By giving write permissions to anyone on /etc/network/interfaces ?
After your comment, your requirement is to allow a non root user to do a particular administrative tasks that would require root priviledge. The traditional way would be to make the program owned by root and setuid. This is now a throwned upon way, because a setuid program (su or sudo are) should be thoroughly scrutinized for any potential security problem: a buffer overflow or other would allow execution of arbitrary code as root.
For your example, if it is a simple program, it could make sense, but at least the return value of every operation (fopen and fwrite here) should be tested!
The recommended way for that will now be to use sudo and set specific entries in the /etc/sudoers file to allow any user (or a specific list of groups and/or users) to execute that specific command as root. To achieve almost the same that a setuid command but prompt the user for his/her password to notice him/her of an administrative task:
ALL local_host_name = (root) /full/path/to/command
But the sudoers syntax allow much finer grained authorizations.
(Beware: you still have to twice control your code)
you can try something like this :
install sudo
create a new user
Give sudo permission for the new user only on your program.
This way, when people will try to execute any command other than your program,it will be refused.
Now, your program will run with sudo rigth, so make sure that your program cannot be modified or replaced by another program (like chmod 700 and chown root) and make sure your program will not mess /etc/network/interface

Unix: Prevent delete on a user file from a user

[UNIX] Assume that there exists a user X (i.e. not a superuser), which belongs to a group G. This user X creates a file F in a directory, with permissions "rw-rw----".
Is there a way to prevent delete on this file from any user (except superusers), with a command issued by user X?
I found "chattr +a", but it can only be issued by superuser.
In other words, I am user X, member of group G, I own a file which must have permissions "rw-rw----". I want to prevent this file from deletion by myself and any other user of group G.
A possible solution is to provide a script owned by root and with setuid flag on. That script would only run egainst files located in a particular directory so as to avoid a confused deputy attack.
An other possibility that I did not explore is to use ACL's which provide more granularity than the standard rwx.
Maybe you are trying to solve the wrong problem ("I want to protect against accidental deletion of my own files").
The usual countermeasure is backups and/or archival. For single files I simply check them in with RCS, i.e. ci -l precious.txt each time I modify them. Note that this solution also solves the problem of accidental modifications, since you can checkout any earlier version with ease.
See the manuals for rcsintro(1), ci(1), co(1) and rcsdiff(1).

How to verify password on Unix (HPUX)

I'm writing a user daemon and when the user logs on, I want to make sure that the user is the one who started the daemon. Reason is, that I need some way of running commands which can take a lot of time. Using nohup for this has some drawbacks, like I can not interact with the process anymore, so the daemon should watch these processes and allow me to interact with them.
The problem now is, how can I verify the password, as the user will not have permission to read the shadowfile and the /etc/passwd passwort is not set.
You could use the PAM to check the user / passwd. It's also present in Unix systems. You should check the interfaces which are implemented in HPUX.
https://www.ibm.com/developerworks/linux/library/l-pam/
Im not sure on how to do daemons, but I do know that in C, all you would have to do is, create a string and check whether or not that is what the user types in.
have it accept what the user sets:
// accept
printf("1. login \n 2. create information ");
this gives them the option, then switch the options, case 1 being the information for logging in, and then case 2 being the option that allows them to type in the information, and you saving it in something to be read later, and determining if it already created or not.
Hope this helps!

Resources