I have a server component that reads its configuration from a file. The configuration file is also read and written by an administration component. The components are separate programs, and they will be running under separate accounts. I want to change the ACL on the configuration file to:
application: read
administration: read and write
Its important to drop write from the application because the application opens a listening socket. That is, its high risk and I want to contain it as much as possible.
After some searching, it looks like ioctl is used to do it in C. ioctl_list offers a list of control codes but its not apparent to me how to add two users with different permissions on the configuration file. The man page online at die.net does not discuss the permissions in-depth or offer sample code. For example the word "perm" (root of "permission") only shows up once in the discussion.
On Windows, reducing permission to honor least privilege is drawn out but its pretty straight forward (Richter gives good examples in his Advanced Windows programming series).
How does one change permissions on a linux file using C APIs? What control codes are to be used?
Thanks in advance.
This is not done with ioctl, but rather with dedicated system calls: chmod, chown, and chgrp for the basic user/group/other set of file permissions, and acl_* for full-fledged ACLs. You probably also want to know about the setuid, setgid, and setgroups system calls, which are how you drop privileges in a running application.
You can accomplish your goals using only the basic user/group/other permissions. Configure your system as follows:
The server application has a dedicated user ID and group; let's say they are both named nlserver ("nl" for "noloader").
The administrative component also has a dedicated user ID and group, let's say nladmin.
The configuration file is set to be mode 0640 (aka -rw-r-----) and owned by user nladmin, group nlserver. (The code responsible for doing this should be in the administrative component, not the server itself.)
When the server starts up, after doing everything it needs to do as root (e.g. bind low-numbered ports), it uses setgroups, setgid, and setuid (IN THAT ORDER!) to change to user nlserver, group nlserver, and clear the supplementary groups list. Only after doing so does it open the configuration file.
Related
Is it possible to use a set of C library or system calls to drop all user privileges on POSIX, or at least on Linux? Note that I am not asking how to drop root privileges, which is what all of the other StackOverflow search results seem to be asking and answering.
I want the same effect as switching to user nobody, but stronger if possible. That is, I want my C application to do the following:
Run as a normal user, not root, and without the setuid file permission bit
Retain the ability to access specific files and open outgoing network connections
Voluntarily and permanently lose the ability to read and write files in specified (or all) directories, especially $HOME
If possible, give up or sandbox all other nonessential abilities, like opening a listening socket with accept
Things I have considered so far that don't fit the bill:
Switching to user nobody with setuid/setgid
Ordinary users are forbidden from switching to other users (like nobody), and the application should not require root just to switch to nobody.
Linux/POSIX.1e Capabilities
Capabilities only add root-like privileges, not take away ordinary user privileges
Traditional seccomp
My application will need more than just exit, sigreturn, read, and write
Things that look interesting, but for which I couldn't find documentation, appear to be unmaintained, or appear to be non-portable:
seccomp-bpf
AppArmor
grsecurity RBAC/role-based access control
So is there a well-documented, preferably portable way to drop nonessential user privileges and sandbox a process without having to become root first?
It's unlikely any solution will work on all POSIX, since POSIX doesn't define the mechanism you're looking for.
Looking at just the requirements and just Linux, probably the easiest way to satisfy them is actual via the security modules. Any of apparmor, selinux, RBAC will do what you need, but only via external profile - not something built into your app. The problem may be that adding a profile in all those cases requires the root user to do it (but the profile applies to user process too).
A bit more complicated solution that almost satisfies the requirements is seccomp. While it doesn't understand paths at all (you can only see pointers), there are ways to limit the access: seccomp policies can be defined per thread, so you could redesign your system to have a "path verification thread", which doesn't do anything apart from reading paths and returning sockets if they match your specification. Then limit that thread to just recv(), open() and send(). Thread doing other work can then drop open() and use the other service.
Or if you can configure the paths at program startup, you can put them into an array, mark that page as read-only, and setup seccomp policy which will only accept open() with filenames from that array (that's just a pointer comparison in that case).
To some extent, the approach of splitting application into separate processes which have very limited responsibilities is something you could replicate on other systems, but without the same guarantees as on Linux. For example qmail is kind of a system of very small processes which work as a pipeline for data (simplification). On Linux you could still apply seccomp to them, on Solaris just drop exec and other capabilities, on other systems... I don't know, but probably you can do something.
With Windows' Win32 API it's possible to create files and assign to them proper security permissions (e.g. some users can read from and write to the file, other users in another group can only read but not write, etc.), using CreateFile() and its SECURITY_ATTRIBUTES parameter.
Does Linux offer something similar? Which functions and data structures should be used for that purpose?
(I can be missing something, but the classical C fopen() does not seem to offer a similar security permission setting feature...)
EDIT
Just to clarify, I'm looking for something like Windows ACL.
Most recent file systems under Linux support ACL.
However ACL support needs to be enabled via the according entry to /etc/fstab, when mounting the file-system.
To get and set ACL from the command line use
getfacl
setfacl
On how to access ACL programmatically see man 5 acl.
If your looking for file attributes and ownership, there's chmod() or fchmod() and chown() or fchown(). There's also SELinux which has setfilecon() and a few other API functions. Just note that not every Unix computer has SELinux enabled.
My application creates a rudimentary ACL and communicates this to a Kernel Module. The ACL contains a list of UID/GID. The checks on these IDs are custom and on top of what the system already provides.
Now if the root/user changes UID/GID the ACL needs to be refreshed. Is there a way to get notification in an application whenever UID/GID changes e.g. through usermod command? Right now the platform is Linux but we could be porting this to other platforms as well(AIX/Solaris)
I'd say there is no way to reliably detect a change in the UID/Username mapping, especially when you go cross-platform. The user database may reside in NIS, NIS+, or nowadays, LDAP. They might be integrating their UNIX/Linux systems with a Windows Server running Active Directory, or they might be using something more obscure like Hesoid. I know of no way to receive any automatic feedback from these various databases. But also, any good book on UNIX Administration will tell you to not change these mappings, or at the very least, if you must, don't ever re-use a UID. Don't forget, the filesystem whether it's using standard POSIX permissions or POSIX ACLs will also be storing UIDs that won't be getting updates if an Administrator decides to change the UID for a user. The Kernel and filesystem both treat a specific UID as a specific user, regardless of their username. I really don't think you need to bother with the case of an Administrator changing UIDs for a user, it's likely to be too error prone for everyone.
Also, a quick look at NTFS on Windows will reveal that it also stores the equivalent of a UID called SID, it'a a long number used to represent a user and Windows does not provide or expect you to be changing the mapping of that SID to a specific Username. The SID is what the NT Kernel uses internally, not a username. If I open up the Security tab on a file, for a split second I may see numbers until Windows is able to query the Active Directory Controller and give convenient usernames to those numbers. Ultimately, it's the SID, not username that uniquely identifies the user.
On Linux, inotify does what you want. On other systems, try FAM.
One possible way (triggered from Frédéric's reply) is that I could possibly set a inotify/(dnotify gasp! for older kernels) operation on /etc/passwd because that file will always change for at least any change in local user privileges. Trouble is how to do this in NIS environment.
In the typical Unix security model, you should only care about the numerical value for GID/UID, not the mapping between human-readable string and numeric value. As that seems to be the case, have you carefully considered what you are trying to accomplish? Maybe it would be better to pass the name or a name/id tuple, instead of just the id?
I need to write a C program that will allow me to read/write files that are owned by root. However, I can only run the code under another user. I have the root password, but there are no "sudo" or "su" commands on the system, so I have no way of accessing the root account (there are practically no shell commands whatsoever, actually). I don't know a whole lot about UNIX permissions, so I don't know whether or not it is actually possible to do this without exploiting the system in some way or running a program owned by root itself (with +s or whatever). Any advice?
Thanks!
P.S. No, this isn't anything malicious, this is on an iPhone.
Under the UNIX permissions system, you need to run a file owned by root itself that's marked setuid-root (+s, as you said) or communicate with some process that is already running as root.
If there is no such file, you are out of luck.
You can do this with setting suid bit to application, but if you want from this c application run a some shell this was be runned on local user if you do it normally this is security system.
However you can read/write/execute files owned by root, but if your user is not in group of file your target file must have setted read/write/execute on last 3 bits or when your user is in file owner group you must check/apply this to 3 bits in middle position. (3 first bits setting permission to owner but this may not by a usable information for you).
If you dont have any access to root account. Then if group and other user permissions dont access functions as you must have, you can't do with this anything except trying get some prilveaged user for access this file. In other cases you can do some fixes in file access permissions but not from this system, you must get hard drive from this device and attach to other to change it or load on this device some live system to change this. However you can do this on privleaged system not on this.
More information about SUID bits you can find at:
http://www.codecoffee.com/tipsforlinux/articles/028.html
http://www.everyjoe.com/newlinuxuser/explain-what-is-setuid-and-setgid/
The iPhone SDK doesn't allow this. Your application is sandboxed and it is not allowed to go outside of that sandbox except in very specific ways provided by Apple. The only way to do this on an iPhone is to jailbreak it.
I have written a cgi-bin application in C that runs in a browser and allows the user to open an interactive shell and view & edit files on a Linux machine. It runs as the standard apache "www-data" user. I just added a login screen to it where the user types in their name and password (in a form) but I cannot authenticate the user using getspnam since this function only works when running as root.
What options do I have to check the login credentials of a user when not running as root?
PS: In my interactive shell I can type "su root" and then type in my password and it does elevate to root fine so it obviously can be done interactively.
I think you want to take a look at Pluggable authentication modules. AFAIK, PAM handles all the messy stuff for you and you just need to do a few function calls to authenticate the user on whatever the backend to authenticate users on the Linux host is (be it shadow passwords, nis, ldap, whatever)
Here's a short guide about integrating your C code with them.
With regard to your PS: Well, when you do a su root you're switching to the root user. So yes, of course, root can read the shadow file, you all ready said that.
With regard to your problem: Can't you have your apache processes temporarily elevate to root (by calling setuid or similar) to perform the authentication?
Good luck!
As suggested, I think PAM is the modern way to do this. But if you want to go old school, you need to create a setuid-root program (not a script) to do your authentication.
There are lots of gotchas with setuid-root programs, which is why PAM is likely better.
Here's a link to some good papers on safely writing setuid-root programs.