FREE THOUGHT · FREE SOFTWARE · FREE WORLD

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..

.htaccess

$ chmod 604 .htaccess

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

php.cgi

$ chmod 711 php.cgi

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

.php.ini

$ 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 php.net 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) {
 clearstatcache();
 $ss=@stat($filename);
 if(!$ss) die("Couldnt stat {$filename}");
 $file_convert=array(0140000=>'ssocket',0120000=>'llink',0100000=>'-file',0060000=>'bblock',0040000=>'ddir',0020000=>'cchar',0010000=>'pfifo');
 $p=$ss['mode'];
 $t=decoct($ss['mode'] & 0170000);
 $str = (array_key_exists(octdec($t),$file_convert)) ? $file_convert[octdec($t)]{0} : 'u';
 $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':'-'));

 $s=array(
 'perms'=>array(
  'umask'=>sprintf("%04o",umask()),
  'human'=>$str,
  'octal1'=>sprintf("%o", ($ss['mode'] & 000777)),
  'octal2'=>sprintf("0%o", 0777 & $p),
  'decimal'=>sprintf("%04o", $p),
  'fileperms'=>@fileperms($filename),
  'mode1'=>$p,
  'mode2'=>$ss['mode']),

 'filetype'=>array(
  'type'=>substr($file_convert[octdec($t)],1),
  'type_octal'=>sprintf("%07o", octdec($t)),
  'is_file'=>@is_file($filename),
  'is_dir'=>@is_dir($filename),
  'is_link'=>@is_link($filename),
  'is_readable'=> @is_readable($filename),
  'is_writable'=> @is_writable($filename)),

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

 'file'=>array(
  'filename'=>$filename,
  'realpath'=>(@realpath($filename) != $filename) ? @realpath($filename) : '',
  'dirname'=>@dirname($filename),
  'basename'=>@basename($filename)),

 'device'=>array(
  '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'=>array(
  '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.

 'time'=>array(
  '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'])),
 );

 clearstatcache();
 return $s;
}

PHP Stat Function Output

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

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

Congratulations!

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 ) {
$p=@fileperms($filename);
$s=@stat($filename);
$str='';
$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['default_umask']=sprintf("%04o",umask());
$stat['perm_human']=$str;
$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

clearstatcache();
return $stat;
}

header('Content-Type: text/plain');
$stat=askapache_stat(__FILE__);
print_r($stat);

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:

a=rw

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

go-w

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.

go=

Another way to specify the same thing is:

og-rwx

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

o+g

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:

+w

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:

a+w

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

apr_unix_perms2mode(perms){
 mode=0;
 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;
}


apr_unix_mode2perms(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

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

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

 convert_to_long_ex(arg1);
 umask(Z_LVAL_PP(arg1));
 RETURN_LONG(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

#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO  (S_IRUSR|S_IRGRP|S_IROTH)
#define S_IWUGO  (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO  (S_IXUSR|S_IXGRP|S_IXOTH)

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

filetype_from_mode(mode){
 type;
 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

touch

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 rainforce.org)
  • 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 rainforce.org

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/rainforce.org 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

/usr/lib/w3m/cgi-bin/dirlist.cgi

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' : '-'));
}

/usr/lib/perl/5.8.4/linux/stat.ph

        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/types.ph';
        require 'linux/time.ph';
    }

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;

/usr/include/libpng12/png.h

/* 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 */

/usr/lib/python2.4/stat.py

# 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_ENFMT = S_ISGID
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

/usr/include/bits/stat.h

/* 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.  */

/usr/include/linux/nfs.h

#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

/usr/include/linux/nfs3.h

#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

/usr/include/linux/stat.h

#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

 

 

Comments