create file and assign permissions - c

It seems as though whatever I put as PERMS the file created has the same permissions - rwx r-x r-x
I tried 755 and 777 and the permissions just stay the same.
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#define PERMS 0777
int main(int argc, char *argv[])
{
int createDescriptor;
char fileName[15]="Filename.txt";
if ((createDescriptor = creat(fileName, PERMS )) == -1)
{
printf("Error creating %s", fileName);
exit(EXIT_FAILURE);
}
if((close(createDescriptor))==-1)
{
write(2, "Error closing file.\n", 19);
}
return 0;
}

I think you might need to change the umask before calling creat:
umask(0000);
See man 2 umask. The default umask is often 0022 which would exactly make the difference between 0777 and 0755 vanish.

Try chmod function. For more detais just right click in the IDE and type chmod.
NAME:
chmod - change mode of a file
SYNOPSIS:
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
DESCRIPTION:
The chmod() function shall change S_ISUID, S_ISGID, [XSI] S_ISVTX, and the file permission bits of the file named by the pathname pointed to by the path argument to the corresponding bits in the mode argument. The application shall ensure that the effective user ID of the process matches the owner of the file or the process has appropriate privileges in order to do this.
S_ISUID, S_ISGID, [XSI] S_ISVTX, and the file permission bits are described in <sys/stat.h>.
If the calling process does not have appropriate privileges, and if the group ID of the file does not match the effective group ID or one of the supplementary group IDs and if the file is a regular file, bit S_ISGID (set-group-ID on execution) in the file's mode shall be cleared upon successful return from chmod().
Additional implementation-defined restrictions may cause the S_ISUID and S_ISGID bits in mode to be ignored.
The effect on file descriptors for files open at the time of a call to chmod() is implementation-defined.
Upon successful completion, chmod() shall mark for update the st_ctime field of the file.
RETURN VALUE:
Upon successful completion, 0 shall be returned; otherwise, -1 shall be returned and errno set to indicate the error. If -1 is returned, no change to the file mode occurs.
More information can be found at this link.

Related

Why can't I open my file using open method?

Why can't I open my file using open method?
this is my source code:
char* dest;
char cwd1[256];
if (getcwd(cwd1, sizeof(cwd1)) == NULL)
perror("getcwd() error\n");
else
dest=cwd1;
char* destPlus=strcat(dest,"/");
char*myPathName =strcat(destPlus,fileName);
printf("the path name1: %s \n",myPathName);
char* outputPathName=myPathName;
int d;
// FILE* fd;
if(append)
d= open(outputPathName, O_WRONLY, O_APPEND | O_CREAT|O_WRONLY|O_TRUNC);
else
d= open(outputPathName, O_WRONLY,O_CREAT|O_WRONLY|O_TRUNC);
if(d<0){
printf("hello, there's an error with your file, plz check it out\n");
return;
}
in this code d will be negative, why?
Note: the path is true I check it, the error Number is 2
Both uses of open are wrong:
if(append)
d= open(outputPathName, O_WRONLY, O_APPEND | O_CREAT|O_WRONLY|O_TRUNC);
else
d= open(outputPathName, O_WRONLY,O_CREAT|O_WRONLY|O_TRUNC);
open() takes three arguments - the const char *path, the int oflag, and the variable argument mode_t mode, which is only used for newly-created files to specify the most-permissive access mode that can be used for the file (as modified by the process's umask setting). mode only needs to be supplied when O_CREAT is set in in the oflag flags variable.
You are misusing both the oflag and mode argument.
A proper use of open() would be something like this:
if(append)
d= open(outputPathName, O_WRONLY|O_CREAT|O_APPEND, 0644 );
else
d= open(outputPathName, O_WRONLY|O_CREAT, 0644 );
Per [POSIX open() documentation](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/open.htm
SYNOPSIS
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag, ...);
int openat(int fd, const char *path, int oflag, ...);
DESCRIPTION
The open() function shall establish the connection between a file and
a file descriptor. It shall create an open file description that
refers to a file and a file descriptor that refers to that open file
description. The file descriptor is used by other I/O functions to
refer to that file. The path argument points to a pathname naming the
file.
The open() function shall return a file descriptor for the named file,
allocated as described in File Descriptor Allocation. The open file
description is new, and therefore the file descriptor shall not share
it with any other process in the system. The FD_CLOEXEC file
descriptor flag associated with the new file descriptor shall be
cleared unless the O_CLOEXEC flag is set in oflag.
The file offset used to mark the current position within the file
shall be set to the beginning of the file.
The file status flags and file access modes of the open file
description shall be set according to the value of oflag.
Values for oflag are constructed by a bitwise-inclusive OR of flags
from the following list, defined in <fcntl.h>. Applications shall
specify exactly one of the first five values (file access modes) below
in the value of oflag:
O_EXEC Open for execute only (non-directory files). The result is
unspecified if this flag is applied to a directory.
O_RDONLY Open for reading only.
...
O_CREAT If the file exists, this flag has no effect except as noted
under O_EXCL below. Otherwise, if O_DIRECTORY is not set the file
shall be created as a regular file; the user ID of the file shall be
set to the effective user ID of the process; the group ID of the file
shall be set to the group ID of the file's parent directory or to the
effective group ID of the process; and the access permission bits (see
<sys/stat.h>) of the file mode shall be set to the value of the
argument following the oflag argument taken as type mode_t
modified as follows: a bitwise AND is performed on the file-mode bits
and the corresponding bits in the complement of the process' file mode
creation mask. Thus, all bits in the file mode whose corresponding bit
in the file mode creation mask is set are cleared. When bits other
than the file permission bits are set, the effect is unspecified. The
argument following the oflag argument does not affect whether the
file is open for reading, writing, or for both. Implementations shall
provide a way to initialize the file's group ID to the group ID of the
parent directory. Implementations may, but need not, provide an
implementation-defined way to initialize the file's group ID to the
effective group ID of the calling process.

Is it possible to change open file descriptor's access flags of another process using any system calls or even using loadable kernel module?

I am running a process (Process A) which opens a file with read only access mode. Then it pauses, causing the process to stay running and keep the file descriptor open. Later, if any of the below is possible, it will resume after some time and continue operation.
I want to know if any of these are possible:
Can we create another process (Process B) with superuser privileges, which can access Process A's open file descriptor and change its access mode to read and write ?
Can we modify the file descriptor of Process A, from within the process (I mean within its code) from read only to read and write?
Can I create a loadable kernel module that access the process A using its process ID (PID) and check for open file descriptors and change their permissions to read and write?
I have searched the forums countless number of times, but didn't find anything specific to my problem. I also found out about the fcntl() system call. But this doesn't allow us to modify the status flag of a file descriptor.
You can't. Permissions are locked in place at the time when a file descriptor is opened and it would be almost impossible to ensure the security of the system if they could be changed at run time. You could make a kernel module that changes this, but it would pretty much be a death sentence to the stability and security of the system.
What you can do and what is normally done is to open the file again with different permissions and replace the file descriptor with dup2.
3 first, since it's easiest: Can it be done in the kernel? Certainly … in theory, you can do “almost anything” there.
Both #2 and #1 come down to the question as to whether the file descriptor is re-openable.
In the most common case — the fd refers to a regular file stream in the local filesystem, the pathname of which has a directory link to which has not been altered — you can simply open the same pathname from another process. EG: If A opens /home/user/foo.log read-only, then either A or B can simply open the same pathname read-write in future.
Since you're asking, I'll assume it's not that easy. Perhaps the pathname may have been altered (eg, the file may have been unlinked), or perhaps the fd is a reference to another type of stream, like a shell pipeline, FIFO, or network socket connection.
As you probably noticed, fcntl does not allow escalation of privileges:
F_SETFL (int)
Set the file status flags to the value specified by arg. File
access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation
flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are
ignored.
This is, of course, a security precaution to protect against escalation of privileges in a process that may have opened the file under temporarily elevated or changed permissions.
However, it seems that you may have a chance to open a new, duplicate stream based upon a pathname if you know the file descriptor number and the process ID of Process A.
The /proc filesystem contains virtual file entries which represent open streams. Under /proc/ pid /fd/ fd you can find a pathname to the currently-open stream. Given sufficient permissions, you can open that stream.
reader.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char** argv) {
FILE* f = fopen("/tmp/foo", "r");
while(1) {
sleep(10);
}
}
writer.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main (int argc, char** argv) {
/* sane PID passed in */
if (2 != argc) exit(1);
if (5 > strlen(argv[1])) exit(2);
for(size_t ci = 0; argv[ci]; ++ci) {
if (! ( ('0' <= argv[1][ci]) && (argv[1][ci] <= '9') ) ) exit(3);
}
/* note we know FD=3 so it's hard-coded */
char path[100];
int n = snprintf(path, 99, "/proc/%s/fd/3", argv[1]);
if (n < 0) exit (4);
FILE* f = fopen(path, "rw+");
fprintf(f, "written\n");
exit(0);
}
shell test
⇒ cc reader.c -o reader
⇒ cc writer.c -o writer
⇒ echo XXXXXXXXXXXX > /tmp/foo
⇒ cat /tmp/foo
XXXXXXXXXXXX
⇒ ./reader &
[1] 20709
⇒ ./writer 20709
⇒ cat /tmp/foo
written
XXXX

Why can't my program set 0777 mode with the mkdir system call?

I wrote following code to try to create a directory with 0777 mode on Linux:
#include <sys/stat.h>
#include <sys/types.h>
int main () {
mkdir("/tmp/mkdir-test", 0777);
return 0;
}
But actually, the new directory has 0755 mode.
# stat /tmp/mkdir-test
File: `/tmp/mkdir-test'
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 802h/2050d Inode: 1772304 Links: 2
Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2016-09-27 20:23:54.000000000 -0700
Modify: 2016-09-27 20:23:54.000000000 -0700
Change: 2016-09-27 20:23:54.000000000 -0700
Can someone explain this? And how can the program create a real 0777 mode directory?
Run umask in the shell; it will report 022. The bits set in the umask value are removed from permissions when creating files or directories.
In a single-threaded program, one way to really set 0777 permissions is to dink with umask():
mode_t old_mask = umask(0);
mkdir("/tmp/mkdir-test", 0777);
umask(old_mask);
That preserves the current setting except when you are sure you need to override it. However, this is dangerous in multi-threaded programs because the umask value is global per-process, not per-thread (and thanks to Peter Cordes for pointing this out).
The other option for setting the permissions is to use chmod(), and doing so is safe with multi-threaded programs too:
const char *dirname = "/tmp/mkdir-test";
mode_t target_mode = 0777;
if (mkdir(dirname, 0) == 0)
chmod(dirname, target_mode);
The permissions set by the chmod() function are not affected by umask values.
The permissions on the call to mkdir() are probably best set to 0 as shown; it will always work reliably and doesn't risk affecting other threads by modifying the umask value. Alternatively, you could use the desired target permissions in the call to mkdir() if you wanted to (and a previous version of this answer suggested doing so, using 0777 as the hard-coded target permissions).
const char *dirname = "/tmp/mkdir-test";
mode_t target_mode = 0777;
if (mkdir(dirname, target_mode) == 0)
chmod(dirname, target_mode);
If you use this idiom, it is important that the mode passed to mkdir() is the same as, or less permissive than, the mode passed to chmod() — and 0 is less permissive than any other mode (and always works).
If you use a more relaxed mode in the call to mkdir(), there's a TOCTOU (Time-of-Check, Time-of-Use) style vulnerability between the mkdir() and chmod() calls during which someone (some process) could get into the directory with relaxed permissions and wreak havoc; this could be a security risk.
Note that umask() is a very simple system call and therefore very quick too (as system calls go, compared with heavyweights such as open(), mkdir() or chmod()).
You can simply do it using the following code:
mkdirfile.cpp
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main() {
long result;
result = syscall(__NR_mkdir, "/tmp/mkdir-test", 0777);
printf("The result is %ld.\n", result);
return 0;
}
Then compile the code using gcc and run it:
gcc mkdirfile.cpp && ./a.out

Why are the file permissions changed when creating a file with the open system call on Linux?

I am creating a file with full permission (777) using the open system call, but when I do ls -l I can see only permission as (755). Could you please tell why file permission is not 777?
Code
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
int fd;
/* Creates a file with full permission*/
fd = open("test", O_CREAT | O_RDWR | O_APPEND, 0777);
if (fd = -1)
{
return -1;
}
close(fd);
}
Output
$ ls -l
-rwxr-xr-x 1 ubuntu ubuntu 0 2012-09-19 11:55 test
There's a value maintained by the system called the umask; it is a property of the process, just like the PID (process ID) or EUID (effective user ID) is. It will be set to 022 (octal), which indicates that the system should remove the group and other write permission from files that are created.
You can call umask(0); before using open() so that the mode you specify in open() won't be altered. You should certainly do this to demonstrate that umask is the issue. However, it is generally best to let the user's choice of umask prevail — I for one get very stroppy if a program doesn't obey my umask setting; it tends not to be used again after I spot and verify the problem.
The shell also has a (built-in) command umask which you can use. The 022 value is a sensible default; most of the time, you do not want just anybody writing to your files.
The permissions of a created file are restricted by the process's current umask -- your current umask is 022, so group and world write are always disabled by default. (Which is a good thing, in most cases.) If you really want a group- and world-writable file, you will need to temporarily set umask(0) while creating this file (make sure to save the old value returned by the system call, and set it back afterwards!), or "manually" set the file's permissions using chmod().
umask will return the original value of the mask, so to reset it temporarily you just need to do
#include <sys/types.h>
#include <sys/stat.h>
mode_t old_mask = umask(0);
...
umask(old_mask);
though it would be perhaps preferable to use fchmod after opening the file - this will avoid the problem of changing process-global state:
fd = open("test", O_CREAT | O_RDWR | O_APPEND, 0777);
if (fd < 0) { ... }
int rv = fchmod(fd, 0777);
if (rv < 0) { /* fchmod errored */ }

Getting the environment of a process running under a different user

Assume I have a process with PID 1234 running in the background under user A.
If I run the following program as user A, it succeeds. If I run it as user B, it fails with open: Permission denied.
This makes sense, as the environ file is owned by user A and has read permission only for A.
But if I make the program set-user-ID for user A and run it as user B, it fails with read: Permission denied. This doesn't seem to happen with a regular file having the same permissions. It also doesn't happen if A is root.
Any ideas why? Is there any other way to get the environment of another process that works around this issue?
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, const char *argv[])
{
unsigned char ch = 0;
int fd = -1;
int read_result = -1;
setresuid(geteuid(), geteuid(), geteuid());
fd = open("/proc/1234/environ", O_RDONLY);
if (-1 == fd) {
perror("open");
return EXIT_FAILURE;
}
read_result = read(fd, &ch, 1);
if (-1 == read_result) {
perror("read");
return EXIT_FAILURE;
}
close(fd);
return EXIT_SUCCESS;
}
As you can see, if your program run without SETUID, open(2) gives you Permission denied, whereas if you run the program with SETUID, open(2) works ok, but read(2) causes the same error. This happens because of additional permission check during each file operation on /proc/* inodes. Looks like this additional permission check uses something other than EUID of the running process. If you run GNU/Linux, for more details see NOTE at the beginning of the code in <kernel_source>/fs/proc/base.c and environ_read() function in the same file.
One of the possible quick solutions:
set owner of the program file to root
set owner group to some special group
add user that should run the program (user B) to that special group
set mode bits to 4550 (r-sr-x---)
call setuid(getuid()) to drop priveleges as soon as possible, i.e. right after reading environ file
In this case any user from the given group could read /proc/*/environ of any other user.
If you want to reduce the permissions of your program to allow only read environ files of the specific user (user A), you probably should think of some other tricks. For example config file, containing the user(s) whose environ file(s) could be read.
Always be careful with extra permissions. Especially with root permissions. Do necessary privileged operations and drop permissions as soon as possible.

Resources