Chmod, Umask, Stat, Fileperms, and File Permissions

Unix file permissions are one of the more difficult subjects to grasp.. Well, ok maybe "grasp" isn't the word.. Master is the right word.. Unix file permissions is a hard topic to fully master, mainly I think because there aren't many instances when a computer user encounters them. Windows has been trying to figure it out for decades with little progress, so don't feel bad if you don't know much about it. Unless you're with the program and running Mac or any other BSD/Unix based OS you've never had the ability to secure your system in this most basic and fundamental way. Usually the first time someone encounters file permissions it's because their website was cracked..


$ chmod 604 .htaccess

604 -rw----r--  /web/askapache/cgi-bin/.htaccess


$ chmod 711 php.cgi

$ 711 -rwx--x--x  /web/askapache/cgi-bin/php.cgi


$ chmod 600 php.ini

$ 600 -rw-------  /web/askapache/cgi-bin/php.ini

I'm in the process of developing an updated version of the .htaccess security plugin, and one thing I have been working on is file permissions. Some people had problems trying to create files on their server and I realized it was bad programming on my part.. so I began researching permissions in detail. I went deep into the source code of Apache (which is why this site is called AskApache, BTW), PHP, Python, Ocaml, Perl, Ruby, and POSIX operating systems and got a pretty good handle on it now..

Tips before we dig in

Here's a few things I've learned that I didn't know before (using php).

Deleting Files and Directories

Deleting a file may require chmodding the file to 666 or even 777 before you are able to delete it. You also might have to chmod the parent directory of the file as well. Also, you may have to chdir to the directory the file is in. And lastly you may have to change the owner or group of the file. Further than that you can try renaming the file first then deleting it..

Deleting a directory means you need to remove every file in it first. It needs to be empty. And if your file system uses NFS or some other networked FS you might have even more problems deleting files. If the file you are trying to delete is being used by say, Apache or php then you might have to kill that process first.

Creating Files in Restrictive Environments

My research has been geared to try and make my code as robust as possible, I'm throwing everything but the kitchen sink into some of these functions because so many people are on such different types of servers. To create a file in a restrictive environment is a fun excercise to take.. You can write a file using many different functions, but there are some tricks if they all fail. One trick is instead of trying to "write" the data to the file, you can UPLOAD the data to the server and let PHP handle the file as if you used an upload form. I like to use fsockopen to do it, as some installations have been setup to prevent this type of fake upload.

Then there are the various other hacks like using an ftp connection (if you know the user/pass) to send the file from php, using ssh from php, whatever is available on the hosts php installation. In addition to those more involved workarounds you can often get around this problem by doing little hacks discussed at in the comments for various functions. Such as changing the umask, changing directories with chdir first, creating a temporary file using a function like tempfile and then renaming or copying the tempfile to your desired file which sometimes gives you the permissions needed to write to the location.

If the php installation is newer than you can also look into creating your own stream context to pass write the data direct.

Stat Function

I've created a stat function in php that goes farther than the normal stat function... Just give the function a file to stat, and it returns an array of information.

function askapache_stat($filename) {
 if(!$ss) die("Couldnt stat {$filename}");
 $t=decoct($ss['mode'] & 0170000);
 $str = (array_key_exists(octdec($t),$file_convert)) ? $file_convert[octdec($t)]{0} : 'u';

  'octal1'=>sprintf("%o", ($ss['mode'] & 000777)),
  'octal2'=>sprintf("0%o", 0777 & $p),
  'decimal'=>sprintf("%04o", $p),

  'type_octal'=>sprintf("%07o", octdec($t)),
  'is_readable'=> @is_readable($filename),
  'is_writable'=> @is_writable($filename)),

  'owner_name'=>(function_exists('posix_getpwuid')) ? @reset(@posix_getpwuid($ss['uid'])) : '',
  'group_name'=>(function_exists('posix_getgrgid')) ? @reset(@posix_getgrgid($ss['gid'])) : ''),

  'realpath'=>(@realpath($filename) != $filename) ? @realpath($filename) : '',

  'device'=>$ss['dev'], //Device
  'device_number'=>$ss['rdev'], //Device number, if device.
  'inode'=>$ss['ino'], //File serial number
  'link_count'=>$ss['nlink'], //link count
  'link_to'=>($s['type']=='link') ? @readlink($filename) : ''),

  'size'=>$ss['size'], //Size of file, in bytes.
  'blocks'=>$ss['blocks'], //Number 512-byte blocks allocated
  'block_size'=> $ss['blksize']), //Optimal block size for I/O.

  'mtime'=>$ss['mtime'], //Time of last modification
  'atime'=>$ss['atime'], //Time of last access.
  'ctime'=>$ss['ctime'], //Time of last status change
  'accessed'=>@date('Y M D H:i:s',$ss['atime']),
  'modified'=>@date('Y M D H:i:s',$ss['mtime']),
  'created'=>@date('Y M D H:i:s',$ss['ctime'])),

 return $s;

PHP Stat Function Output

Example output, say from print_r(askapache_stat( __FILE__ ) );

[perms] => Array
  [umask] => 0022
  [human] => -rw-r--r--
  [octal1] => 644
  [octal2] => 0644
  [decimal] => 100644
  [fileperms] => 33188
  [mode1] => 33188
  [mode2] => 33188

[filetype] => Array
  [type] => file
  [type_octal] => 0100000
  [is_file] => 1
  [is_dir] =>
  [is_link] =>
  [is_readable] => 1
  [is_writable] => 1

[owner] => Array
  [fileowner] => 035483
  [filegroup] => 23472
  [owner_name] => askapache
  [group_name] => grp22558

[file] => Array
  [filename] => /web/askapache/askapache-stat/public_html/ok/g.php
  [realpath] =>
  [dirname] => /web/askapache/askapache-stat/public_html/ok
  [basename] => g.php

[device] => Array
  [device] => 25
  [device_number] => 0
  [inode] => 92455020
  [link_count] => 1
  [link_to] =>

[size] => Array
  [size] => 2652
  [blocks] => 8
  [block_size] => 8192

[time] => Array
  [mtime] => 1227685253
  [atime] => 1227685138
  [ctime] => 1227685253
  [accessed] => 2008 Nov Tue 23:38:58
  [modified] => 2008 Nov Tue 23:40:53
  [created] => 2008 Nov Tue 23:40:53

Every Permission 0000 to 0777

chmod, umask, file permissions testThis shows what each numeric permission does to a REGULAR file. I'll provide the code to do this below so you can do the same thing on your server.

chmod 0
chmod 1
chmod 2
chmod 3
chmod 4
chmod 5
chmod 6
chmod 7
chmod 10
chmod 11
chmod 12
chmod 13
chmod 14
chmod 15
chmod 16
chmod 17
chmod 20
chmod 21
chmod 22
chmod 23
chmod 24
chmod 25
chmod 26
chmod 27
chmod 30
chmod 31
chmod 32
chmod 33
chmod 34
chmod 35
chmod 36
chmod 37
chmod 40
chmod 41
chmod 42
chmod 43
chmod 44
chmod 45
chmod 46
chmod 47
chmod 50
chmod 51
chmod 52
chmod 53
chmod 54
chmod 55
chmod 56
chmod 57
chmod 60
chmod 61
chmod 62
chmod 63
chmod 64
chmod 65
chmod 66
chmod 67
chmod 70
chmod 71
chmod 72
chmod 73
chmod 74
chmod 75
chmod 76
chmod 77
chmod 100
chmod 101
chmod 102
chmod 103
chmod 104
chmod 105
chmod 106
chmod 107
chmod 110
chmod 111
chmod 112
chmod 113
chmod 114
chmod 115
chmod 116
chmod 117
chmod 120
chmod 121
chmod 122
chmod 123
chmod 124
chmod 125
chmod 126
chmod 127
chmod 130
chmod 131
chmod 132
chmod 133
chmod 134
chmod 135
chmod 136
chmod 137
chmod 140
chmod 141
chmod 142
chmod 143
chmod 144
chmod 145
chmod 146
chmod 147
chmod 150
chmod 151
chmod 152
chmod 153
chmod 154
chmod 155
chmod 156
chmod 157
chmod 160
chmod 161
chmod 162
chmod 163
chmod 164
chmod 165
chmod 166
chmod 167
chmod 170
chmod 171
chmod 172
chmod 173
chmod 174
chmod 175
chmod 176
chmod 177
chmod 200
chmod 201
chmod 202
chmod 203
chmod 204
chmod 205
chmod 206
chmod 207
chmod 210
chmod 211
chmod 212
chmod 213
chmod 214
chmod 215
chmod 216
chmod 217
chmod 220
chmod 221
chmod 222
chmod 223
chmod 224
chmod 225
chmod 226
chmod 227
chmod 230
chmod 231
chmod 232
chmod 233
chmod 234
chmod 235
chmod 236
chmod 237
chmod 240
chmod 241
chmod 242
chmod 243
chmod 244
chmod 245
chmod 246
chmod 247
chmod 250
chmod 251
chmod 252
chmod 253
chmod 254
chmod 255
chmod 256
chmod 257
chmod 260
chmod 261
chmod 262
chmod 263
chmod 264
chmod 265
chmod 266
chmod 267
chmod 270
chmod 271
chmod 272
chmod 273
chmod 274
chmod 275
chmod 276
chmod 277
chmod 300
chmod 301
chmod 302
chmod 303
chmod 304
chmod 305
chmod 306
chmod 307
chmod 310
chmod 311
chmod 312
chmod 313
chmod 314
chmod 315
chmod 316
chmod 317
chmod 320
chmod 321
chmod 322
chmod 323
chmod 324
chmod 325
chmod 326
chmod 327
chmod 330
chmod 331
chmod 332
chmod 333
chmod 334
chmod 335
chmod 336
chmod 337
chmod 340
chmod 341
chmod 342
chmod 343
chmod 344
chmod 345
chmod 346
chmod 347
chmod 350
chmod 351
chmod 352
chmod 353
chmod 354
chmod 355
chmod 356
chmod 357
chmod 360
chmod 361
chmod 362
chmod 363
chmod 364
chmod 365
chmod 366
chmod 367
chmod 370
chmod 371
chmod 372
chmod 373
chmod 374
chmod 375
chmod 376
chmod 377
chmod 400
chmod 401
chmod 402
chmod 403
chmod 404
chmod 405
chmod 406
chmod 407
chmod 410
chmod 411
chmod 412
chmod 413
chmod 414
chmod 415
chmod 416
chmod 417
chmod 420
chmod 421
chmod 422
chmod 423
chmod 424
chmod 425
chmod 426
chmod 427
chmod 430
chmod 431
chmod 432
chmod 433
chmod 434
chmod 435
chmod 436
chmod 437
chmod 440
chmod 441
chmod 442
chmod 443
chmod 444
chmod 445
chmod 446
chmod 447
chmod 450
chmod 451
chmod 452
chmod 453
chmod 454
chmod 455
chmod 456
chmod 457
chmod 460
chmod 461
chmod 462
chmod 463
chmod 464
chmod 465
chmod 466
chmod 467
chmod 470
chmod 471
chmod 472
chmod 473
chmod 474
chmod 475
chmod 476
chmod 477
chmod 500
chmod 501
chmod 502
chmod 503
chmod 504
chmod 505
chmod 506
chmod 507
chmod 510
chmod 511
chmod 512
chmod 513
chmod 514
chmod 515
chmod 516
chmod 517
chmod 520
chmod 521
chmod 522
chmod 523
chmod 524
chmod 525
chmod 526
chmod 527
chmod 530
chmod 531
chmod 532
chmod 533
chmod 534
chmod 535
chmod 536
chmod 537
chmod 540
chmod 541
chmod 542
chmod 543
chmod 544
chmod 545
chmod 546
chmod 547
chmod 550
chmod 551
chmod 552
chmod 553
chmod 554
chmod 555
chmod 556
chmod 557
chmod 560
chmod 561
chmod 562
chmod 563
chmod 564
chmod 565
chmod 566
chmod 567
chmod 570
chmod 571
chmod 572
chmod 573
chmod 574
chmod 575
chmod 576
chmod 577
chmod 600
chmod 601
chmod 602
chmod 603
chmod 604
chmod 605
chmod 606
chmod 607
chmod 610
chmod 611
chmod 612
chmod 613
chmod 614
chmod 615
chmod 616
chmod 617
chmod 620
chmod 621
chmod 622
chmod 623
chmod 624
chmod 625
chmod 626
chmod 627
chmod 630
chmod 631
chmod 632
chmod 633
chmod 634
chmod 635
chmod 636
chmod 637
chmod 640
chmod 641
chmod 642
chmod 643
chmod 644
chmod 645
chmod 646
chmod 647
chmod 650
chmod 651
chmod 652
chmod 653
chmod 654
chmod 655
chmod 656
chmod 657
chmod 660
chmod 661
chmod 662
chmod 663
chmod 664
chmod 665
chmod 666
chmod 667
chmod 670
chmod 671
chmod 672
chmod 673
chmod 674
chmod 675
chmod 676
chmod 677
chmod 700
chmod 701
chmod 702
chmod 703
chmod 704
chmod 705
chmod 706
chmod 707
chmod 710
chmod 711
chmod 712
chmod 713
chmod 714
chmod 715
chmod 716
chmod 717
chmod 720
chmod 721
chmod 722
chmod 723
chmod 724
chmod 725
chmod 726
chmod 727
chmod 730
chmod 731
chmod 732
chmod 733
chmod 734
chmod 735
chmod 736
chmod 737
chmod 740
chmod 741
chmod 742
chmod 743
chmod 744
chmod 745
chmod 746
chmod 747
chmod 750
chmod 751
chmod 752
chmod 753
chmod 754
chmod 755
chmod 756
chmod 757
chmod 760
chmod 761
chmod 762
chmod 763
chmod 764
chmod 765
chmod 766
chmod 767
chmod 770
chmod 771
chmod 772
chmod 773
chmod 774
chmod 775
chmod 776
chmod 777


Here's my custom stat function, which I am definately not finished with, so check back in a couple days and if you find any improvements please hook me up with a comment!

function askapache_stat( $filename ) {
$t=decoct($s['mode'] & 0170000);

switch (octdec($t)) {
case 0140000: $str = 's'; $stat['type']='socket'; break;
case 0120000: $str = 'l'; $stat['type']='link'; break;
case 0100000: $str = '-'; $stat['type']='file'; break;
case 0060000: $str = 'b'; $stat['type']='block'; break;
case 0040000: $str = 'd'; $stat['type']='dir'; break;
case 0020000: $str = 'c'; $stat['type']='char'; break;
case 0010000: $str = 'p'; $stat['type']='fifo'; break;
default: $str = 'u'; $stat['type']='unknown'; break;

$stat['type_octal'] = sprintf("%07o", octdec($t));

$str .= (($p&0x0100)?'r':'-').(($p&0x0080)?'w':'-').(($p&0x0040)?(($p&0x0800)?'s':'x'):(($p&0x0800)?'S':'-'));
$str .= (($p&0x0020)?'r':'-').(($p&0x0010)?'w':'-').(($p&0x0008)?(($p&0x0400)?'s':'x'):(($p&0x0400)?'S':'-'));
$str .= (($p&0x0004)?'r':'-').(($p&0x0002)?'w':'-').(($p&0x0001)?(($p&0x0200)?'t':'x'):(($p&0x0200)?'T':'-'));

$stat['perm_octal1'] = sprintf( "%o", ( $s['mode'] & 00777 ) );
$stat['perm_octal2'] = sprintf("0%o", 0777 & $p);
$stat['perm_dec'] = sprintf("%04o", $p);
$stat['perm_mode']=$s['mode'];	 // File mode.

$stat['file'] = @realpath($filename);
$stat['basename'] = basename( $filename );

$stat['user_id'] = $s['uid'];
$stat['group_id'] = $s['gid'];

$stat['device']=$s['dev'];			// Device
$stat['device_number']=$s['rdev'];		// Device number, if device.
$stat['inode']=$s['ino'];			// File serial number
$stat['link_count']=$s['nlink'];		// link count
if($stat['type']=='link')$stat['link_to']=@readlink( $filename );

$stat['size']=$s['size'];		// Size of file, in bytes.
$stat['block_size']=$s['blksize'];	// Optimal block size for I/O.
$stat['blocks']=$s['blocks'];	// Number 512-byte blocks allocated

$stat['time_access']=@date( 'Y M D H:i:s',$s['atime']);		// Time of last access.
$stat['time_modified']=@date( 'Y M D H:i:s',$s['mtime']);		// Time of last modification
$stat['time_created']=@date( 'Y M D H:i:s',$s['ctime']);		// Time of last status change

return $stat;

header('Content-Type: text/plain');

Defining Permission Bits

!defined('S_IFMT') && define('S_IFMT', 0170000); //	mask for all types
!defined('S_IFSOCK') && define('S_IFSOCK', 0140000); // type: socket
!defined('S_IFLNK') && define('S_IFLNK', 0120000); // type:	symbolic link
!defined('S_IFREG') && define('S_IFREG', 0100000); // type:	regular file
!defined('S_IFBLK') && define('S_IFBLK', 0060000); // type:	block device
!defined('S_IFDIR') && define('S_IFDIR', 0040000); // type:	directory
!defined('S_IFCHR') && define('S_IFCHR', 0020000); // type:	character device
!defined('S_IFIFO') && define('S_IFIFO', 0010000); // type:	fifo

!defined('S_ISUID') && define('S_ISUID', 0004000); // set-uid bit
!defined('S_ISGID') && define('S_ISGID', 0002000); // set-gid bit
!defined('S_ISVTX') && define('S_ISVTX', 0001000); // sticky bit
!defined('S_IRWXU') && define('S_IRWXU', 00700); //	mask for owner permissions
!defined('S_IRUSR') && define('S_IRUSR', 00400); //	owner: read permission
!defined('S_IWUSR') && define('S_IWUSR', 00200); //	owner: write permission
!defined('S_IXUSR') && define('S_IXUSR', 00100); //	owner: execute permission
!defined('S_IRWXG') && define('S_IRWXG', 00070); //	mask for group permissions
!defined('S_IRGRP') && define('S_IRGRP', 00040); //	group: read permission
!defined('S_IWGRP') && define('S_IWGRP', 00020); //	group: write permission
!defined('S_IXGRP') && define('S_IXGRP', 00010); //	group: execute permission
!defined('S_IRWXO') && define('S_IRWXO', 00007); //	mask for others permissions
!defined('S_IROTH') && define('S_IROTH', 00004); //	others:	read permission
!defined('S_IWOTH') && define('S_IWOTH', 00002); //	others:	write permission
!defined('S_IXOTH') && define('S_IXOTH', 00001); //	others:	execute permission

!defined('S_IRWXUGO') && define('S_IRWXUGO', (S_IRWXU | S_IRWXG | S_IRWXO));
!defined('S_IALLUGO') && define('S_IALLUGO', (S_ISUID | S_ISGID | S_ISVTX | S_IRWXUGO));
!defined('S_IRUGO') && define('S_IRUGO', (S_IRUSR | S_IRGRP | S_IROTH));
!defined('S_IWUGO') && define('S_IWUGO', (S_IWUSR | S_IWGRP | S_IWOTH));
!defined('S_IXUGO') && define('S_IXUGO', (S_IXUSR | S_IXGRP | S_IXOTH));
!defined('S_IRWUGO') && define('S_IRWUGO', (S_IRUGO | S_IWUGO));

How File Permissions Work

When PHP is installed on your server by you or whoever runs the server, it uses the file permissions that are used by the Operating System running the server.. If you are smart or just lucky than you are running some type of BSD/Unix/Solaris/Linux/Sun based Operating system and PHP won't have any problems. If you are running on a Locked, proprietary OS like Windows, PHP will still work but it has to use a lot of shortcuts and hacks to basically "Pretend" to act like the OS is BSD/Unix, and some key features just won't be available.

The OS Permission Bits

Here's the file permissions my Linux server uses, and which PHP automatically uses. The code basically just defines the default permissions for files, and defines the file atributes for each file that you can access by using the stat function, which I've improved upon to make things easier.

Download: POSIX Standard: 5.6 File Characteristicssys/stat.h

Protection bits for File Owner

#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

Protection bits for File Group

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010

Protection bits for All Others

#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

Some Example Permissions

0477 // owner has read only, other and group has rwx 0677 // owner has rw only, other and group has rwx

0444 // all have read only 0666 // all have rw only

0400 // owner has read only, group and others have no permission 0600 // owner has rw only, group and others have no permission

0470 // owner has read only, group has rwx, others have no permission 0407 // owner has read only, other has rwx, group has no permission

0670 // owner has rw only, group has rwx, others have no permission 0607 // owner has rw only, group has no permission and others have rwx

What's a File

A file is not merely its contents, a name, and a file type. A file also has an owner (a user ID), a group (a group ID), permissions (what the owner can do with the file, what people in the group can do, and what everyone else can do), various timestamps, and other information. Collectively, we call these a file's attributes.

Structure of File Mode Bits

The file mode bits have two parts: the file permission bits, which control ordinary access to the file, and special mode bits, which affect only some files.

There are three kinds of permissions that a user can have for a file:

  1. permission to read the file. For directories, this means permission to list the contents of the directory.
  2. permission to write to (change) the file. For directories, this means permission to create and remove files in the directory.
  3. permission to execute the file (run it as a program). For directories, this means permission to access files in the directory.

There are three categories of users who may have different permissions to perform any of the above operations on a file:

  1. the file's owner.
  2. other users who are in the file's group
  3. everyone else.

Files are given an owner and group when they are created. Usually the owner is the current user and the group is the group of the directory the file is in, but this varies with the operating system, the file system the file is created on, and the way the file is created. You can change the owner and group of a file by using the chown and chgrp commands.

In addition to the three sets of three permissions listed above, the file mode bits have three special components, which affect only executable files (programs) and, on most systems, directories:

  1. Set the process's effective user ID to that of the file upon execution (called the set-user-ID bit, or sometimes the setuid bit). For directories on a few systems, give files created in the directory the same owner as the directory, no matter who creates them, and set the set-user-ID bit of newly-created subdirectories.
  2. Set the process's effective group ID to that of the file upon execution (called the set-group-ID bit, or sometimes the setgid bit). For directories on most systems, give files created in the directory the same group as the directory, no matter what group the user who creates them is in, and set the set-group-ID bit of newly-created subdirectories.
  3. Prevent unprivileged users from removing or renaming a file in a directory unless they own the file or the directory; this is called the restricted deletion flag for the directory, and is commonly found on world-writable directories like /tmp.

For regular files on some older systems, save the program's text image on the swap device so it will load more quickly when run; this is called the sticky bit.

Setting Permissions

The basic symbolic operations on a file's permissions are adding, removing, and setting the permission that certain users have to read, write, and execute or search the file. These operations have the following format:

users operation permissions

The spaces between the three parts above are shown for readability only; symbolic modes cannot contain spaces. The users part tells which users' access to the file is changed. It consists of one or more of the following letters (or it can be empty). When more than one of these letters is given, the order that they are in does not matter.

  • u - the user who owns the file.
  • g - other users who are in the file's group.
  • o - all other users.
  • a - all users; the same as ugo.

The operation part tells how to change the affected users' access to the file, and is one of the following symbols:

  • + - to add the permissions to whatever permissions the users already have for the file.
  • - - to remove the permissions from whatever permissions the users already have for the file.
  • = - to make the permissions the only permissions that the users have for the file.

The permissions part tells what kind of access to the file should be changed; it is normally zero or more of the following letters. As with the users part, the order does not matter when more than one letter is given. Omitting the permissions part is useful only with the = operation, where it gives the specified users no access at all to the file.

  • r - the permission the users have to read the file.
  • w - the permission the users have to write to the file.
  • x - the permission the users have to execute the file, or search it if it is a directory.

For example, to give everyone permission to read and write a regular file, but not to execute it, use:


To remove write permission for all users other than the file's owner, use:


The above command does not affect the access that the owner of the file has to it, nor does it affect whether other users can read or execute the file.

To give everyone except a file's owner no permission to do anything with that file, use the mode below. Other users could still remove the file, if they have write permission on the directory it is in.


Another way to specify the same thing is:


Copying Existing Permissions

You can base a file's permissions on its existing permissions. To do this, instead of using a series of r, w, or x letters after the operator, you use the letter u, g, or o. For example, the mode


adds the permissions for users who are in a file's group to the permissions that other users have for the file. Thus, if the file started out as mode 664 (rw-rw-r--), the above mode would change it to mode 666 (rw-rw-rw-). If the file had started out as mode 741 (rwxr----x), the above mode would change it to mode 745 (rwxr--r-x). The - and = operations work analogously.

Umask and Protection

If the users part of a symbolic mode is omitted, it defaults to a (affect all users), except that any permissions that are set in the system variable umask are not affected. The value of umask can be set using the umask command. Its default value varies from system to system.

Omitting the users part of a symbolic mode is generally not useful with operations other than +. It is useful with + because it allows you to use umask as an easily customizable protection against giving away more permission to files than you intended to. As an example, if umask has the value 2, which removes write permission for users who are not in the file's group, then the mode:


adds permission to write to the file to its owner and to other users who are in the file's group, but not to other users. In contrast, the mode:


ignores umask, and does give write permission for the file to all users.

Directories, Set-User-ID and Set-Group-ID Bits

On most systems, if a directory's set-group-ID bit is set, newly created subfiles inherit the same group as the directory, and newly created subdirectories inherit the set-group-ID bit of the parent directory. On a few systems, a directory's set-user-ID bit has a similar effect on the ownership of new subfiles and the set-user-ID bits of new subdirectories. These mechanisms let users share files more easily, by lessening the need to use chmod or chown to share new files.

These convenience mechanisms rely on the set-user-ID and set-group-ID bits of directories. If commands like chmod and mkdir routinely cleared these bits on directories, the mechanisms would be less convenient and it would be harder to share files. Therefore, a command like chmod does not affect the set-user-ID or set-group-ID bits of a directory unless the user specifically mentions them in a symbolic mode, or sets them in a numeric mode. For example, on systems that support set-group-ID inheritance:

# These commands leave the set-user-ID and
# set-group-ID bits of the subdirectories alone,
# so that they retain their default values.
mkdir A B C
chmod 755 A
chmod 0755 B
chmod u=rwx,go=rx C
mkdir -m 755 D
mkdir -m 0755 E
mkdir -m u=rwx,go=rx F

If you want to try to set these bits, you must mention them explicitly in the symbolic or numeric modes, e.g.:

# These commands try to set the set-user-ID
# and set-group-ID bits of the subdirectories.
mkdir G H
chmod 6755 G
chmod u=rwx,go=rx,a+s H
mkdir -m 6755 I
mkdir -m u=rwx,go=rx,a+s J

If you want to try to clear these bits, you must mention them explicitly in a symbolic mode, e.g.:

# This command tries to clear the set-user-ID
# and set-group-ID bits of the directory D.
chmod a-s D

Numeric Modes

The permissions granted to the user, to other users in the file's group, and to other users not in the file's group each require three bits, which are represented as one octal digit. The three special mode bits also require one bit each, and they are as a group represented as another octal digit. Here is how the bits are arranged, starting with the lowest valued bit:

Other users not in the file's group:

1 Execute/search
2 Write
4 Read

Other users in the file's group:

10 Execute/search
20 Write
40 Read

The file's owner:

100 Execute/search
200 Write
400 Read

Special mode bits:

1000 Restricted deletion flag or sticky bit
2000 Set group ID on execution
4000 Set user ID on execution

For example, numeric mode 4755 corresponds to symbolic mode u=rwxs,go=rx, and numeric mode 664 corresponds to symbolic mode ug=rw,o=r. Numeric mode 0 corresponds to symbolic mode a=.

Apache's Internal Bits (hex)

#define APR_FPROT_USETID 	0x8000 /* Set user id */
#define APR_FPROT_UREAD 	0x0400 /* Read by user */
#define APR_FPROT_UWRITE 	0x0200 /* Write by user */
#define APR_FPROT_UEXECUTE 0x0100 /* Execute by user */

#define APR_FPROT_GSETID 	0x4000 /* Set group id */
#define APR_FPROT_GREAD 	0x0040 /* Read by group */
#define APR_FPROT_GWRITE 	0x0020 /* Write by group */
#define APR_FPROT_GEXECUTE 0x0010 /* Execute by group */

#define APR_FPROT_WSTICKY 0x2000 /* Sticky bit */
#define APR_FPROT_WREAD 	0x0004 /* Read by others */
#define APR_FPROT_WWRITE 0x0002 /* Write by others */
#define APR_FPROT_WEXECUTE 0x0001 /* Execute by others */

#define APR_FPROT_OS_DEFAULT  0x0FFF /* use OS's default permissions */

/* additional permission flags for apr_file_copy  and apr_file_append */
#define APR_FPROT_FILE_SOURCE_PERMS 0x1000 /* Copy source file's permissions */

Download: httpd-2.2.10/srclib/apr/file_io/unix/fileacc.c Here's some interesting bitmasking done by Apache that uses the defined bits set earlier by stat.h

 if (perms & APR_USETID) mode |= S_ISUID;
 if (perms & APR_UREAD)  mode |= S_IRUSR;
 if (perms & APR_UWRITE) mode |= S_IWUSR;
 if (perms & APR_UEXECUTE) mode |= S_IXUSR;

 if (perms & APR_GSETID) mode |= S_ISGID;
 if (perms & APR_GREAD)  mode |= S_IRGRP;
 if (perms & APR_GWRITE) mode |= S_IWGRP;
 if (perms & APR_GEXECUTE) mode |= S_IXGRP;

 if (perms & APR_WSTICKY) mode |= S_ISVTX;
 if (perms & APR_WREAD)  mode |= S_IROTH;
 if (perms & APR_WWRITE) mode |= S_IWOTH;
 if (perms & APR_WEXECUTE) mode |= S_IXOTH;
 return mode;

 perms = 0;
 if (mode & S_ISUID)perms |= APR_USETID;
 if (mode & S_IRUSR)perms |= APR_UREAD;
 if (mode & S_IWUSR)perms |= APR_UWRITE;
 if (mode & S_IXUSR)perms |= APR_UEXECUTE;

 if (mode & S_ISGID)perms |= APR_GSETID;
 if (mode & S_IRGRP)perms |= APR_GREAD;
 if (mode & S_IWGRP)perms |= APR_GWRITE;
 if (mode & S_IXGRP)perms |= APR_GEXECUTE;

 if (mode & S_ISVTX)perms |= APR_WSTICKY;
 if (mode & S_IROTH)perms |= APR_WREAD;
 if (mode & S_IWOTH)perms |= APR_WWRITE;
 if (mode & S_IXOTH)perms |= APR_WEXECUTE;
 return perms;


umask(int mask){
 int oldumask;
 int arg_count = ZEND_NUM_ARGS();
 oldumask = umask(077);

 if (BG(umask) == -1) BG(umask) = oldumask;
 if (arg_count == 0) umask(oldumask);


File Attributes

Each file will have attributes based on the type of OS.. Using the stat command you can view them.

Viewing stat results

* %a - Access rights in octal
* %A - Access rights in human readable form
* %b - Number of blocks allocated (see %B)
* %B - The size in bytes of each block reported by %b
* %d - Device number in decimal
* %D - Device number in hex
* %f - Raw mode in hex
* %F - File type
* %g - Group ID of owner
* %G - Group name of owner
* %h - Number of hard links
* %i - Inode number
* %n - File name
* %N - Quoted file name with dereference if symbolic link
* %o - I/O block size
* %s - Total size, in bytes
* %t - Major device type in hex
* %T - Minor device type in hex
* %u - User ID of owner
* %U - User name of owner
* %x - Time of last access
* %X - Time of last access as seconds since Epoch
* %y - Time of last modification
* %Y - Time of last modification as seconds since Epoch
* %z - Time of last change
* %Z - Time of last change as seconds since Epoch

The OS Attribute Bits

These defined values are what allows your operating system to determine the type of file being accessed.

#define S_IFMT   00170000  /* These bits determine file type. */
#define S_IFSOCK 0140000  /* Socket file */
#define S_IFLNK   0120000  /* Symbolic Link */
#define S_IFREG   0100000  /* Regular file */
#define S_IFDIR   0040000  /* Directory */
#define S_IFIFO  0010000   /* FIFO first-in-first-out file */

/* Such devices can be read either a character at a time or a "block" (many characters) at a time,
hence we say there are block special files and character special files. */
#define S_IFBLK   0060000  /* Block device */
#define S_IFCHR  0020000  /* Character device */

Special Permission Bits

#define S_ISUID  0004000  /* Set user ID on execution.  */
#define S_ISGID  0002000  /* Set group ID on execution.  */
#define S_ISVTX  0001000 /* Save swapped text after use (sticky).  */

Bitmasking to determine Filetype

#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)

Default Permission Masks


Download: httpd-2.2.10/srclib/apr/file_io/unix/filestat.c, this file shows a simple way to determine the type of file.

 switch (mode & S_IFMT) {
  case S_IFREG:  type = APR_REG;  break;
  case S_IFDIR:  type = APR_DIR;  break;
  case S_IFLNK:  type = APR_LNK;  break;

  case S_IFCHR:  type = APR_CHR;  break;
  case S_IFBLK:  type = APR_BLK;  break;
  case S_IFFIFO: type = APR_PIPE; break;
  case S_IFSOCK: type = APR_SOCK; break;
  default: type = APR_UNKFILE;
 return type;

Apache Stat Bits

#define APR_FINFO_LINK  0x00000001 /* Stat the link not the file itself if it is a link */
#define APR_FINFO_MTIME  0x00000010 /* Modification Time */
#define APR_FINFO_CTIME  0x00000020 /* Creation or inode-changed time */
#define APR_FINFO_ATIME  0x00000040 /* Access Time */
#define APR_FINFO_SIZE  0x00000100 /* Size of the file */
#define APR_FINFO_CSIZE  0x00000200 /* Storage size consumed by the file */
#define APR_FINFO_DEV  0x00001000 /* Device */
#define APR_FINFO_INODE  0x00002000 /* Inode */
#define APR_FINFO_NLINK  0x00004000 /* Number of links */
#define APR_FINFO_TYPE  0x00008000 /* Type */
#define APR_FINFO_USER  0x00010000 /* User */
#define APR_FINFO_GROUP  0x00020000 /* Group */
#define APR_FINFO_UPROT  0x00100000 /* User protection bits */
#define APR_FINFO_GPROT  0x00200000 /* Group protection bits */
#define APR_FINFO_WPROT  0x00400000 /* World protection bits */
#define APR_FINFO_ICASE  0x01000000 /* if dev is case insensitive */
#define APR_FINFO_NAME  0x02000000 /* name in proper case */
#define APR_FINFO_MIN  0x00008170 /* type, mtime, ctime, atime, size */
#define APR_FINFO_IDENT  0x00003000 /* dev and inode */
#define APR_FINFO_OWNER  0x00030000 /* user and group */
#define APR_FINFO_PROT  0x00700000 /* all protections */
#define APR_FINFO_NORM  0x0073b170 /* an atomic unix apr_stat() */
#define APR_FINFO_DIRENT 0x02000000 /* an atomic unix apr_dir_read() */

The Apache file information structure.

apr_uid_t user;  /* The user id that owns the file */
apr_gid_t group;  /* The group id that owns the file */
apr_ino_t inode; /* The inode of the file. */
apr_dev_t device; /* The id of the device the file is on. */
apr_int32_t nlink; /* The number of hard links to the file. */
apr_off_t size;  /* The size of the file */
apr_off_t csize; /* The storage size consumed by the file */
apr_time_t atime; /* The time the file was last accessed */
apr_time_t mtime; /* The time the file was last modified */
apr_time_t ctime; /* The time the file was created, or the inode was last changed */
const char *fname; /* The pathname of the file (possibly unrooted) */
const char *name; /* The file's name (no path) in filesystem case */

File Time Attributes


If changing both the access and modification times to the current time, touch can change the timestamps for files that the user running it does not own but has write permission for. Otherwise, the user must own the files.

Although touch provides options for changing two of the times the times of last access and modification of a file, there is actually a third one as well: the inode change time. This is often referred to as a file's ctime. The inode change time represents the time when the file's meta-information last changed. One common example of this is when the permissions of a file change. Changing the permissions doesn't access the file, so the atime doesn't change, nor does it modify the file, so the mtime doesn't change. Yet, something about the file itself has changed, and this must be noted somewhere. This is the job of the ctime field. This is necessary, so that, for example, a backup program can make a fresh copy of the file, including the new permissions value. Another operation that modifies a file's ctime without affecting the others is renaming. In any case, it is not possible, in normal operations, for a user to change the ctime field to a user-specified value.

Shared hosting user security

WebHost allows you to create multiple users per account. Each user can have domain assigned to its home home directory accessible via FTP or SSH/SCP. The problem with multiple users on the same account is that they share the same default unix group, and default permissions allow their files to be easily modified by the members of this group. Usually this doesn't pose a problem as each user is probably trusted by account owner to not to mess with others files, but if one of the users have their web application hacked then all other users on the same account will be in danger.

By default all files in your account are created with 644 privileges and directories are with 775. That means any user can read your files and any user from the same account can move and add files in your freshly made directories. Your home directory is different, though. By default it carries 751 attribute meaning that only members of your group can see your files, but can't add any new. These group access schemes are possible, because every user in your account has its primary/default group set to "pgxxxxxx", which is assigned to every new file you create by default. The normal way to secure users from web-intrusion is to assign a separate group to the web-server user, removing it from default group. This way, exploited scripts will not be able to traverse into home directories of other users on your account. To allow account users to update centralized web-site they could be added to web-site group explicitly. But this "normal way" doesn't work with DreamHost, because you can't delete web-user from the default group and unless you set access for every new file explicitly, it will be possible for an intruder to read it.

To make managing privileges easier in interactive sessions "umask 007" command can be specified in your .bash_profile - this makes all new files carry xx0 mask. You also need to control your scripts (web based or cron/shell) so that they set mask for critical files explicitly. To secure account users from access by means of hacked user script you would also like to define another group for every user in your account and change group ownership of the user's home directory to that group with "set gid" bit set (and optional umask 007 in .bash_profile).

Therefore, to secure your users from web-intrusion you need to:

  1. Add a separate user and group for every domain where apache will be running
  2. Add a separate group for other user accounts
  3. Change the default group for new files created by your users by changing the group of their home directory and setting "set gid" bit for it (it is impossible to do this with FTP accounts, therefore you will need to login in each account via SSH)
  4. Add users who need access to web-site into the web-user group
  5. Optionally set umask 007 in .bash_profile for every user to tweak default WebHost775/664 permissions to something like 770/660 for directories and files that are not meant to be read by Apache (660 could also be used for all web scripts including .php as they are not read by dhapache CGI, but merely executed)

Apache Security

All your web files that need to be read by Apache should be readable by everyone as Apache itself is run under dhapache user. However, executable scripts like .php are executed under your own user and do not have to be world readable as they are not actually read by Apache, but executed via suEXEC. Quite the opposite - to prevent your code or database settings from being messed by any third-parties you SHOULD set permissions to these files explicitly to something like 640 or even 600 depending on who do you trust.

Multiuser security setup example

For our example, we will create a rainforce_www user and a aapp_www group for serving web files with apache and setup a rainforce user with a 'aapp group to manage mail and keep other files on DH privately. Since these records already exist, you will need to subsitute your own names.

  • Login to create the users rainforce_www and rainforce with shell access.
  • Create two groups - aapp_www and aapp. Note that users created in previous step are still members of the same default pgxxxxxx group.
  • Add rainforce_www to 'the 'aapp_www group and rainforce to both the aapp_www and aapp groups
  • Move your domain to rainforce_www account (mine is
  • Now login to SSH with your rainforce_www user and change the default group for your home directory with "sgid" bit set to make all current and new files/directories created in this directory have the same aapp_www group.
 $ chgrp -R aapp_www .
 $ chmod 2751 .
 $ chmod 2771

By setting 2771 the directory will be writable by the owner, the group and will be only executable by others. The contents of an executable only directory cannot be listed, but the files inside it can be read (if the permissions of the file allow it). It is important that the directory can be executable in order to allow static content (e.g. .html files) inside it to be read. Remember that directories you don't want anyone to have web access to, should be 0770 (writable by the owner and group, or 0750 writable by the owner and readable by group). Such strict permissions should by applied to password files, php include files or databases files (such as SQLite, BDB, etc).

  • Do the same for rainforce user, but specify aapp group instead.
 $ chgrp -R aapp .
 $ chmod 2751 .
  • Optionally modify umask in .bash_profile in user's home to 007 to make all files created by this user have 660 permissions set by default. If you want that newly created files by accessible by the web, you need to manually setup it's permissions to 664.

Now I can login as the user "rainforce" and update the web-site in the ../rainforce_www/ directory. There is one more setup needed. Because files copied from other accounts can have 644 permissions set instead of 664, you need a script which will update permissions to 664 or 660 to allow other group members modify such files.

SSH key fingerprints

Just gen your own I guess

Original Article from DreamHost Wiki

Content is available under GNU Free Documentation License 1.2.

Example File Permission Bits


sub utype {
  local($_) = @_;
  local(%T) = (
    0010000, 'PIPE',
    0020000, 'CHR',
    0040000, 'DIR',
    0060000, 'BLK',
    0100000, 'FILE',
    0120000, 'LINK',
    0140000, 'SOCK',
  return $T{($_ & 0170000)} || 'FILE';

sub umode {
  local($_) = @_;
  local(%T) = (
    0010000, 'p',
    0020000, 'c',
    0040000, 'd',
    0060000, 'b',
    0100000, '-',
    0120000, 'l',
    0140000, 's',

  return ($T{($_ & 0170000)} || '-')
     . (($_ & 00400) ? 'r' : '-')
     . (($_ & 00200) ? 'w' : '-')
     . (($_ & 04000) ? 's' :
       (($_ & 00100) ? 'x' : '-'))
     . (($_ & 00040) ? 'r' : '-')
     . (($_ & 00020) ? 'w' : '-')
     . (($_ & 02000) ? 's' :
       (($_ & 00010) ? 'x' : '-'))
     . (($_ & 00004) ? 'r' : '-')
     . (($_ & 00002) ? 'w' : '-')
     . (($_ & 01000) ? 't' :
       (($_ & 00001) ? 'x' : '-'));


        eval 'sub S_IFMT () {00170000;}' unless defined(&S_IFMT);
        eval 'sub S_IFSOCK () {0140000;}' unless defined(&S_IFSOCK);
        eval 'sub S_IFLNK () {0120000;}' unless defined(&S_IFLNK);
        eval 'sub S_IFREG () {0100000;}' unless defined(&S_IFREG);
        eval 'sub S_IFBLK () {0060000;}' unless defined(&S_IFBLK);
        eval 'sub S_IFDIR () {0040000;}' unless defined(&S_IFDIR);
        eval 'sub S_IFCHR () {0020000;}' unless defined(&S_IFCHR);
        eval 'sub S_IFIFO () {0010000;}' unless defined(&S_IFIFO);
        eval 'sub S_ISUID () {0004000;}' unless defined(&S_ISUID);
        eval 'sub S_ISGID () {0002000;}' unless defined(&S_ISGID);
        eval 'sub S_ISVTX () {0001000;}' unless defined(&S_ISVTX);
        eval 'sub S_ISLNK {
            local($m) = @_;
            eval q(((($m) &  &S_IFMT) ==  &S_IFLNK));
        }' unless defined(&S_ISLNK);
        eval 'sub S_ISREG {
            local($m) = @_;
            eval q(((($m) &  &S_IFMT) ==  &S_IFREG));
        }' unless defined(&S_ISREG);
        eval 'sub S_ISDIR {
            local($m) = @_;
            eval q(((($m) &  &S_IFMT) ==  &S_IFDIR));
        }' unless defined(&S_ISDIR);
        eval 'sub S_ISCHR {
            local($m) = @_;
            eval q(((($m) &  &S_IFMT) ==  &S_IFCHR));
        }' unless defined(&S_ISCHR);
        eval 'sub S_ISBLK {
            local($m) = @_;
            eval q(((($m) &  &S_IFMT) ==  &S_IFBLK));
        }' unless defined(&S_ISBLK);
        eval 'sub S_ISFIFO {
            local($m) = @_;
            eval q(((($m) &  &S_IFMT) ==  &S_IFIFO));
        }' unless defined(&S_ISFIFO);
        eval 'sub S_ISSOCK {
            local($m) = @_;
            eval q(((($m) &  &S_IFMT) ==  &S_IFSOCK));
        }' unless defined(&S_ISSOCK);
        eval 'sub S_IRWXU () {00700;}' unless defined(&S_IRWXU);
        eval 'sub S_IRUSR () {00400;}' unless defined(&S_IRUSR);
        eval 'sub S_IWUSR () {00200;}' unless defined(&S_IWUSR);
        eval 'sub S_IXUSR () {00100;}' unless defined(&S_IXUSR);
        eval 'sub S_IRWXG () {00070;}' unless defined(&S_IRWXG);
        eval 'sub S_IRGRP () {00040;}' unless defined(&S_IRGRP);
        eval 'sub S_IWGRP () {00020;}' unless defined(&S_IWGRP);
        eval 'sub S_IXGRP () {00010;}' unless defined(&S_IXGRP);
        eval 'sub S_IRWXO () {00007;}' unless defined(&S_IRWXO);
        eval 'sub S_IROTH () {00004;}' unless defined(&S_IROTH);
        eval 'sub S_IWOTH () {00002;}' unless defined(&S_IWOTH);
        eval 'sub S_IXOTH () {00001;}' unless defined(&S_IXOTH);
    if(defined(&__KERNEL__)) {
        eval 'sub S_IRWXUGO () {( &S_IRWXU| &S_IRWXG| &S_IRWXO);}' unless defined(&S_IRWXUGO);
        eval 'sub S_IALLUGO () {( &S_ISUID| &S_ISGID| &S_ISVTX| &S_IRWXUGO);}' unless defined(&S_IALLUGO);
        eval 'sub S_IRUGO () {( &S_IRUSR| &S_IRGRP| &S_IROTH);}' unless defined(&S_IRUGO);
        eval 'sub S_IWUGO () {( &S_IWUSR| &S_IWGRP| &S_IWOTH);}' unless defined(&S_IWUGO);
        eval 'sub S_IXUGO () {( &S_IXUSR| &S_IXGRP| &S_IXOTH);}' unless defined(&S_IXUGO);
        require 'linux/';
        require 'linux/';

Mozilla-Source 1.8a2

/* notice that these valuse are octal. */
const PERM_IRWXU = 00700;  /* read, write, execute/search by owner */
const PERM_IRUSR = 00400;  /* read permission, owner */
const PERM_IWUSR = 00200;  /* write permission, owner */
const PERM_IXUSR = 00100;  /* execute/search permission, owner */
const PERM_IRWXG = 00070;  /* read, write, execute/search by group */
const PERM_IRGRP = 00040;  /* read permission, group */
const PERM_IWGRP = 00020;  /* write permission, group */
const PERM_IXGRP = 00010;  /* execute/search permission, group */
const PERM_IRWXO = 00007;  /* read, write, execute/search by others */
const PERM_IROTH = 00004;  /* read permission, others */
const PERM_IWOTH = 00002;  /* write permission, others */
const PERM_IXOTH = 00001;  /* execute/search permission, others */

const MODE_RDONLY   = 0x01;
const MODE_WRONLY   = 0x02;
const MODE_RDWR     = 0x04;
const MODE_CREATE   = 0x08;
const MODE_APPEND   = 0x10;
const MODE_TRUNCATE = 0x20;
const MODE_SYNC     = 0x40;
const MODE_EXCL     = 0x80;


/* Transform masks for the high-level interface */
#define PNG_TRANSFORM_IDENTITY       0x0000    /* read and write */
#define PNG_TRANSFORM_STRIP_16       0x0001    /* read only */
#define PNG_TRANSFORM_STRIP_ALPHA    0x0002    /* read only */
#define PNG_TRANSFORM_PACKING        0x0004    /* read and write */
#define PNG_TRANSFORM_PACKSWAP       0x0008    /* read and write */
#define PNG_TRANSFORM_EXPAND         0x0010    /* read only */
#define PNG_TRANSFORM_INVERT_MONO    0x0020    /* read and write */
#define PNG_TRANSFORM_SHIFT          0x0040    /* read and write */
#define PNG_TRANSFORM_BGR            0x0080    /* read and write */
#define PNG_TRANSFORM_SWAP_ALPHA     0x0100    /* read and write */
#define PNG_TRANSFORM_SWAP_ENDIAN    0x0200    /* read and write */
#define PNG_TRANSFORM_INVERT_ALPHA   0x0400    /* read and write */
#define PNG_TRANSFORM_STRIP_FILLER   0x0800    /* WRITE only */


# Extract bits from the mode

def S_IMODE(mode):
    return mode & 07777

def S_IFMT(mode):
    return mode & 0170000

# Constants used as S_IFMT() for various file types
# (not all are implemented on all systems)

S_IFDIR  = 0040000
S_IFCHR  = 0020000
S_IFBLK  = 0060000
S_IFREG  = 0100000
S_IFIFO  = 0010000
S_IFLNK  = 0120000
S_IFSOCK = 0140000

# Functions to test for each file type

def S_ISDIR(mode):
    return S_IFMT(mode) == S_IFDIR

def S_ISCHR(mode):
    return S_IFMT(mode) == S_IFCHR

def S_ISBLK(mode):
    return S_IFMT(mode) == S_IFBLK

def S_ISREG(mode):
    return S_IFMT(mode) == S_IFREG

def S_ISFIFO(mode):
    return S_IFMT(mode) == S_IFIFO

def S_ISLNK(mode):
    return S_IFMT(mode) == S_IFLNK

def S_ISSOCK(mode):
    return S_IFMT(mode) == S_IFSOCK

# Names for permission bits

S_ISUID = 04000
S_ISGID = 02000
S_ISVTX = 01000
S_IREAD = 00400
S_IWRITE = 00200
S_IEXEC = 00100
S_IRWXU = 00700
S_IRUSR = 00400
S_IWUSR = 00200
S_IXUSR = 00100
S_IRWXG = 00070
S_IRGRP = 00040
S_IWGRP = 00020
S_IXGRP = 00010
S_IRWXO = 00007
S_IROTH = 00004
S_IWOTH = 00002
S_IXOTH = 00001


/* Encoding of the file mode.  */

#define __S_IFMT        0170000 /* These bits determine file type.  */

/* File types.  */
#define __S_IFDIR       0040000 /* Directory.  */
#define __S_IFCHR       0020000 /* Character device.  */
#define __S_IFBLK       0060000 /* Block device.  */
#define __S_IFREG       0100000 /* Regular file.  */
#define __S_IFIFO       0010000 /* FIFO.  */
#define __S_IFLNK       0120000 /* Symbolic link.  */
#define __S_IFSOCK      0140000 /* Socket.  */

/* POSIX.1b objects.  Note that these macros always evaluate to zero.  But
   they do it by enforcing the correct use of the macros.  */
#define __S_TYPEISMQ(buf)  ((buf)->st_mode - (buf)->st_mode)
#define __S_TYPEISSEM(buf) ((buf)->st_mode - (buf)->st_mode)
#define __S_TYPEISSHM(buf) ((buf)->st_mode - (buf)->st_mode)

/* Protection bits.  */

#define __S_ISUID       04000   /* Set user ID on execution.  */
#define __S_ISGID       02000   /* Set group ID on execution.  */
#define __S_ISVTX       01000   /* Save swapped text after use (sticky).  */
#define __S_IREAD       0400    /* Read by owner.  */
#define __S_IWRITE      0200    /* Write by owner.  */
#define __S_IEXEC       0100    /* Execute by owner.  */


#define NFS_FIFO_DEV    (-1)
#define NFSMODE_FMT     0170000
#define NFSMODE_DIR     0040000
#define NFSMODE_CHR     0020000
#define NFSMODE_BLK     0060000
#define NFSMODE_REG     0100000
#define NFSMODE_LNK     0120000
#define NFSMODE_SOCK    0140000
#define NFSMODE_FIFO    0010000


#define NFS3_FIFO_DEV           (-1)
#define NFS3MODE_FMT            0170000
#define NFS3MODE_DIR            0040000
#define NFS3MODE_CHR            0020000
#define NFS3MODE_BLK            0060000
#define NFS3MODE_REG            0100000
#define NFS3MODE_LNK            0120000
#define NFS3MODE_SOCK           0140000
#define NFS3MODE_FIFO           0010000

/* Flags for access() call */
#define NFS3_ACCESS_READ        0x0001
#define NFS3_ACCESS_LOOKUP      0x0002
#define NFS3_ACCESS_MODIFY      0x0004
#define NFS3_ACCESS_EXTEND      0x0008
#define NFS3_ACCESS_DELETE      0x0010
#define NFS3_ACCESS_EXECUTE     0x0020
#define NFS3_ACCESS_FULL        0x003f


#define S_IFMT  00170000
#define S_IFSOCK 0140000
#define S_IFLNK  0120000
#define S_IFREG  0100000
#define S_IFBLK  0060000
#define S_IFDIR  0040000
#define S_IFCHR  0020000
#define S_IFIFO  0010000
#define S_ISUID  0004000
#define S_ISGID  0002000
#define S_ISVTX  0001000

#define S_ISLNK(m)      (((m) & S_IFMT) == S_IFLNK)
#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
#define S_ISCHR(m)      (((m) & S_IFMT) == S_IFCHR)
#define S_ISBLK(m)      (((m) & S_IFMT) == S_IFBLK)
#define S_ISFIFO(m)     (((m) & S_IFMT) == S_IFIFO)
#define S_ISSOCK(m)     (((m) & S_IFMT) == S_IFSOCK)

#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010

#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

Further File Permissions Reading

Special file types

Changing file attributes

Security chmod File Permissions umask