I am trying to write a simple C program that creates directories (a mkdir clone.). This is what I have so far:
#include <stdlib.h>
#include <sys/stat.h> // mkdir
#include <stdio.h> // perror
mode_t getumask()
{
mode_t mask = umask(0);
umask (mask);
return mask;
}
int main(int argc, const char *argv[])
{
mode_t mask = getumask();
printf("%i",mask);
if (mkdir("trial",mask) == -1) {
perror(argv[0]);
exit(EXIT_FAILURE);
}
return 0;
}
This code creates directory with d--------- but I want it to create it with drwxr-xr-x like mkdir do? What am I doing wrong here?
You seem to be misunderstanding what umask is used for. It sets/retrieves the process's file mode creation mask, which in turn is used to turn off bits in the file mode you specify in calls like mkdir, like this (pseduo-code):
real_mode = requested_mode & ~umask
So in your code, since you pass in the value of the umask itself, you end up specifying permissions as zero, which is exactly what you see.
Instead, you should specify the permissions you want in the call to mkdir, like this:
mkdir("trial", 0755)
As Eric says, umask is the complement of the actual permission mode you get. So instead of passing mask itself to mkdir(), you should pass 0777-mask to mkdir().
Disclaimer: I extracted this answer from the OPs question. Answers should not be contained in the question itself.
Answer provided by yasar:
This is the working solution for me:
int main(int argc, const char *argv[])
{
if (mkdir("trial",0777) == -1) {
perror(argv[0]);
exit(EXIT_FAILURE);
}
return 0;
}
Setting right permissions according to umask is automatically handled. So I only needed to call mkdir with full permissions, and that gets chopped according to current umask.
Related
I have a question, here is my original code in the testchdir.c file:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
if (argc < 2)
{
printf("Usage: %s <pathname\n",argv[0]);
exit(1);
}
if (chdir(argv[1]) == 0)
{
printf("success in chdir\n");
return 0;
}
else
{
printf("error happened");
exit(1);
}
}
In my Linux system, my original path is /home/Tom3543, then when I compile my codes above using gcc -o testchdir testchdir.c, it looks good. Later on, I want to change my path and execute the program, so I type
./testchdir /home/tom3543/C++
"success in chdir" appeared in my terminal, but my path is still /home/Tom3543 in my terminal. Can someone help me explain why? I am confused about that!
It's because the shell starts a new process for your program, and you only change the current directory in that new process. The shells process will be unaffected.
Unfortunately (for you) there's no real good (or legal) way to change the working directory of the parent process (the process of the shell).
Using a c program I need to find and delete all symbolic links in a directory, with missing target.
What is the most efficient way to check whether the target of a symbolic link exist or not. Any method other than opening the symlink and check the return value. I'm working with linux and gcc.
stat or access, or indeed open. That's about all you can do.
From the man 3 stat man page
If the named file is a symbolic link, the stat() function shall continue pathname resolution using the
contents of the symbolic link, and shall return information pertaining to the resulting file if the
file exists.
So the following works nice:
#include <sys/stat.h>
#include <stdio.h>
int main() {
struct stat ctx;
int status = stat("test.txt", &ctx);
if(status != 0) {
perror("[stat]");
return 1;
}
else {
puts("works nice");
}
return 0;
}
The access () function with F_OK mode set will follow a symlink path.
The following code will print "Yes!" if both the symlink and the target file exist...
#include <stdio.h>
#include <unistd.h>
int
main (void)
{
if (access ("test.txt", F_OK) != -1) {
puts ("Yes!");
return 0;
}
puts ("No.");
return 1;
}
With chmod I can assign permissions like
chmod(file, S_IRUSR);
Is there a way to only take away the read permission from the user?
I've tried
chmod(file, !S_IRUSR);
and
chmod(file, -S_IRUSR);
Neither work.
You can't change individual permission bits using chmod(2) like you can with the command-line utility. You can only set a new complete set of permissions.
To implement a change, you need to read them first, with stat(2), toggle the desired bits from the st_mode field, and then set them with chmod(2).
The following code will remove clear the S_IRUSR bit for test.txt, and set the S_IXUSR bit. (For brevity, error checking has been omitted.)
#include <sys/stat.h>
int main(void)
{
struct stat st;
mode_t mode;
const char *path = "test.txt";
stat(path, &st);
mode = st.st_mode & 07777;
// modify mode
mode &= ~(S_IRUSR); /* Clear this bit */
mode |= S_IXUSR; /* Set this bit */
chmod(path, mode);
return 0;
}
I am doing a project in C, and I'm stuck on one thing, i need to check if the directoy "/var/log/PROJECT " exist, if not, my program must create it, the aplication will always run on super user, this is what im doing:
struct stat st = {0};
if (stat("/var/log/project/PROJECT", &st) == -1) {
printf("im creating the folder\n");
mode_t process_mask = umask(0);
int result_code = mkdir("/var/log/project/PROJECT", 0777);
umask(process_mask);
}else{
printf("exist\n");
}
Sorry for asking to "do my homework" but im really stuck...
Well, I'm going to run with my suspicion. If the problem is that the parent directory of the directory you're trying to create does not exist, the solution is to create the parent directory before it. This is not terribly difficult to do with recursion, thankfully. Try this:
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int create_directory_with_parents(char const *pathname, mode_t modus) {
struct stat st;
if(stat(pathname, &st) == -1) {
// If the directory does not yet exist:
//
// Make sure the parent directory is there. dirname() gives us the name of
// the parent directory, then we call this very function recursively because
// we are, after all, in a function that makes sure directories exist.
char *path_cpy = strdup(pathname);
char *dir = dirname(path_cpy);
int err = create_directory_with_parents(dir, modus);
free(path_cpy);
// If we were able to make sure the parent directory exists,
// make the directory we really want.
if(err == 0) {
mode_t process_mask = umask(0);
int err = mkdir(pathname, modus);
umask(process_mask);
}
// err is 0 if everything went well.
return err;
} else if(!S_ISDIR(st.st_mode)) {
// If the "directory" exists but is not a directory, complain.
errno = ENOTDIR;
return -1;
}
// If the directory exists and is a directory, there's nothing to do and
// nothing to complain about.
return 0;
}
int main(void) {
if(0 != create_directory_with_parents("/var/log/project/PROJECT", 0777)) {
perror("Could not create directory or parent of directory: ");
}
}
The recursion ends when the first parent directory is found that exists; that is with / at the latest.
One limitation of this implementation is that all parent directories will have the same access rights as the leaf directory, which may or may not be what you want. If this is not what you want, you'll have to change the modus parameter in the recursive call to create_directory_with_parents. How to pass several modus parameters for several layers of parent directories that may have to be created is something of a design question that depends on what exactly your needs are, so I cannot give a general answer to it.
Why not just execute the mkdir command anyway, and simply ignore the error it will produce if the directory already exists? This will save you playing around with stat.
Is there a reason you need the file permissions to be 777? If not, you can drop the umask bit too.
In order to protect an application from begin used wrongly, I'm trying to check that its configuration files have correct permissions, so that the application can trust the content of the files not being modified by someone else.
I believe the following rules are corrects:
the file must not be writable by others
the file must be owned by a trusted user/group: root
or
the file must be owned by the effective user/group running the application (think of setuid program)
Here an example:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
static
int is_secure(const char *name)
{
struct stat st;
uid_t euid = geteuid();
gid_t egid = getegid();
if (stat(name, &st) != 0) {
int err = errno;
fprintf(stderr, "can't stat() '%s': %d (%s)\n", name, err, strerror(err));
return 0;
}
/* writable by other: unsecure */
if ((st.st_mode & S_IWOTH) != 0) {
return 0;
}
/* not owned by group root and not owned by effective group: unsecure */
if (st.st_gid != 0 && st.st_gid != egid) {
return 0;
}
/* not owned by user root and not owned by effective user: unsecure */
if (st.st_uid != 0 && st.st_uid != euid) {
return 0;
}
return 1;
}
int
main(int argc, char *argv[])
{
int i;
for(i = 1; i < argc; i++) {
printf("'%s' : %s\n", argv[i], is_secure(argv[i]) ? "sure" : "unsure");
}
return 0;
}
Since I'm not sure about my assumptions, can someone check if I leave some loophole in the file permissions check.
Update
sudo has a function for that: sudo_secure_path, it only check for one uid/gid, but it take care of checking for group write bit.
Regards.
Your rules and your code look correct to me, although you should be aware of the following security risks that could still affect your implementation.
An attacker with physical access to the machine or NFS/SMB access could mount the file system with a box that has root privileges, and then modify your file.
A vulnerability in another program being run as either the trusted user or root could allow that program to be exploited to modify your file.
All it would take to break your security check would be a careless user or sys-admin that messes up the privilege settings of the file. I've seen this happen during backups and copies to thumb drives, etc.
Also make sure the file is not executable. I can't think of an instance where this could be exploited on a config file, but the general rule with security is don't give any privileges that aren't required for the job.
As you can see these are not issues under control of your code. Therefore, you should make sure you client is aware of these risks before assuring them of the non-tamperability of the config file.
I believe you also want to check permissions on the directory.
A user would be able to mv another file belonging to the correct user to replace this one, if they are allowed to write to the directory.
Something like:
sudo touch foo.conf
sudo touch foo.conf-insecure-sample
mv -f foo.conf-insecure-sample foo.conf