Wednesday, August 20, 2014

Unix Prog: Files -- Permissions(2)

1. access function
Since effective userid/groupid may be different from the real userid/groupid, so the permission granting result is different by using effective and real id. System will use effective id to determine the permission, but user may want to use "real id" to test if the current process has permission.

definition:
R_OK, W_OK, X_OK, F_OK 4 bits are used on "access" to test if real id has the corresponding permission.
 ubuntu@ip-172-31-23-227:~$ less /usr/include/unistd.h  
 .......  
 /* Values for the second argument to access.  
   These may be OR'd together. */  
 #define R_OK  4        /* Test for read permission. */  
 #define W_OK  2        /* Test for write permission. */  
 #define X_OK  1        /* Test for execute permission. */  
 #define F_OK  0        /* Test for existence. */  
   
 /* Test for access to NAME using the real UID and real GID. */  
 extern int access (const char *__name, int __type) __THROW __nonnull ((1));  
 ......  

fileio.c:
For a given file, check its access permission by "access" and "open".
"access" is based on its real id permission.
"open" is based on its effective id permission.
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<fcntl.h>  
   
 int main(int argc, char* argv[])  
 {  
  if(argc != 2) {  
   printf("usage: io.out <pathname>\n");  
   exit(1);  
  }  
   
  if(access(argv[1], R_OK) <0 ) {  
   printf("access error!\n");  
  }  
  else {  
   printf("access read ok!\n");  
  }  
   
  if(open(argv[1], O_RDONLY) < 0) {  
   printf("open error!\n");  
  }  
  else {  
   printf("open ok!\n");  
  }  
   
  exit(0);  
 }  

shell:
1) We change the io.out owner to "root", which is user itself.
2) List all files, now io.out's owner is already root
3) Turn on the "set-user-id" on "io.out", then any process who executes this file will have the effective user id as "root", file's owner user id.
4) List all files, now io.out's "set-user-id" bit is already on.
5) Run ./io.out against ./test, right now for current process, real id is "ubuntu", effective user id is "root". For ./test, user's permission and group's permission is all off, only other's read permission is on.
So, "access" function will not access the file successfully, since its real user id is ubuntu. "open" function will access the file successfully, since its effective user id is "root", which falls into the "other" users.
 ubuntu@ip-172-31-23-227:~$ sudo chown root ./io.out  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu  97 Aug 21 02:05 fileio.c~  
 -rw-rw-r-- 1 ubuntu ubuntu 426 Aug 21 02:10 fileio.c  
 -rwxrwxr-x 1 root  ubuntu 9768 Aug 21 02:10 io.out  
 -------r-- 1 ubuntu ubuntu  0 Aug 21 02:16 test  
 ubuntu@ip-172-31-23-227:~$ sudo chmod u+s ./io.out  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu  97 Aug 21 02:05 fileio.c~  
 -rw-rw-r-- 1 ubuntu ubuntu 426 Aug 21 02:10 fileio.c  
 -rwsrwxr-x 1 root  ubuntu 9768 Aug 21 02:10 io.out  
 -------r-- 1 ubuntu ubuntu  0 Aug 21 02:16 test  
 ubuntu@ip-172-31-23-227:~$ ./io.out ./test  
 access error!  
 open ok!  

2. umask
The umask functoin sets the file mode creation mask for the process and returns the previous value.

definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/stat.h  
 ......  
 /* Set the file creation mask of the current process to MASK,  
   and return the old creation mask. */  
 extern __mode_t umask (__mode_t __mask) __THROW;  
 ......  

creation mask: if one specific mask bit is on, then for newly created file, corresponding permission bit will be turned off.

fileio.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<sys/stat.h>  
   
 int main(int argc, char* argv[])  
 {  
  // Enable all bits  
  umask(0);  
  if(creat("foo", S_IRWXU | S_IRWXG) < 0) {  
   printf("create error for foo\n");  
   exit(1);  
  }  
   
  // Disable group read and write bits  
  umask(S_IRGRP | S_IWGRP);  
  if(creat("bar", S_IRWXU | S_IRWXG) < 0) {  
   printf("create error for bar\n");  
   exit(2);  
  }  
   
  exit(0);  
 }  

shell:
1) Run the umask command at the shell, current mask value is 0002, which means disable the "other write" permission, to prevent others writing your file
2) run above program, it will create foo and bar files.
For foo file, since umask is setup to be 0, which means not "masking off" any bit. So its permission bit will be same as the one specified by creat system calls.
For bar file, since umask is setup to be group read and write bits, which means it will mask off these two bits. So its permission bits will be the one specified by creat system call "minus" bits set by umask command.
3) List these 2 files to prove that bits setup are right.
4) Run the umask command, the mask bits is still 0002. It means, ./io.out was run at the different process, and umask bits changed on that process doesn't affect umask bits at the shell process.
 ubuntu@ip-172-31-23-227:~$ umask  
 0002  
 ubuntu@ip-172-31-23-227:~$ ./io.out  
 ubuntu@ip-172-31-23-227:~$ ls -lrt foo bar  
 -rwxrwx--- 1 ubuntu ubuntu 0 Aug 23 12:31 foo  
 -rwx--x--- 1 ubuntu ubuntu 0 Aug 23 12:31 bar  
 ubuntu@ip-172-31-23-227:~$ umask  
 0002  

symbolic form of umask:
this is more easy to understand that which bit is turned off. In this case, other's write permission is masked off.
 ubuntu@ip-172-31-23-227:~$ umask -S  
 u=rwx,g=rwx,o=rx  
ubuntu@ip-172-31-23-227:~$ umask
0002

No comments:

Post a Comment