15
\$\begingroup\$

The Challenge

Given a string indicating the symbolic notation of UNIX permission of a file and its ownership (user ID and group ID), decide whether a given user A has permission to read / write / execute it.

Related.

Permissions in UNIX system

In UNIX, every file has three classes of permissions (user, group and others) and ownership, including which user and which group it belongs to.

The symbolic notation consists of ten characters. The first character is not important in this challenge. The remaining nine characters are in three sets of three characters, representing permissions of user, group and others class. Characters in each set indicates whether reading / writing / executing is permitted. If permitted, it will be r, w or x. Otherwise, it will be -.

Note that setuid, setgid and sticky bit may change the third character of each set to s, S, t or T. Here's a simple rule: if the character is lowercase letter, then the permission is set; otherwise, it is not.

(For the details of symbolic notation of permissions, please refer to here.)

Every user has its user ID, and every group has its group ID. All IDs will be non-negative integers. A user will belong to at least one group. If a user A want to get access to a file, the system will check their permissions as follows:

  • If the file belongs to user A, check the permissions of user class.

  • If the file doesn't belong to A, but A belongs to the group which the file belongs to, check the permissions of group class.

  • Otherwise, check the permissions of others class.

However, there is one exception: if the user ID is 0 (superuser), they have permission to do anything!

Specifications

  • Your program / function should take these as input in any reasonable format:
    • Permissions in symbolic notation.
    • User ID and group ID which the file belongs to.
    • The user ID of A, and a list of group IDs which A belongs to.
    • Type of access. You can use any three different one-digit or one-character values for read, write and execute.
  • Return / output a truthy value if A has permission to access the file, or a falsy value if not.
  • You can assume that the first character of the notation will always be - (regular file).
  • This is , so the shortest in bytes wins!

Test Cases

The format here is [permissions, user ID of file, group ID of file, user ID of A, group IDs of A, type(r/w/x)].

[-rwx------, 13, 15, 13, [15, 24], r]: True   # user
[-rwxr-xr-x, 13, 24, 24, [15, 24], w]: False  # group 
[-rwxr-Sr-T, 13, 15, 24, [15, 35], x]: False  # group
[-rwsr-xr-t, 13, 15, 24, [24, 35], x]: True   # others
[----------, 13, 15, 0, [0, 1, 2], r]: True   # superuser
[----------, 13, 15, 1, [0, 1, 2], r]: False  # others
[----rwxrwx, 13, 15, 13, [15, 24], r]: False  # user
\$\endgroup\$
0

6 Answers 6

7
\$\begingroup\$

JavaScript (ES6), 61 51 50 bytes

Takes 6 distinct parameters as input, in the order described in the challenge. Expects the last parameter to be 1 for read, 2 for write or 3 for execute. Returns 0 or 1.

(p,u,g,a,G,P)=>!a|p[u-a?6-3*G.includes(g)+P:P]>'Z'

Test cases

let f =

(p,u,g,a,G,P)=>!a|p[u-a?6-3*G.includes(g)+P:P]>'Z'

//            p             u   g   a   G          P
console.log(f('-rwx------', 13, 15, 13, [15, 24],  1)) // True  (user)
console.log(f('-rwxr-xr-x', 13, 24, 24, [15, 24],  2)) // False (group)
console.log(f('-rwxr-Sr-T', 13, 15, 24, [15, 35],  3)) // False (group)
console.log(f('-rwsr-xr-t', 13, 15, 24, [24, 35],  3)) // True  (others)
console.log(f('----------', 13, 15,  0, [0, 1, 2], 1)) // True  (superuser)
console.log(f('----------', 13, 15,  1, [0, 1, 2], 1)) // False (others)
console.log(f('----rwxrwx', 13, 15, 13, [15, 24],  1)) // False (user)

\$\endgroup\$
0
3
\$\begingroup\$

Python 2, 76 70 67 63 59 58 56 55 52 49 48 bytes

lambda p,u,g,A,G,t:A*'_'<p[~(u==A)*3*(g in G)-t]

Try it online!

Takes type as 3 for read, 2 for write ,and 1 for execute

\$\endgroup\$
4
  • \$\begingroup\$ 68 bytes \$\endgroup\$
    – Mr. Xcoder
    Commented Nov 29, 2017 at 11:12
  • 1
    \$\begingroup\$ It is not necessary to be superuser to have group ID 0. I added it to the test cases. \$\endgroup\$
    – Colera Su
    Commented Nov 29, 2017 at 11:28
  • \$\begingroup\$ @ColeraSu Ah i misread, can the user id be negative? \$\endgroup\$
    – TFeld
    Commented Nov 29, 2017 at 11:35
  • \$\begingroup\$ Both UID and GID will be non-negative. \$\endgroup\$
    – Colera Su
    Commented Nov 29, 2017 at 11:38
1
\$\begingroup\$

Java (OpenJDK 8), 60 bytes

(p,u,g,U,G,t)->U<1|p.charAt(t+(u==U?0:G.contains(g)?3:6))>90

Try it online!

The mapping for the type is the following: 1 means r, 2 means w and 3 means x.

\$\endgroup\$
1
\$\begingroup\$

Pyth, 22 21 bytes

|!Q}@@c3tw*nEQ-2}EEEG

Try it online. Test suite.

Takes input as six lines:

user id
permissions
file user id
file group
user groups
permission (0 = read, 1 = write, 2 = execute)

Explanation

|!Q}@@c3tw*nEQ-2}EEEG     Implicit: read user id to Q
 !Q                       True if user id is 0, false otherwise
|                         If true, just return it
         w                Read permission string
        -                 Omit first -
      c3                  Split in 3 parts
            E             Read file user id
           n Q            See if it doesn't equal Q
                          -> False (0) if user matches, true (1) otherwise
                 E        Read file group
                  E       Read user groups
                }         -> True (1) if group matches, false (0) otherwise
              -2          Subtract from 2
                          -> 1 if group matches, 2 otherwise
          *               Multiply the two numbers
                          -> 0 if user matches, 1 if group matches, 2 otherwise
     @                    Take correct part of permission string
    @                     Take correct character of that part
   }                G     See if it is in lowercase alphabet
        
           
\$\endgroup\$
1
+300
\$\begingroup\$

Go, 284 bytes

import(."unicode";."golang.org/x/exp/slices")
func X(P string,f,g,u,a int,s[]int)int{P=P[1:]
p,i:=0,0
for;i<3;i++{for j:= 0;j<3;j++{e:=0
if IsLower(rune(P[3*i+j])){e++}
p|=e<<(3*i+j)}}
if u==0{return 1}
p>>=a
if f==u{return p&1}else if Contains(s,g){return p>>3&1}else{return p>>6&1}}

Attempt This Online!

rwx is 012.

Explanation

import(."unicode";."golang.org/x/exp/slices")
func X(P string,f,g,u,a int,s[]int)int{
// load the perms
P=P[1:] // strip the leading char
p,i:=0,0
// for all chars in the string...
for;i<3;i++{for j:= 0;j<3;j++{
// if it's lowercase, bit-or it with its respective location in the perms variable
e:=0
if IsLower(rune(P[3*i+j])){e++}
p|=e<<(3*i+j)}}
// the perm variable is stored as
// 876543210
// xwrxwrxwr
// -o-|g|-u-
// other, group, user, with the lowest bit on the right.
if u==0{return 1} // superuser
p>>=a // constant offset based on the access type
if f==u{
// user's file
return p&1
}else if Contains(s,g){
// user's group's file
return p>>3&1
}else{
// other
return p>>6&1
}}

Directly accessing the string, 145 bytes

import."golang.org/x/exp/slices"
func X(P string,f,g,u,a int,s[]int)bool{k:=0
if f==u{}else if Contains(s,g){k=3}else{k=6}
return u<1||P[a+k]>90}

Attempt This Online!

Based on @Olivier Grégoire's answer, and rwx is also 123 here.

\$\endgroup\$
0
\$\begingroup\$

C (GCC), 117 bytes

f(p,u,g,U,G,t,o)char*p;int*G;{t=t-'r'?t-117:1;if(o=u-U?6:0)for(;*G;++G)if(g==*G)o=3;return U==0|p[t+=o]>96&p[t]<123;}

Attempt This Online!

\$\endgroup\$
1

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.