1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-30 12:21:25 -08:00

Use connection-aware functions when getting the UID/GID in Eshell

This means, for example, that when using Tramp to sudo in Eshell, "rm"
queries the user before deleting anything (bug#63221).

* lisp/eshell/esh-util.el (eshell-user-login-name): New function...
* lisp/eshell/em-unix.el (eshell/whoami): ... use it.

* lisp/eshell/em-ls.el (eshell-ls-applicable): Use 'file-user-uid' and
'eshell-user-login-name'.
(eshell-ls-decorated-name): Use 'file-user-uid'.

* lisp/eshell/em-pred.el (eshell-predicate-alist): Use 'file-user-uid'
and 'file-group-gid'.

* lisp/eshell/em-unix.el (eshell-interactive-query): New widget...
(eshell-rm-interactive-query, eshell-mv-interactive-query)
(eshell-cp-interactive-query, eshell-ln-interactive-query): ... use
it.
(eshell-interactive-query-p): New function...
(eshell/rm, eshell/mv, eshell/cp, eshell/ln): ... use it.

* lisp/simple.el (file-group-gid): New function.

* lisp/net/ange-ftp.el (ange-ftp-file-group-gid): New function...
(file-group-gid): ... use it.

* lisp/net/tramp.el (tramp-handle-file-group-gid):
* lisp/net/tramp-archive.el (tramp-archive-handle-file-group-gid): New
functions.

* lisp/net/tramp.el (tramp-file-name-for-operation): Add
'file-group-gid'.

* lisp/net/tramp-adb.el (tramp-adb-file-name-handler-alist):
* lisp/net/tramp-archive.el (tramp-archive-file-name-handler-alist):
* lisp/net/tramp-crypt.el (tramp-crypt-file-name-handler-alist):
* lisp/net/tramp-gvfs.el (tramp-gvfs-file-name-handler-alist):
* lisp/net/tramp-rclone.el (tramp-rclone-file-name-handler-alist):
* lisp/net/tramp-sh.el (tramp-sh-file-name-handler-alist):
* lisp/net/tramp-smb.el (tramp-smb-file-name-handler-alist):
* lisp/net/tramp-sshfs.el (tramp-sshfs-file-name-handler-alist):
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-file-name-handler-alist):
Add 'file-group-gid' mapping.

* test/lisp/net/tramp-tests.el (tramp-test44-file-user-group-ids):
* test/lisp/net/tramp-archive-tests.el
(tramp-archive-test44-file-user-group-ids): Add tests for
'file-group-gid'.

* doc/lispref/files.texi (Magic File Names): Mention 'file-group-gid'.

* doc/lispref/os.texi (User Identification): Document
'file-group-gid', and move 'group-real-gid' to match the order of
'user-real-uid'.

* etc/NEWS: Announce 'file-group-gid'.
This commit is contained in:
Jim Porter 2023-05-01 09:49:00 -07:00
parent fa33a14ebe
commit 40d6609563
21 changed files with 143 additions and 44 deletions

View file

@ -3405,7 +3405,7 @@ first, before handlers for jobs such as remote file access.
@code{file-readable-p}, @code{file-regular-p},
@code{file-remote-p}, @code{file-selinux-context},
@code{file-symlink-p}, @code{file-system-info},
@code{file-truename}, @code{file-user-uid},
@code{file-truename}, @code{file-user-uid}, @code{file-group-gid},
@code{file-writable-p},
@code{find-backup-file-name},@*
@code{get-file-buffer},
@ -3467,7 +3467,7 @@ first, before handlers for jobs such as remote file access.
@code{file-readable-p}, @code{file-regular-p},
@code{file-remote-p}, @code{file-selinux-context},
@code{file-symlink-p}, @code{file-system-info},
@code{file-truename}, @code{file-user-uid},
@code{file-truename}, @code{file-user-uid}, @code{file-group-gid},
@code{file-writable-p},
@code{find-backup-file-name},
@code{get-file-buffer},

View file

@ -1290,12 +1290,22 @@ the remote connection has no associated user, it will instead return
@end defun
@cindex GID
@defun group-real-gid
This function returns the real @acronym{GID} of the Emacs process.
@end defun
@defun group-gid
This function returns the effective @acronym{GID} of the Emacs process.
@end defun
@defun group-real-gid
This function returns the real @acronym{GID} of the Emacs process.
@defun file-group-gid
This function returns the connection-local value for the user's
effective @acronym{GID}. Similar to @code{file-user-uid}, if
@code{default-directory} is local, this is equivalent to
@code{group-gid}, but for remote files (@pxref{Remote Files, , ,
emacs, The GNU Emacs Manual}), it will return the @acronym{GID} for
the user associated with that remote connection; if the remote
connection has no associated user, it will instead return -1.
@end defun
@defun system-users

View file

@ -529,10 +529,10 @@ The declaration '(important-return-value t)' sets the
return value should probably not be thrown away implicitly.
+++
** New function 'file-user-uid'.
This function is like 'user-uid', but is aware of file name handlers,
so it will return the remote UID for remote files (or -1 if the
connection has no associated user).
** New functions 'file-user-uid' and 'file-group-gid'.
These functions are like 'user-uid' and 'group-gid', respectively, but
are aware of file name handlers, so they will return the remote UID or
GID for remote files (or -1 if the connection has no associated user).
+++
** 'fset', 'defalias' and 'defvaralias' now signal an error for cyclic aliases.

View file

@ -199,9 +199,9 @@ calling FUNC with FILE as an argument."
`(let ((owner (file-attribute-user-id ,attrs))
(modes (file-attribute-modes ,attrs)))
(cond ((cond ((numberp owner)
(= owner (user-uid)))
(= owner (file-user-uid)))
((stringp owner)
(or (string-equal owner (user-login-name))
(or (string-equal owner (eshell-user-login-name))
(member owner (eshell-current-ange-uids)))))
;; The user owns this file.
(not (eq (aref modes ,index) ?-)))
@ -919,7 +919,7 @@ to use, and each member of which is the width of that column
((not (eshell-ls-filetype-p (cdr file) ?-))
'eshell-ls-special)
((and (/= (user-uid) 0) ; root can execute anything
((and (/= (file-user-uid) 0) ; root can execute anything
(eshell-ls-applicable (cdr file) 3
'file-executable-p (car file)))
'eshell-ls-executable)

View file

@ -87,11 +87,11 @@ ordinary strings."
(?U . (lambda (file) ; owned by effective uid
(if (file-exists-p file)
(= (file-attribute-user-id (file-attributes file))
(user-uid)))))
(file-user-uid)))))
(?G . (lambda (file) ; owned by effective gid
(if (file-exists-p file)
(= (file-attribute-group-id (file-attributes file))
(group-gid)))))
(file-group-gid)))))
(?* . (lambda (file)
(and (file-regular-p file)
(not (file-symlink-p file))

View file

@ -91,14 +91,29 @@ Otherwise, `rmdir' is required."
:type 'boolean
:group 'eshell-unix)
(defcustom eshell-rm-interactive-query (= (user-uid) 0)
"If non-nil, `rm' will query before removing anything."
:type 'boolean
(define-widget 'eshell-interactive-query 'radio
"When to interatively query the user about a particular operation.
If t, always query. If nil, never query. If `root', query when
the user is logged in as root (including when `default-directory'
is remote with a root user)."
:args '((const :tag "Never" nil)
(const :tag "Always" t)
(const :tag "When root" root)))
(defcustom eshell-rm-interactive-query 'root
"When `rm' should query before removing anything.
If t, always query. If nil, never query. If `root', query when
the user is logged in as root (including when `default-directory'
is remote with a root user)."
:type 'eshell-interactive-query
:group 'eshell-unix)
(defcustom eshell-mv-interactive-query (= (user-uid) 0)
"If non-nil, `mv' will query before overwriting anything."
:type 'boolean
(defcustom eshell-mv-interactive-query 'root
"When `mv' should query before overwriting anything.
If t, always query. If nil, never query. If `root', query when
the user is logged in as root (including when `default-directory'
is remote with a root user)."
:type 'eshell-interactive-query
:group 'eshell-unix)
(defcustom eshell-mv-overwrite-files t
@ -106,9 +121,12 @@ Otherwise, `rmdir' is required."
:type 'boolean
:group 'eshell-unix)
(defcustom eshell-cp-interactive-query (= (user-uid) 0)
"If non-nil, `cp' will query before overwriting anything."
:type 'boolean
(defcustom eshell-cp-interactive-query 'root
"When `cp' should query before overwriting anything.
If t, always query. If nil, never query. If `root', query when
the user is logged in as root (including when `default-directory'
is remote with a root user)."
:type 'eshell-interactive-query
:group 'eshell-unix)
(defcustom eshell-cp-overwrite-files t
@ -116,9 +134,12 @@ Otherwise, `rmdir' is required."
:type 'boolean
:group 'eshell-unix)
(defcustom eshell-ln-interactive-query (= (user-uid) 0)
"If non-nil, `ln' will query before overwriting anything."
:type 'boolean
(defcustom eshell-ln-interactive-query 'root
"When `ln' should query before overwriting anything.
If t, always query. If nil, never query. If `root', query when
the user is logged in as root (including when `default-directory'
is remote with a root user)."
:type 'eshell-interactive-query
:group 'eshell-unix)
(defcustom eshell-ln-overwrite-files nil
@ -159,6 +180,17 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
(defvar em-recursive)
(defvar em-verbose)
(defun eshell-interactive-query-p (value)
"Return non-nil if a command should query the user according to VALUE.
If VALUE is nil, return nil (never query). If `root', return
non-nil if the user is logged in as root (including when
`default-directory' is remote with a root user; see
`file-user-uid'). If VALUE is any other non-nil value, return
non-nil (always query)."
(if (eq value 'root)
(= (file-user-uid) 0)
value))
(defun eshell/man (&rest args)
"Invoke man, flattening the arguments appropriately."
(funcall 'man (apply 'eshell-flatten-and-stringify args)))
@ -249,7 +281,8 @@ argument."
:usage "[OPTION]... FILE...
Remove (unlink) the FILE(s).")
(unless em-interactive
(setq em-interactive eshell-rm-interactive-query))
(setq em-interactive (eshell-interactive-query-p
eshell-rm-interactive-query)))
(if (and force-removal em-interactive)
(setq em-interactive nil))
(while args
@ -523,7 +556,8 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
[OPTION] DIRECTORY...")
(let ((no-dereference t))
(eshell-mvcpln-template "mv" "moving" 'rename-file
eshell-mv-interactive-query
(eshell-interactive-query-p
eshell-mv-interactive-query)
eshell-mv-overwrite-files))))
(put 'eshell/mv 'eshell-no-numeric-conversions t)
@ -561,7 +595,8 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
(if archive
(setq preserve t no-dereference t em-recursive t))
(eshell-mvcpln-template "cp" "copying" 'copy-file
eshell-cp-interactive-query
(eshell-interactive-query-p
eshell-cp-interactive-query)
eshell-cp-overwrite-files preserve)))
(put 'eshell/cp 'eshell-no-numeric-conversions t)
@ -594,7 +629,8 @@ with `--symbolic'. When creating hard links, each TARGET must exist.")
(if symbolic
'make-symbolic-link
'add-name-to-file)
eshell-ln-interactive-query
(eshell-interactive-query-p
eshell-ln-interactive-query)
eshell-ln-overwrite-files))))
(put 'eshell/ln 'eshell-no-numeric-conversions t)
@ -960,7 +996,7 @@ Show wall-clock time elapsed during execution of COMMAND.")
(defun eshell/whoami (&rest _args)
"Make \"whoami\" Tramp aware."
(or (file-remote-p default-directory 'user) (user-login-name)))
(eshell-user-login-name))
(defvar eshell-diff-window-config nil)

View file

@ -502,6 +502,11 @@ list."
(sit-for 0)
(error nil)))
(defun eshell-user-login-name ()
"Return the connection-aware value of the user's login name.
See also `user-login-name'."
(or (file-remote-p default-directory 'user) (user-login-name)))
(defun eshell-read-passwd-file (file)
"Return an alist correlating gids to group names in FILE."
(let (names)

View file

@ -4381,7 +4381,11 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
(ange-ftp-real-find-backup-file-name fn)))
(defun ange-ftp-file-user-uid ()
;; Return "don't know" value.
;; Return "don't know" value.
-1)
(defun ange-ftp-file-group-gid ()
;; Return "don't know" value.
-1)
;;; Define the handler for special file names
@ -4524,8 +4528,9 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
(put 'file-notify-rm-watch 'ange-ftp 'ignore)
(put 'file-notify-valid-p 'ange-ftp 'ignore)
;; Return the "don't know' value for remote user uid.
;; Return the "don't know" value for remote user uid and group gid.
(put 'file-user-uid 'ange-ftp 'ange-ftp-file-user-uid)
(put 'file-group-gid 'ange-ftp 'ange-ftp-file-group-gid)
;;; Define ways of getting at unmodified Emacs primitives,
;;; turning off our handler.

View file

@ -154,6 +154,7 @@ It is used for TCP/IP devices."
(file-system-info . tramp-adb-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
(file-user-uid . tramp-handle-file-user-uid)
(file-group-gid . tramp-handle-file-group-gid)
(file-writable-p . tramp-adb-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -266,6 +266,7 @@ It must be supported by libarchive(3).")
(file-system-info . tramp-archive-handle-file-system-info)
(file-truename . tramp-archive-handle-file-truename)
(file-user-uid . tramp-archive-handle-file-user-uid)
(file-group-gid . tramp-archive-handle-file-group-gid)
(file-writable-p . ignore)
(find-backup-file-name . ignore)
;; `get-file-buffer' performed by default handler.
@ -678,6 +679,13 @@ offered."
;; `file-user-uid' exists since Emacs 30.1.
(tramp-compat-funcall 'file-user-uid))))
(defun tramp-archive-handle-file-group-gid ()
"Like `group-gid' for file archives."
(with-parsed-tramp-archive-file-name default-directory nil
(let ((default-directory (file-name-directory archive)))
;; `file-group-gid' exists since Emacs 30.1.
(tramp-compat-funcall 'file-group-gid))))
(defun tramp-archive-handle-insert-directory
(filename switches &optional wildcard full-directory-p)
"Like `insert-directory' for file archives."

View file

@ -205,6 +205,7 @@ If NAME doesn't belong to an encrypted remote directory, return nil."
(file-system-info . tramp-crypt-handle-file-system-info)
;; `file-truename' performed by default handler.
;; `file-user-uid' performed by default-handler.
;; `file-group-gid' performed by default-handler.
(file-writable-p . tramp-crypt-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -831,6 +831,7 @@ It has been changed in GVFS 1.14.")
(file-system-info . tramp-gvfs-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
(file-user-uid . tramp-handle-file-user-uid)
(file-group-gid . tramp-handle-file-group-gid)
(file-writable-p . tramp-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -119,6 +119,7 @@
(file-system-info . tramp-rclone-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
(file-user-uid . tramp-handle-file-user-uid)
(file-group-gid . tramp-handle-file-group-gid)
(file-writable-p . tramp-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -1097,6 +1097,7 @@ Format specifiers \"%s\" are replaced before the script is used.")
(file-system-info . tramp-sh-handle-file-system-info)
(file-truename . tramp-sh-handle-file-truename)
(file-user-uid . tramp-handle-file-user-uid)
(file-group-gid . tramp-handle-file-group-gid)
(file-writable-p . tramp-sh-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -270,6 +270,7 @@ See `tramp-actions-before-shell' for more info.")
(file-system-info . tramp-smb-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
(file-user-uid . tramp-handle-file-user-uid)
(file-group-gid . tramp-handle-file-group-gid)
(file-writable-p . tramp-smb-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -125,6 +125,7 @@
(file-system-info . tramp-sshfs-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
(file-user-uid . tramp-handle-file-user-uid)
(file-group-gid . tramp-handle-file-group-gid)
(file-writable-p . tramp-sshfs-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -115,6 +115,7 @@ See `tramp-actions-before-shell' for more info.")
(file-system-info . tramp-sudoedit-handle-file-system-info)
(file-truename . tramp-sudoedit-handle-file-truename)
(file-user-uid . tramp-handle-file-user-uid)
(file-group-gid . tramp-handle-file-group-gid)
(file-writable-p . tramp-sudoedit-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.

View file

@ -2650,7 +2650,7 @@ Must be handled by the callers."
;; Emacs 29+ only.
list-system-processes memory-info process-attributes
;; Emacs 30+ only.
file-user-uid))
file-user-uid file-group-gid))
default-directory)
;; PROC.
((member operation '(file-notify-rm-watch file-notify-valid-p))
@ -3939,6 +3939,15 @@ Let-bind it when necessary.")
;; consistency.
tramp-unknown-id-integer)))
(defun tramp-handle-file-group-gid ()
"Like `group-gid' for Tramp files."
(let ((v (tramp-dissect-file-name default-directory)))
(or (tramp-get-remote-gid v 'integer)
;; Some handlers for `tramp-get-remote-gid' return nil if they
;; can't get the GID; always return -1 in this case for
;; consistency.
tramp-unknown-id-integer)))
(defun tramp-handle-access-file (filename string)
"Like `access-file' for Tramp files."
(setq filename (file-truename filename))

View file

@ -4753,6 +4753,18 @@ this function will instead return -1."
(funcall handler 'file-user-uid)
(user-uid)))
(defun file-group-gid ()
"Return the connection-local effective gid.
This is similar to `group-gid', but may invoke a file name handler
based on `default-directory'. See Info node `(elisp)Magic File
Names'.
If a file name handler is unable to retrieve the effective gid,
this function will instead return -1."
(if-let ((handler (find-file-name-handler default-directory 'file-group-gid)))
(funcall handler 'file-group-gid)
(group-gid)))
(defun max-mini-window-lines (&optional frame)
"Compute maximum number of lines for echo area in FRAME.
As defined by `max-mini-window-height'. FRAME defaults to the

View file

@ -881,16 +881,18 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
(zerop (nth 1 fsi))
(zerop (nth 2 fsi))))))
;; `file-user-uid' was introduced in Emacs 30.1.
(ert-deftest tramp-archive-test44-file-user-uid ()
;; `file-user-uid' and `file-group-gid' were introduced in Emacs 30.1.
(ert-deftest tramp-archive-test44-user-group-ids ()
"Check that `file-user-uid' returns proper values."
(skip-unless tramp-archive-enabled)
(skip-unless (fboundp 'file-user-uid))
(skip-unless (and (fboundp 'file-user-uid)
(fboundp 'file-group-gid)))
(let ((default-directory tramp-archive-test-archive))
;; `file-user-uid' exists since Emacs 30.1. We don't want to see
;; compiler warnings for older Emacsen.
(should (integerp (with-no-warnings (file-user-uid))))))
;; `file-user-uid' and `file-group-gid' exist since Emacs 30.1.
;; We don't want to see compiler warnings for older Emacsen.
(should (integerp (with-no-warnings (file-user-uid))))
(should (integerp (with-no-warnings (file-group-gid))))))
(ert-deftest tramp-archive-test48-auto-load ()
"Check that `tramp-archive' autoloads properly."

View file

@ -7367,16 +7367,20 @@ This requires restrictions of file name syntax."
(dotimes (i (length fsi))
(should (natnump (or (nth i fsi) 0))))))
;; `file-user-uid' was introduced in Emacs 30.1.
(ert-deftest tramp-test44-file-user-uid ()
"Check that `file-user-uid' and `tramp-get-remote-*' return proper values."
;; `file-user-uid' and `file-group-gid' were introduced in Emacs 30.1.
(ert-deftest tramp-test44-file-user-group-ids ()
"Check results of user/group functions.
`file-user-uid', `file-group-gid', and `tramp-get-remote-*'
should all return proper values."
(skip-unless (tramp--test-enabled))
(let ((default-directory ert-remote-temporary-file-directory))
;; `file-user-uid' exists since Emacs 30.1. We don't want to see
;; compiler warnings for older Emacsen.
;; `file-user-uid' and `file-group-gid' exist since Emacs 30.1.
;; We don't want to see compiler warnings for older Emacsen.
(when (fboundp 'file-user-uid)
(should (integerp (with-no-warnings (file-user-uid)))))
(when (fboundp 'file-group-gid)
(should (integerp (with-no-warnings (file-group-gid)))))
(with-parsed-tramp-file-name default-directory nil
(should (or (integerp (tramp-get-remote-uid v 'integer))