]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve SELinux handling in Tramp
authorMichael Albinus <michael.albinus@gmx.de>
Thu, 3 Aug 2023 11:17:02 +0000 (13:17 +0200)
committerMichael Albinus <michael.albinus@gmx.de>
Thu, 3 Aug 2023 11:17:02 +0000 (13:17 +0200)
* lisp/net/tramp-sh.el (tramp-stat-file-attributes-with-selinux)
(tramp-stat-directory-files-and-attributes-with-selinux): New defconst.
(tramp-do-file-attributes-with-ls)
(tramp-do-file-attributes-with-stat)
(tramp-do-directory-files-and-attributes-with-stat): Return also
SELinux context.
(tramp-remote-selinux-p, tramp-do-copy-or-rename-file): Adapt docstring.

* lisp/net/tramp-sudoedit.el (tramp-sudoedit-do-copy-or-rename-file)
(tramp-sudoedit-remote-selinux-p): Adapt docstring.
(tramp-sudoedit-file-attributes-with-selinux): New defconst.
(tramp-sudoedit-handle-file-attributes): Use it.

* lisp/net/tramp.el (tramp-convert-file-attributes):
Extract SELinux context.

lisp/net/tramp-sh.el
lisp/net/tramp-sudoedit.el
lisp/net/tramp.el

index b33e788b8935246bf06b3ec33f42996aa4ff852f..2b1d26dd232888bc84a1cbe7eefbf19f8889c3c8 100644 (file)
@@ -717,6 +717,25 @@ on the remote file system.
 Format specifiers are replaced by `tramp-expand-script', percent
 characters need to be doubled.")
 
+(defconst tramp-stat-file-attributes-with-selinux
+  (format
+   (concat
+    "(%%s -c"
+    " '((%s%%%%N%s) %%%%h (%s%%%%U%s . %%%%u) (%s%%%%G%s . %%%%g)"
+    " %%%%X %%%%Y %%%%Z %%%%s %s%%%%A%s t %%%%i -1 %s%%%%C%s)'"
+    " \"$1\" %%n || echo nil) |"
+    " sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g'")
+   tramp-stat-marker tramp-stat-marker ; %%N
+   tramp-stat-marker tramp-stat-marker ; %%U
+   tramp-stat-marker tramp-stat-marker ; %%G
+   tramp-stat-marker tramp-stat-marker ; %%A
+   tramp-stat-marker tramp-stat-marker ; %%C
+   tramp-stat-quoted-marker)
+  "Shell function to produce output suitable for use with `file-attributes'
+on the remote file system, including SELinux context.
+Format specifiers are replaced by `tramp-expand-script', percent
+characters need to be doubled.")
+
 (defconst tramp-perl-directory-files-and-attributes
   "%p -e '
 chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
@@ -795,6 +814,33 @@ characters need to be doubled.")
 Format specifiers are replaced by `tramp-expand-script', percent
 characters need to be doubled.")
 
+(defconst tramp-stat-directory-files-and-attributes-with-selinux
+  (format
+   (concat
+    ;; We must care about file names with spaces, or starting with
+    ;; "-"; this would confuse xargs.  "ls -aQ" might be a solution,
+    ;; but it does not work on all remote systems.  Therefore, we use
+    ;; \000 as file separator.  `tramp-sh--quoting-style-options' do
+    ;; not work for file names with spaces piped to "xargs".
+    ;; Apostrophes in the stat output are masked as
+    ;; `tramp-stat-marker', in order to make a proper shell escape of
+    ;; them in file names.
+    "cd \"$1\" && echo \"(\"; (%%l -a | tr '\\n\\r' '\\000\\000' |"
+    " xargs -0 %%s -c"
+    " '(%s%%%%n%s (%s%%%%N%s) %%%%h (%s%%%%U%s . %%%%u) (%s%%%%G%s . %%%%g) %%%%X %%%%Y %%%%Z %%%%s %s%%%%A%s t %%%%i -1 %s%%%%C%s)'"
+    " -- %%n | sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g'); echo \")\"")
+   tramp-stat-marker tramp-stat-marker ; %n
+   tramp-stat-marker tramp-stat-marker ; %N
+   tramp-stat-marker tramp-stat-marker ; %U
+   tramp-stat-marker tramp-stat-marker ; %G
+   tramp-stat-marker tramp-stat-marker ; %A
+   tramp-stat-marker tramp-stat-marker ; %C
+   tramp-stat-quoted-marker)
+  "Shell function implementing `directory-files-and-attributes' as Lisp
+`read'able output, including SELinux context.
+Format specifiers are replaced by `tramp-expand-script', percent
+characters need to be doubled.")
+
 (defconst tramp-perl-id
   "%p -e '
 use strict;
@@ -1255,10 +1301,10 @@ Operations not mentioned here will be handled by the normal Emacs functions.")
   (let (symlinkp dirp
        res-inode res-filemodes res-numlinks
        res-uid-string res-gid-string res-uid-integer res-gid-integer
-       res-size res-symlink-target)
+       res-size res-symlink-target res-context)
     (tramp-message vec 5 "file attributes with ls: %s" localname)
-    ;; We cannot send all three commands combined, it could exceed
-    ;; NAME_MAX or PATH_MAX.  Happened on macOS, for example.
+    ;; We cannot send both commands combined, it could exceed NAME_MAX
+    ;; or PATH_MAX.  Happened on macOS, for example.
     (when (tramp-send-command-and-check
            vec
            (format "cd %s && (%s %s || %s -h %s)"
@@ -1277,13 +1323,14 @@ Operations not mentioned here will be handled by the normal Emacs functions.")
                      (file-name-nondirectory localname)))))
       (tramp-send-command
        vec
-       (format "%s -ild %s %s; %s -lnd %s %s"
+       (format "%s -ild %s %s; %s -lnd%s %s %s"
                (tramp-get-ls-command vec)
                ;; On systems which have no quoting style, file names
                ;; with special characters could fail.
                (tramp-sh--quoting-style-options vec)
                (tramp-shell-quote-argument localname)
                (tramp-get-ls-command vec)
+              (if (tramp-remote-selinux-p vec) "Z" "")
                ;; On systems which have no quoting style, file names
                ;; with special characters could fail.
                (tramp-sh--quoting-style-options vec)
@@ -1333,6 +1380,10 @@ Operations not mentioned here will be handled by the normal Emacs functions.")
            (setq res-uid-integer tramp-unknown-id-integer))
           (unless (numberp res-gid-integer)
            (setq res-gid-integer tramp-unknown-id-integer))
+         ;; ... SELinux context
+         (when (tramp-remote-selinux-p vec)
+           (setq res-context (read (current-buffer))
+                 res-context (symbol-name res-context)))
 
          ;; Return data gathered.
           (list
@@ -1359,7 +1410,10 @@ Operations not mentioned here will be handled by the normal Emacs functions.")
            ;; 10. Inode number.
            res-inode
            ;; 11. Device number.  Will be replaced by a virtual device number.
-           -1))))))
+           -1
+          ;; 12. SELinux context.  Will be extracted in
+          ;; `tramp-convert-file-attributes'.
+          res-context))))))
 
 (defun tramp-do-file-attributes-with-perl (vec localname)
   "Implement `file-attributes' for Tramp files using a Perl script."
@@ -1373,11 +1427,20 @@ Operations not mentioned here will be handled by the normal Emacs functions.")
 (defun tramp-do-file-attributes-with-stat (vec localname)
   "Implement `file-attributes' for Tramp files using stat(1) command."
   (tramp-message vec 5 "file attributes with stat: %s" localname)
-  (tramp-maybe-send-script
-   vec tramp-stat-file-attributes "tramp_stat_file_attributes")
-  (tramp-send-command-and-read
-   vec (format "tramp_stat_file_attributes %s"
-              (tramp-shell-quote-argument localname))))
+  (cond
+   ((tramp-remote-selinux-p vec)
+    (tramp-maybe-send-script
+     vec tramp-stat-file-attributes-with-selinux
+     "tramp_stat_file_attributes_with_selinux")
+    (tramp-send-command-and-read
+     vec (format "tramp_stat_file_attributes_with_selinux %s"
+                (tramp-shell-quote-argument localname))))
+   (t
+    (tramp-maybe-send-script
+     vec tramp-stat-file-attributes "tramp_stat_file_attributes")
+    (tramp-send-command-and-read
+     vec (format "tramp_stat_file_attributes %s"
+                (tramp-shell-quote-argument localname))))))
 
 (defun tramp-sh-handle-set-visited-file-modtime (&optional time-list)
   "Like `set-visited-file-modtime' for Tramp files."
@@ -1572,7 +1635,7 @@ ID-FORMAT valid values are `string' and `integer'."
              (tramp-shell-quote-argument localname))))))))
 
 (defun tramp-remote-selinux-p (vec)
-  "Check, whether SELINUX is enabled on the remote host."
+  "Check, whether SELinux is enabled on the remote host."
   (with-tramp-connection-property (tramp-get-process vec) "selinux-p"
     (tramp-send-command-and-check vec "selinuxenabled")))
 
@@ -1775,12 +1838,21 @@ ID-FORMAT valid values are `string' and `integer'."
 (defun tramp-do-directory-files-and-attributes-with-stat (vec localname)
   "Implement `directory-files-and-attributes' for Tramp files with stat(1) command."
   (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
-  (tramp-maybe-send-script
-   vec tramp-stat-directory-files-and-attributes
-   "tramp_stat_directory_files_and_attributes")
-  (tramp-send-command-and-read
-   vec (format "tramp_stat_directory_files_and_attributes %s"
-              (tramp-shell-quote-argument localname))))
+  (cond
+   ((tramp-remote-selinux-p vec)
+    (tramp-maybe-send-script
+     vec tramp-stat-directory-files-and-attributes-with-selinux
+     "tramp_stat_directory_files_and_attributes_with_selinux")
+    (tramp-send-command-and-read
+     vec (format "tramp_stat_directory_files_and_attributes_with_selinux %s"
+                (tramp-shell-quote-argument localname))))
+   (t
+    (tramp-maybe-send-script
+     vec tramp-stat-directory-files-and-attributes
+     "tramp_stat_directory_files_and_attributes")
+    (tramp-send-command-and-read
+     vec (format "tramp_stat_directory_files_and_attributes %s"
+                (tramp-shell-quote-argument localname))))))
 
 ;; This function should return "foo/" for directories and "bar" for
 ;; files.
@@ -1966,7 +2038,7 @@ OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
 KEEP-DATE means to make sure that NEWNAME has the same timestamp
 as FILENAME.  PRESERVE-UID-GID, when non-nil, instructs to keep
 the uid and gid if both files are on the same host.
-PRESERVE-EXTENDED-ATTRIBUTES activates selinux and acl commands.
+PRESERVE-EXTENDED-ATTRIBUTES activates SELinux and ACL commands.
 
 This function is invoked by `tramp-sh-handle-copy-file' and
 `tramp-sh-handle-rename-file'.  It is an error if OP is neither
index 2ce2647b5ac9cc1c337dc44e370c0866ef155d09..3d6e1d92d0b15283fca3b2dadb7aab0bbc0683d9 100644 (file)
@@ -234,7 +234,7 @@ OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
 KEEP-DATE means to make sure that NEWNAME has the same timestamp
 as FILENAME.  PRESERVE-UID-GID, when non-nil, instructs to keep
 the uid and gid if both files are on the same host.
-PRESERVE-EXTENDED-ATTRIBUTES activates selinux and acl commands.
+PRESERVE-EXTENDED-ATTRIBUTES activates SELinux and ACL commands.
 
 This function is invoked by `tramp-sudoedit-handle-copy-file' and
 `tramp-sudoedit-handle-rename-file'.  It is an error if OP is
@@ -434,14 +434,37 @@ the result will be a local, non-Tramp, file name."
   "stat format string to produce output suitable for use with
 `file-attributes' on the remote file system.")
 
+(defconst tramp-sudoedit-file-attributes-with-selinux
+  (format
+   ;; Apostrophes in the stat output are masked as
+   ;; `tramp-stat-marker', in order to make a proper shell escape of
+   ;; them in file names.  They are replaced in
+   ;; `tramp-sudoedit-send-command-and-read'.
+   (concat "((%s%%N%s) %%h (%s%%U%s . %%u) (%s%%G%s . %%g)"
+          " %%X %%Y %%Z %%s %s%%A%s t %%i -1 %s%%C%s)")
+   tramp-stat-marker tramp-stat-marker  ; %%N
+   tramp-stat-marker tramp-stat-marker  ; %%U
+   tramp-stat-marker tramp-stat-marker  ; %%G
+   tramp-stat-marker tramp-stat-marker  ; %%A
+   tramp-stat-marker tramp-stat-marker) ; %%C
+  "stat format string to produce output suitable for use with
+`file-attributes' on the remote file system, including SELinux context.")
+
 (defun tramp-sudoedit-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
   ;; The result is cached in `tramp-convert-file-attributes'.
   (with-parsed-tramp-file-name (expand-file-name filename) nil
     (tramp-convert-file-attributes v localname id-format
-      (tramp-sudoedit-send-command-and-read
-       v "env" "QUOTING_STYLE=locale" "stat" "-c"
-       tramp-sudoedit-file-attributes (file-name-unquote localname)))))
+      (cond
+       ((tramp-sudoedit-remote-selinux-p v)
+       (tramp-sudoedit-send-command-and-read
+        v "env" "QUOTING_STYLE=locale" "stat" "-c"
+        tramp-sudoedit-file-attributes-with-selinux
+        (file-name-unquote localname)))
+       (t
+       (tramp-sudoedit-send-command-and-read
+        v "env" "QUOTING_STYLE=locale" "stat" "-c"
+        tramp-sudoedit-file-attributes (file-name-unquote localname)))))))
 
 (defun tramp-sudoedit-handle-file-executable-p (filename)
   "Like `file-executable-p' for Tramp files."
@@ -507,7 +530,7 @@ the result will be a local, non-Tramp, file name."
         v 'file-error "Error while changing file's mode %s" filename)))))
 
 (defun tramp-sudoedit-remote-selinux-p (vec)
-  "Check, whether SELINUX is enabled on the remote host."
+  "Check, whether SELinux is enabled on the remote host."
   (with-tramp-connection-property (tramp-get-process vec) "selinux-p"
     (zerop (tramp-call-process vec "selinuxenabled"))))
 
index 0267b69340dfc4521c3e0dc94e81bbb33f5da66b..31b91b4e91070d73dc947b7465d0659edf07f1de 100644 (file)
@@ -6055,6 +6055,13 @@ to cache the result.  Return the modified ATTR."
                 ;; Set virtual device number.
                 (setcar (nthcdr 11 attr)
                         (tramp-get-device ,vec))
+                ;; Set SELinux context.
+                (when (stringp (nth 12 attr))
+                  (tramp-set-file-property
+                   ,vec ,localname  "file-selinux-context"
+                   (split-string (nth 12 attr) ":" 'omit)))
+                ;; Remove optional entries.
+                (setcdr (nthcdr 11 attr) nil)
                 attr)))))
 
        ;; Return normalized result.