7
\$\begingroup\$

I'm trying to create a read-write-execute permissions system for items using user-group-world system.

I already have the user/group system set up, just not the permissions.

This is what I wrote:

/** @param $requestedPerm the permission being requested: read write or execute - 4, 2, or 1 respectively 
* @param $level the permission level: world, group, or user
* @param $permInt the permissions checked against: 
   (like 754) which is user:read-write-exec, group:read-exec, world:read
*/
function check($requestedPerm,$level,$permInt){
    $digit = ($permInt/$level)%10;
    return ($requestedPerm & $digit)===$requestedPerm;
}

$read = 4;
$write = 2;
$exec = 1;

$world = 1;
$group = 10;
$user = 100;

$bool = check($read,$group,754);

It seems to work how I want it to, but I'm new to bitwise operations, so I'm not too confident.

In my production code, it will be object oriented, but basically it'll work the same.

Is this check() function reliable, as long as I provide the correct $requestedPerm, $level, and $permInt?

\$\endgroup\$
2
  • \$\begingroup\$ How would you use this system? Where are the permissions coming from? What are you going to use this system to protect? I can't help but feel that there is a bit of context missing here. Giving more information will help us give a better answer. \$\endgroup\$ Commented Jan 29, 2015 at 22:23
  • \$\begingroup\$ The context isn't necessary, because I'm just asking about the bitwise operations. I updated my question to be more clear. \$\endgroup\$
    – Reed
    Commented Jan 29, 2015 at 22:55

1 Answer 1

12
\$\begingroup\$

Your presentation of your problem indicates that you want to emulate the permission system as used by POSIX like systems (Unix). The three sets (user, group, and world), and three permissions (read, write, execute) are from that. Your actual implementation though is very different....

What you have will work, but is wasteful of bits, and is only a partial bitwise solution.

Consider the permissions 0777 (by the way, the 0 there is supposed to indicate that the value is Octal - did you know that? - see PHP's documentation on Integers)

The 7 permission is the read permission (4), the write permission (2), and the execute permission (1). The important thing is to look at it in binary though:

read  00000100
write 00000010
exec  00000001

If we 'OR' all those permissions, we get:

rwx   00000111

Now, the way things are supposed to work, is that the right-most 3 bits represent the permissions of the world users, the next are the group users, and then the actual user:

user rwx     00000001 11000000
group rwx    00000000 00111000
world rwx    00000000 00000111

The left-most 7 bits are also used on most systems to represent other properties about the file. For example, in Linux, the details of the bits are described in the stat system function (remember, the leading 0 on the numbers means the number is in Octal...!!!):

       S_IRWXU     00700   mask for file owner permissions

       S_IRUSR     00400   owner has read permission
       S_IWUSR     00200   owner has write permission
       S_IXUSR     00100   owner has execute permission

       S_IRWXG     00070   mask for group permissions
       S_IRGRP     00040   group has read permission
       S_IWGRP     00020   group has write permission
       S_IXGRP     00010   group has execute permission

       S_IRWXO     00007   mask for permissions for others
                           (not in group)
       S_IROTH     00004   others have read permission
       S_IWOTH     00002   others have write permission
       S_IXOTH     00001   others have execute permission

The second reminder about the Octal numbers is important. Note that octal numbers go from 0 to 7. This is conveniently 3-bits in binary (and hexadecimal is conveniently 4 binary bits per hex digit).

OK, so, that's how it's normally done. Setting read-write-execute permissions for user, group, and world results in the binary:

00000001 11111111

which is 511 in decimal. Note, if I want to test whether the user has execute permission, it is a simple case of testing with:

00000000 01000000

If the permission is $perm = 0777 (octal) and the test is $userexec = 0100 (execute for user in octal), then we can do:

if (userexec & perm != 0) {
    // user has execute permission
    ....

But, what does your code do? It does:

7 * 100 + 7 * 10 + 7

which is 777 in decimal, and, unfortunately, in binary it is

00000011 00001001

Now, if I want to determine if the user has write-permissions, I have to do divisions and bit-tests to get there (which is what you do, but it's not the way it is supposed to be).

So, with all that background, what should your code look like? First, let's talk about bit shifting...

If I have the bits (in binary):

00000000 00000111

and I then shift them all 3 positions to the left, I will have:

00000000 00111000

I can left-shift bits with the left-shift operator <<. So, the first value there is 0007 (octal), and I can do:

$threebits = 0007;
$threebits = $threebits << 3;

After that shift, $threebits will have the (octal) value 0070.

Note that we need to shift permission bits 0 times for the world permissions, 3 times for group, and 6 times for user.....

$read = 4;
$write = 2;
$exec = 1;

$world = 0;
$group = 3;
$user = 6;

function check($requestedPerm, $level, $permInt){
    return ($requestedPerm << $level) & $permInt != 0;
}

Note that using the above logic we expect the $permInt to be in a different format to what you had.... so, your current code is:

$bool = check($read,$group,754);

But, that will need to change (to add the 0 to make it octal...):

$bool = check($read, $group, 0754);
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I understand it a lot better now. I am going for a posix-style, since I have a nicely setup user/group system and it just works well w/ the posix permissions. And I didn't know about the octal numbers (or not to much of an extent at least). Thank you for the detailed answer. \$\endgroup\$
    – Reed
    Commented Jan 30, 2015 at 19:57
  • \$\begingroup\$ Thank you for pointing out that 0777 is in octal in PHP - we were very confused until we realised that!! :) \$\endgroup\$
    – Force Hero
    Commented Nov 27, 2017 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.