@@ -13,113 +13,113 @@ import (
1313
1414/* list files in a given directory with some basic information */
1515func ListFiles (path string , userID string ) ([]FileEntry , error ) {
16- var entries []FileEntry
16+ var entries []FileEntry
1717
1818 /* combine basePath with the requested path */
19- fullPath := filepath .Join (config .BackendConfig .AppInfo .BasePath , path )
20-
21- /* clean the path to prevent directory traversal */
22- fullPath = filepath .Clean (fullPath )
23-
24- /* ensure the resulting path is still within the basePath (prevent directory traversal) */
25- if ! strings .HasPrefix (fullPath , filepath .Clean (config .BackendConfig .AppInfo .BasePath )) {
26- return nil , fmt .Errorf ("Path traversal attempt detected: %s" , path )
27- }
28-
29- /* list all the files in the given directory */
30- files , err := os .ReadDir (fullPath )
31- if err != nil {
32- return nil , err
33- }
19+ fullPath := filepath .Join (config .BackendConfig .AppInfo .BasePath , path )
20+
21+ /* clean the path to prevent directory traversal */
22+ fullPath = filepath .Clean (fullPath )
23+
24+ /* ensure the resulting path is still within the basePath (prevent directory traversal) */
25+ if ! strings .HasPrefix (fullPath , filepath .Clean (config .BackendConfig .AppInfo .BasePath )) {
26+ return nil , fmt .Errorf ("Path traversal attempt detected: %s" , path )
27+ }
28+
29+ /* list all the files in the given directory */
30+ files , err := os .ReadDir (fullPath )
31+ if err != nil {
32+ return nil , err
33+ }
3434
3535 /* retrive information for each file in the directory */
36- for _ , f := range files {
37- fullPath := filepath .Join (path , f .Name ())
36+ for _ , f := range files {
37+ fullPath := filepath .Join (path , f .Name ())
3838
39- /* check ACL access first */
40- isOwner , err := isOwner (fullPath , userID )
39+ /* check ACL access first */
40+ isOwner , err := isOwner (fullPath , userID )
4141 if err != nil {
4242 return nil , fmt .Errorf ("error during listing files: %w" , err )
4343 }
4444
45- if ! isOwner {
45+ if ! isOwner {
4646 /* if the user doesn't have right ACL permissions for the file, skip it */
47- continue
48- }
47+ continue
48+ }
4949
5050 /* get information about the file */
51- info , err := f .Info ()
52- if err != nil {
53- continue
54- }
51+ info , err := f .Info ()
52+ if err != nil {
53+ continue
54+ }
5555
5656 /* store it in entries that would be returned */
57- entries = append (entries , FileEntry {
58- Name : f .Name (),
59- Path : fullPath ,
60- IsDir : f .IsDir (),
61- Size : info .Size (),
62- ModTime : info .ModTime ().Unix (),
63- })
64- }
65-
66- return entries , nil
57+ entries = append (entries , FileEntry {
58+ Name : f .Name (),
59+ Path : fullPath ,
60+ IsDir : f .IsDir (),
61+ Size : info .Size (),
62+ ModTime : info .ModTime ().Unix (),
63+ })
64+ }
65+
66+ return entries , nil
6767}
6868
69- /*
70- checks if the user is the owner of the file
69+ /*
70+ checks if the user is the owner of the file
7171 username is the LDAP CN for the user
7272 uses getfacl to fetch the permissions (usually from filesystems mounted from remote servers)
7373*/
7474func isOwner (filePath string , userCN string ) (bool , error ) {
7575
76- cleanPath := filepath .Clean (filePath )
77-
78- /* additional validation to ensure that the path doesn't contain dangerous characters */
79- if strings .Contains (cleanPath , ";" ) || strings .Contains (cleanPath , "|" ) ||
80- strings .Contains (cleanPath , "&" ) || strings .Contains (cleanPath , "`" ) ||
81- strings .Contains (cleanPath , "$" ) || strings .Contains (cleanPath , "(" ) ||
82- strings .Contains (cleanPath , ")" ) {
76+ cleanPath := filepath .Clean (filePath )
77+
78+ /* additional validation to ensure that the path doesn't contain dangerous characters */
79+ if strings .Contains (cleanPath , ";" ) || strings .Contains (cleanPath , "|" ) ||
80+ strings .Contains (cleanPath , "&" ) || strings .Contains (cleanPath , "`" ) ||
81+ strings .Contains (cleanPath , "$" ) || strings .Contains (cleanPath , "(" ) ||
82+ strings .Contains (cleanPath , ")" ) {
8383 zap .L ().Warn ("Illegal method attempted while getting file path by injecting dangerous character in the file path!" )
84- return false , fmt .Errorf ("invalid characters in file path: %s" , cleanPath )
85- }
86-
87- /* get the file's ACL using getfacl with properly escaped arguments */
88- cmd := exec .Command ("getfacl" , "--" , cleanPath )
89- output , err := cmd .Output ()
90- if err != nil {
91- return false , fmt .Errorf ("failed to execute getfacl on %s: %v" , cleanPath , err )
92- }
93-
94- /* parse the getfacl output to check ownership */
95- lines := strings .Split (string (output ), "\n " )
96- for _ , line := range lines {
97- line = strings .TrimSpace (line )
98-
99- /* check for owner line (format: "# owner: username") */
100- if strings .HasPrefix (line , "# owner:" ) {
101- owner := strings .TrimSpace (strings .TrimPrefix (line , "# owner:" ))
102-
103- /* compare with the provided CN (case-insensitive) */
104- if strings .EqualFold (owner , userCN ) {
105- return true , nil
106- }
107- }
108-
109- /* also check user ACL entries (format: "user:username:permissions") */
110- if strings .HasPrefix (line , "user:" ) && ! strings .HasPrefix (line , "user::" ) {
111- parts := strings .Split (line , ":" )
112- if len (parts ) >= 3 {
113- aclUser := parts [1 ]
114- permissions := parts [2 ]
115-
84+ return false , fmt .Errorf ("invalid characters in file path: %s" , cleanPath )
85+ }
86+
87+ /* get the file's ACL using getfacl with properly escaped arguments */
88+ cmd := exec .Command ("getfacl" , "--" , cleanPath )
89+ output , err := cmd .Output ()
90+ if err != nil {
91+ return false , fmt .Errorf ("failed to execute getfacl on %s: %v" , cleanPath , err )
92+ }
93+
94+ /* parse the getfacl output to check ownership */
95+ lines := strings .Split (string (output ), "\n " )
96+ for _ , line := range lines {
97+ line = strings .TrimSpace (line )
98+
99+ /* check for owner line (format: "# owner: username") */
100+ if strings .HasPrefix (line , "# owner:" ) {
101+ owner := strings .TrimSpace (strings .TrimPrefix (line , "# owner:" ))
102+
103+ /* compare with the provided CN (case-insensitive) */
104+ if strings .EqualFold (owner , userCN ) {
105+ return true , nil
106+ }
107+ }
108+
109+ /* also check user ACL entries (format: "user:username:permissions") */
110+ if strings .HasPrefix (line , "user:" ) && ! strings .HasPrefix (line , "user::" ) {
111+ parts := strings .Split (line , ":" )
112+ if len (parts ) >= 3 {
113+ aclUser := parts [1 ]
114+ permissions := parts [2 ]
115+
116116 /* check if this user has write permissions (indicating ownership-like access) */
117- if strings .EqualFold (aclUser , userCN ) && strings .Contains (permissions , "w" ) {
118- return true , nil
119- }
120- }
121- }
122- }
123-
124- return false , nil
117+ if strings .EqualFold (aclUser , userCN ) && strings .Contains (permissions , "w" ) {
118+ return true , nil
119+ }
120+ }
121+ }
122+ }
123+
124+ return false , nil
125125}
0 commit comments