56

I know that after I call (start-server) inside an existing Emacs session I can then use emacsclient -c (on the same computer) to create new frames that connect into that server, so that each new frame created by emacsclient has access to the same set of shared state (e.g. buffers).

Most of the documentation I've found focuses on the "give me fast access to my local Emacs" use case, and so there are two things that I haven't seen any details of yet:

  1. Can emacsclient -c access Emacs servers started by other users, or is it hard-wired to detect only sessions started by my own user?

  2. Does Emacs server (directly or indirectly) support remote connections? That is, is there some way to set up Emacs (possibly involving SSH) that allows calls to emacsclient -c on remote machines to have access to the local state of my Emacs server?

(In case you haven't already guessed, what I'd ultimately like to do is combine the two techniques above to provide rudimentary collaborative editing support.)


This is a real-world problem, so here's what I'm working with:

  • The necessary functionality should be built into Emacs already (23.3.1, 64-bit). I can stretch to Emacs extensions from the standard Ubuntu repositories, but I'd prefer not to. (Which I believe rules out Rudel, sadly.)
  • No new users or user spoofing. Solutions should work with the existing set of user accounts, and users must not pretend to be other users (e.g. via su or ssh).

If it makes any difference, the machines are on a private LAN, have OpenSSH clients and servers installed (and running), and all users can connect to (their own account on) all machines, but they have no shared filesystem.


So, does anybody know whether Emacs server can

  • grant access to other users, or
  • provide remote access?

EDIT

As commented in rwb's answer, it's clear that the new windows being opened locally by running emacsclient -c are actually being created by the remote Emacs server process. That is, emacsclient is simply triggering the relevant behaviour in the server. This causes some issues with incorrect display settings, since the server does not normally have access to the local desktop (see below). However, I can now connect in to a remote Emacs session if I use the following sequence of commands:

In one terminal, where 1.22.333.44 is the IP address of remotehost:

ssh -t -X remotehost \
  "emacs -nw --eval
   '(progn (setq server-host \"1.22.333.44\" server-use-tcp t) (server-start))'"

Then in another (on the same machine):

scp remotehost:.emacs.d/server/server /tmp/server-file
DISPLAY=localhost:10 emacsclient -c -f /tmp/server-file

The emacsclient command causes the remote Emacs server (which it finds details of in /tmp/server-file) to open up a graphical Emacs window (on the local display) that shares state with the Emacs session on the remote host.

Since the remote Emacs server was started via ssh -X, SSH provides it with access to my local display via a "fake" :10 display. The DISPLAY=:10 passed to it (via emacsclient) thus causes a window to be opened on my local desktop.


Although the approach above does tick the "Run Emacs server on remote machine, connect to it using emacsclient locally" box, it's very limited. In fact, it's not much different to running the server and clients all locally as a single user: the only difference is that the server is now remote, so has access to different system resources.

Unfortunately, launching via ssh -X is the only way I've been able to successfully open a window on a different machine's X server:

  • Specifying a basic DISPLAY=remote:0 gets nowhere (since Ubuntu X servers are started with the -nolisten tcp option).

  • Connecting via SSH and then using DISPLAY=:0 also fails, but this time only due to lack of suitable authentication credentials. (I believe that's the case, anyway: the error message cryptically says No protocol specified / Can't open display.)

I think that finding a way around the second problem would probably get me a good deal closer to a solution.


Having read the posts at http://comments.gmane.org/gmane.emacs.devel/103350 (starting at the '25 Oct 14:50' post, about half way down) I'm starting to wonder if this might be one of the rare things that Emacs cannot do (i.e. is impossible ;-) ).

However, if anyone does have a way to provide access to remote X displays without the permissions error above, I'm still open to persuasion....

TL;DR

As pointed out by rwb's answer, my questions above about whether Emacs can grant remote access have got things backwards. There's no real problem with Emacs granting access to other users (server-use-tcp and a suitable server-file take care of this): rather the problem is how to allow a process on one machine to open new X windows on other users' X displays (specifically, the Emacs running (start-server) needs to open windows for users who ask it to via emacsclient -c). That answer's beyond the scope of this question.

Alternative solution

As a workaround, we use the following:

  • machine0: tmux -S /tmp/shared-tmux-socket new-session
  • machine1..machineN: ssh -t machine0 tmux -S /tmp/shared-tmux-socket attach

with suitable file permissions on /tmp/shared-tmux-socket.

Then we run a text-mode Emacs in the shared terminal. :-) This does raise some user-spoofing questions, but at least the host can see everything that the guests are doing.

Paul Whittaker
  • 3,817
  • 3
  • 25
  • 20
  • http://stackoverflow.com/questions/2231902/originate-edit-of-remote-file-using-emacs-tramp-from-ssh-session has several -- much simpler -- answers for the question "how do I use `emacsclient` to connect to my local Emacs server when I have connected over `ssh`?" – tripleee Oct 20 '14 at 07:55

4 Answers4

16

This should provide a starting point for what you want.

From the info node (emacs) emacsclient Options

`--server-file=SERVER-FILE'
     Specify a "server file" for connecting to an Emacs server via TCP.

     An Emacs server usually uses an operating system feature called a
     "local socket" to listen for connections.  Some operating systems,
     such as Microsoft Windows, do not support local sockets; in that
     case, Emacs uses TCP instead.  When you start the Emacs server,
     Emacs creates a server file containing some TCP information that
     `emacsclient' needs for making the connection.  By default, the
     server file is in `~/.emacs.d/server/'.  On Microsoft Windows, if
     `emacsclient' does not find the server file there, it looks in the
     `.emacs.d/server/' subdirectory of the directory pointed to by the
     `APPDATA' environment variable.  You can tell `emacsclient' to use
     a specific server file with the `-f' or `--server-file' option, or
     by setting the `EMACS_SERVER_FILE' environment variable.

     Even if local sockets are available, you can tell Emacs to use TCP
     by setting the variable `server-use-tcp' to `t'.  One advantage of
     TCP is that the server can accept connections from remote machines.
     For this to work, you must (i) set the variable `server-host' to
     the hostname or IP address of the machine on which the Emacs server
     runs, and (ii) provide `emacsclient' with the server file.  (One
     convenient way to do the latter is to put the server file on a
     networked file system such as NFS.)

You also may want to look at variables server-auth-dir, server-auth-key and server-port

rwb
  • 538
  • 2
  • 5
  • That looks like what I'm after; I might even be able to use filesystem permissions to control access to the server file (and thus the session). Will try this and report back. – Paul Whittaker Sep 24 '12 at 16:00
  • The format of the server file is fairly straight-forward so you can generate it if you do not have a shared file system, as long as you set the correct variables. The one thing that cannot be controlled by a variable in the server file is the process ID but from looking at the source code its legacy data that should not matter if you are using TCP connections. – rwb Sep 26 '12 at 02:55
  • 1
    Looks like I'd misunderstood the subtleties of what `emacsclient -c` does. Now that I've had chance to play with it (using the options you suggested) and can successfully connect via TCP to a server on another host, it's clear the frames themselves are originating from the remote server. That is, not only does `emacsclient` need correct authorisation to connect to the server, the server also needs the correct authorisation for opening windows on the client-side display. This is currently non-functional for me. I may update my answer to reflect this new understanding. – Paul Whittaker Oct 04 '12 at 18:39
  • I can now make the remote Emacs server open new graphical windows for me locally. The solution was using `ssh -X` for connecting to the remote server, then giving the local call to `emacsclient` the setting of `DISPLAY` that was needed at the far end, which in this case was `localhost:10`. This still leaves the problem of X11 authentication, but is getting closer. – Paul Whittaker Oct 04 '12 at 19:17
  • Have updated question with more details. Am starting to suspect that multi-user `emacsclient` usage isn't going to fly. – Paul Whittaker Oct 04 '12 at 19:45
11

I think what you're asking for is impossible by definition, because if you give a remote user unrestricted access to your Emacs, this is just as much "user spoofing" as letting that remote user access a shell via ssh. To spell it out, from a security point of view this is probably a bad idea.

Also, the results of letting two users access one Emacs aren't as good as you might hope. It isn't designed with simultaneous access in mind. It's years since I tried it, so things might have moved on a bit, but when I did it was quirky to say the least.

Still, I'll try to answer your question.

It sounds like you're thinking about this back-to-front, because, counter-intuitively, in network terms, the X11 display is the server, and the X11 application is the client. This is surprising because typically the display is local to the user and the application is running on some remote server.

You can instruct a running emacs to connect to a remote display and open a new window with M-x make-frame-on-display. For this to work, the owner of that display will need to grant you access to it.

We will assume host-l is the computer that is running Emacs, and that you want to make it accessible to a user of display 0 on host-r. Be aware that you've said you don't want to use SSH forwarding, so following this method will cause all traffic will go across the network unencrypted.

First, make sure that display host-r:0 is accepting TCP connections. You don't mention your operating system, but this is probably the default on Unix and probably isn't on Linux (for security reasons). If, for example, the following mentions -nolisten tcp then you'll need to change this configuration.

host-r$ ps -ef | grep X

Next, get the user of host-r to run the following, and send you the output. Be sure to warn them that this will allow you to take complete control of their current desktop session, should you choose.

host-r$ xauth list $DISPLAY
host-r/unix:0  MIT-MAGIC-COOKIE-1  01234567890abcdef0123456789abcd

This is, effectively, the "password" for the display. On host-l, put it where Emacs will be able to find it with:

host-l$ xauth add host-r:0 MIT-MAGIC-COOKIE-1  01234567890abcdef0123456789abcd

Now enter M-x make-frame-on-display host-r:0 and an Emacs window should pop up on the remote display.

mavit
  • 619
  • 6
  • 13
  • Thanks Mavit. You're quite right about unrestricted Emacs access being just as bad as shell access would be from a security standpoint. Since that's what emacsclient provides I think I'm now satisfied: this approach isn't going to do what I initially wanted. I had hoped emacsclient would limit what other users could do (e.g. buffer changes only) but that now sounds more like Rudel's territory. – Paul Whittaker May 02 '13 at 18:06
  • I don't actually mind SSH X forwarding per se (I've edited the question to make it clearer what I was trying to avoid) so I might well try out your xauth steps then use make-frame-on-display next time I need something like this. [For anyone else trying this, connections to localhost use 'hostname/unix:0' in the xauth command rather than 'host-r:0', where hostname is the short name of localhost as output by `hostname -s`.] – Paul Whittaker May 02 '13 at 18:23
7

Aaron Gallagher implemented a solution: http://blog.habnab.it/blog/2013/06/25/emacsclient-and-tramp/

It works (AFAIU) like:

  • emacs server is started with tcp
  • He opens a connection to a remote system with tramp-sh, opening a forward port ("back channel")
  • tramp-sh is advised to copy an extended auth cookie file to the remote system
  • On the remote system he calls a special emacsclient.sh shell script that emulates emacsclient but prefixes the file names with the corresponding tramp prefix that is found in the extended auth cookie

I've added a comment to his blog post proposing this idea to be discussed and enhanced on emacs-devel.

Thomas Koch
  • 2,833
  • 2
  • 28
  • 36
4

If you are doing this to enable people to remotely edit files you may want to look at 'tramp mode'

http://emacswiki.org/emacs/TrampMode

sean_m
  • 1,564
  • 1
  • 12
  • 14
  • Thanks Sean; that's a good suggestion, especially as I can use Tramp over SSH. If I can't get something more interactive working, then a (well-coordinated) reload -> edit -> save cycle will make a decent fallback. – Paul Whittaker Sep 24 '12 at 16:03