Discussion:
[systemd-devel] Running pam-enabled /bin/login sessions in unprivileged terminal emulators
nerdopolis
2021-05-16 23:41:30 UTC
Permalink
Hi

I am trying to experiment around replacing the text mode TTYs with usermode
utilities.


While kmscon exists, the problem with it that I see is that it runs as root.
It's most likely so it can run /bin/login as root, and /bin/login is not setuid


I found that doing something like (Can't fit the command in 80 chars, sorry)
systemd-run --setenv XDG_SEAT=$XDG_SEAT --setenv XDG_VTNR=$XDG_VTNR -t /bin/login -p
can work in a way to run /bin/login within a non-privleged terminal emulator,
however authentication is needed to run that command.

(there also seems to be no way to turn off the "press ^] to disconnect" option)



First question:
Is there a supported way to allow a system user account to run one command
without a password prompt with systemd-run? Otherwise I guess I can just make a
setuid binary that calls the systemd-run command...




The second thing: Things like nmtui need a full logind session to be able to
run, and do polkit actions. However on seat0, it seems you need to decide on a
empty TTY to use, which while you can use TTY63, that doesn't seem to be a
'clean' idea.



One interesting workaround that DOES work is loading the vkms driver, adding
the virtual card to a seat called 'seat-vtty' and then starting the login
process on the virtual seat. That allows a full logind session to run and
things like nmtui actually work
modprobe vkms
loginctl attach seat-vtty /sys/devices/platform/vkms/drm/card1
systemd-run --setenv XDG_SEAT=seat-vtty -t /bin/login -p


The fake video card device being added forces logind to create the seat-vtty
seat. From that login prompt, I can log in and have polkit work, testing with
nmtui. It's a bit odd having to use a virtual hardware device to make a fake
seat, but it works to get around the TTY restriction for seat0...

Thanks
nerdopolis
2021-05-20 02:09:39 UTC
Permalink
Post by nerdopolis
Hi
I am trying to experiment around replacing the text mode TTYs with usermode
utilities.
While kmscon exists, the problem with it that I see is that it runs as root.
It's most likely so it can run /bin/login as root, and /bin/login is not setuid
I found that doing something like (Can't fit the command in 80 chars, sorry)
systemd-run --setenv XDG_SEAT=$XDG_SEAT --setenv XDG_VTNR=$XDG_VTNR -t /bin/login -p
can work in a way to run /bin/login within a non-privleged terminal emulator,
however authentication is needed to run that command.
(there also seems to be no way to turn off the "press ^] to disconnect" option)
Is there a supported way to allow a system user account to run one command
without a password prompt with systemd-run? Otherwise I guess I can just make a
setuid binary that calls the systemd-run command...
The second thing: Things like nmtui need a full logind session to be able to
run, and do polkit actions. However on seat0, it seems you need to decide on a
empty TTY to use, which while you can use TTY63, that doesn't seem to be a
'clean' idea.
One interesting workaround that DOES work is loading the vkms driver, adding
the virtual card to a seat called 'seat-vtty' and then starting the login
process on the virtual seat. That allows a full logind session to run and
things like nmtui actually work
modprobe vkms
loginctl attach seat-vtty /sys/devices/platform/vkms/drm/card1
systemd-run --setenv XDG_SEAT=seat-vtty -t /bin/login -p
The fake video card device being added forces logind to create the seat-vtty
seat. From that login prompt, I can log in and have polkit work, testing with
nmtui. It's a bit odd having to use a virtual hardware device to make a fake
seat, but it works to get around the TTY restriction for seat0...
Thanks
Hi

I think I came up with a solution for myself for Question 1. I will have one
service start /bin/login in a PTY with socat, to a socket file with the
permissions set for the service user, and then socat running under a terminal
emulator that runs as the service user will connect.

I actually already had some nice co-dependent .service files already, when I
first tried a socket based solution with tmux. But tmux was hard to nerf to be
"kiosk quality" to act similar to a login TTY. socat seems like it might be a
better fit, so I think I can call off having to worry about calling systemd-run
with a setuid binary, or making a complex polkit rule, or tweaking systemd-run
to disable the ^] disconnect ability...



Question 2, yeah it seems that manager_process_seat_device() is the only thing
that ends up calling seat_new() after some grepping, but I did find that if I
set master-of-seat as a property a device, and add it with udev, I don't have
to use the vkms driver, instead I can say use /dev/tty or something, which is
at least cleaner than using a virtual display device

Thanks
Lennart Poettering
2021-05-20 14:53:24 UTC
Permalink
Post by nerdopolis
Hi
I am trying to experiment around replacing the text mode TTYs with usermode
utilities.
I don't follow?
Post by nerdopolis
While kmscon exists, the problem with it that I see is that it runs as root.
It's most likely so it can run /bin/login as root, and /bin/login is not setuid
I found that doing something like (Can't fit the command in 80 chars, sorry)
systemd-run --setenv XDG_SEAT=$XDG_SEAT --setenv XDG_VTNR=$XDG_VTNR -t /bin/login -p
can work in a way to run /bin/login within a non-privleged terminal emulator,
however authentication is needed to run that command.
hmm? XDG_VTNR is for the Linux VT subsystem but though i don't
understand what you are trying to do i get the impression you don't
want to use VTs? or do you? not following...
Post by nerdopolis
Is there a supported way to allow a system user account to run one command
without a password prompt with systemd-run? Otherwise I guess I can just make a
setuid binary that calls the systemd-run command...
It's PolicyKit enabled, you can allow your user to run unpriv
commands, but it's a all-or-nothing thing.
Post by nerdopolis
The second thing: Things like nmtui need a full logind session to be able to
run, and do polkit actions. However on seat0, it seems you need to decide on a
empty TTY to use, which while you can use TTY63, that doesn't seem to be a
'clean' idea.
Can't parse this, sorry.

Lennart

--
Lennart Poettering, Berlin
nerdopolis
2021-05-22 01:29:09 UTC
Permalink
Post by Lennart Poettering
Post by nerdopolis
Hi
I am trying to experiment around replacing the text mode TTYs with usermode
utilities.
I don't follow?
I am sorry, I will try to be more clear. That first email, went through several
drafts, as at first it was longer and rambly, and I didn't want to bombard the
list with a giant wall of text.


(I actually found my solution was to use socat since sending that last email.)


I was seeking some more existing programs I could try to cobble together to
come up with a solution. The main things were:
1. /bin/login needs to be run as root for it to work
2. It's ill-advised to start a graphical terminal emulator as root
- I looked into the existing kmscon, but it's older, and ran as root

- I tried running tmux client/server with the server as root, the client as
non-root. It worked in theory, but tmux didn't seem fit to run ONLY a login
prompt

- I tried using systemd-run, but it had the quirks I described

BUT
- I found I could do the same client-server thing with socat, not tmux. tmux
has a basic way to forward a PTY to a socket, and then set the permissions on
it for a non-root system user, and then connect to it from a command running
under a terminal emulator running as that non-root user.


So my solution ended up being something like:
-------------------------------------------------------------------------------
vtty-***@tty1.service(u:root) vtty-***@tty1.service(u:vtty)
socat exec:/bin/login unix-listen:/run/socket cage (wayland)
/|\ vte (terminal emulator)
| socat file:`tty` unix-connect:/run/socket<-|
|________________________________________________________|
-------------------------------------------------------------------------------

That way there I was able to solve the first issue. (and actually the second
issue too, by running the backend on a fake seat-vtty seat)
Post by Lennart Poettering
Post by nerdopolis
While kmscon exists, the problem with it that I see is that it runs as root.
It's most likely so it can run /bin/login as root, and /bin/login is not setuid
I found that doing something like (Can't fit the command in 80 chars, sorry)
systemd-run --setenv XDG_SEAT=$XDG_SEAT --setenv XDG_VTNR=$XDG_VTNR -t /bin/login -p
can work in a way to run /bin/login within a non-privleged terminal emulator,
however authentication is needed to run that command.
hmm? XDG_VTNR is for the Linux VT subsystem but though i don't
understand what you are trying to do i get the impression you don't
want to use VTs? or do you? not following...
Sorry, I got the terminology mixed up again. I am still using TTYs to run the
instances of `cage`. It's the kernel mode VT emulators I am replacing with the
user mode terminal emulators (running under a fullscreen Wayland compositor)
Post by Lennart Poettering
Post by nerdopolis
Is there a supported way to allow a system user account to run one command
without a password prompt with systemd-run? Otherwise I guess I can just make a
setuid binary that calls the systemd-run command...
It's PolicyKit enabled, you can allow your user to run unpriv
commands, but it's a all-or-nothing thing.
OK, that's kind of what I thought. Thanks for confirming. (If I hadn't found
the other solution, I would have just made the setuid binary for kicking off
systemd-run)
Post by Lennart Poettering
Post by nerdopolis
The second thing: Things like nmtui need a full logind session to be able to
run, and do polkit actions. However on seat0, it seems you need to decide on a
empty TTY to use, which while you can use TTY63, that doesn't seem to be a
'clean' idea.
Can't parse this, sorry.
I am sorry I was not clear, I'll try to use nmtui as an example to describe
what I am seeing.

nmtui is an example of a utility that needs polkit (or root) to work. It comes
with NetworkManager. Start nmtui from a normal terminal emulator, or a classic
tty, and you likely will be able to edit connections with it.

Now if you do
systemd-run -t /bin/login -p
and then login, and run nmtui, that instance will then say "not authorized"

I forgot what inspired me to experiment with setting XDG_SEAT but if you
systemd-run -t --setenv=XDG_SEAT=seat0 /bin/login -p
and then log in, and nmtui still doesn't work.

Check the journal, you will get an error "failed to create session: VT number
out of range" where the VT number that gets logged is 0. I guess it fails
because on seat0 VT numbers can't be 0.

- one ugly hack though was setting XDG_VTNR to like 63 or something



What DOES work is if you create a second seat somehow called seat-vtty then:
systemd-run -t --setenv=XDG_SEAT=seat-vtty /bin/login -p
and login, and THAT WORKS. because the non-seat0 seat accepts a VTNR of 0
From within that session, you can edit connections with nmtui again.


I hope this clarifies some things, I was able to solve with with using the
socat proxy, so I think I might be all set. Although this might be a good case
to where XDG_VTNR=0 might actually be _valid_ for seat0... Not sure if I should
open a case for that, (or not, if it's going to break compatibility)

Thanks
Post by Lennart Poettering
Lennart
--
Lennart Poettering, Berlin
Pekka Paalanen
2021-05-22 10:50:09 UTC
Permalink
On Fri, 21 May 2021 21:29:09 -0400
Post by nerdopolis
Sorry, I got the terminology mixed up again. I am still using TTYs to run the
instances of `cage`. It's the kernel mode VT emulators I am replacing with the
user mode terminal emulators (running under a fullscreen Wayland compositor)
Hi,

I'm trying to clarify things for everyone here, since I think I can
guess what you want to achieve, but you have a hard time explaining
your original goal. I hope you don't mind.


Starting from the outermost "layer" and going inwards:

1.a Have a system service, that takes over VT 1, changes user to
'vtty', and runs 'cage' which is a Wayland compositor, mostly
unprivileged.

OR

1.b Have a system service, that takes over a seat directly, as the
kernel has the VT system disabled (or the seat is not seat0).
Changes user to 'vtty' and runs 'cage' mostly unprivileged.


2. Inside cage, you run a Wayland terminal emulator as user 'vtty',
so mostly unprivileged. The terminal emulator creates a PTY.

3. Inside that terminal emulator, that is, connecting to that PTY,
you want to be able log in with any user. Therefore the program
running on the PTY should present a login prompt and succeed
in logging a user in and setting up his session, and switching
to a shell running as that user.

All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.

Am I guessing right?

Then the question is, how to organize all this so that it works,
and what program(s) should be used in step 3, and how?


My own proposal for this would be to run everything as systemd
system services:

1. Cage runs as a system service, as user 'vtty'. Cage will require
systemd integration so that it can tell systemd when it is ready
to accept Wayland clients.

2. The Wayland terminal runs as another systemd system service,
depending on the cage service, as user 'vtty'.

3. The login program runs as a third systemd system service,
depending on the terminal service, as user 'root' because it
needs to be able log in a user and set up a session for them.

That would solve the problem of how to get the necessary privileges
to log in a user, but all the other details I'm not sure.

So the main idea here is to not run /bin/login *under* the terminal
emulator or cage, but as a system service which just connects to the
right PTY. I guess it would be like running /bin/login for a serial
terminal, it just connects to ttyS1 or whatever instead of tty1.

Would that work?


Thanks,
pq
nerdopolis
2021-05-22 13:04:42 UTC
Permalink
Post by Pekka Paalanen
On Fri, 21 May 2021 21:29:09 -0400
Post by nerdopolis
Sorry, I got the terminology mixed up again. I am still using TTYs to run the
instances of `cage`. It's the kernel mode VT emulators I am replacing with the
user mode terminal emulators (running under a fullscreen Wayland compositor)
Hi,
I'm trying to clarify things for everyone here, since I think I can
guess what you want to achieve, but you have a hard time explaining
your original goal. I hope you don't mind.
That's fine. Thanks!
Post by Pekka Paalanen
1.a Have a system service, that takes over VT 1, changes user to
'vtty', and runs 'cage' which is a Wayland compositor, mostly
unprivileged.
OR
1.b Have a system service, that takes over a seat directly, as the
kernel has the VT system disabled (or the seat is not seat0).
Changes user to 'vtty' and runs 'cage' mostly unprivileged.
2. Inside cage, you run a Wayland terminal emulator as user 'vtty',
so mostly unprivileged. The terminal emulator creates a PTY.
3. Inside that terminal emulator, that is, connecting to that PTY,
you want to be able log in with any user. Therefore the program
running on the PTY should present a login prompt and succeed
in logging a user in and setting up his session, and switching
to a shell running as that user.
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
Not to mention, getting Shift+PgUp back, (and now on multiseat systems,
keyboard input from non-seat0 seats will no longer bleed into seat0 when VT 1-6
are active) :)
Post by Pekka Paalanen
Am I guessing right?
You are guessing correct. Thanks!
Post by Pekka Paalanen
Then the question is, how to organize all this so that it works,
and what program(s) should be used in step 3, and how?
My own proposal for this would be to run everything as systemd
1. Cage runs as a system service, as user 'vtty'. Cage will require
systemd integration so that it can tell systemd when it is ready
to accept Wayland clients.
2. The Wayland terminal runs as another systemd system service,
depending on the cage service, as user 'vtty'.
That's close to what I was trying, but cage is pretty cool in this regard, you
can start
cage -- vte
and cage starts VTE as its only client, so the complexity of starting the
wayland client externally, don't have to worry about that.
Post by Pekka Paalanen
3. The login program runs as a third systemd system service,
depending on the terminal service, as user 'root' because it
needs to be able log in a user and set up a session for them.
That would solve the problem of how to get the necessary privileges
to log in a user, but all the other details I'm not sure.
That's what I was aiming to do, wasn't sure how to connect to the service until
I found I can do that with socat a few days after I sent that first email to
the list, but I still feel I should still clarify here.

and if you're really curious, I have the .service files I made public
https://github.com/n3rdopolis/fakekmscon/tree/master/usr/lib/systemd/system
Post by Pekka Paalanen
So the main idea here is to not run /bin/login *under* the terminal
emulator or cage, but as a system service which just connects to the
right PTY. I guess it would be like running /bin/login for a serial
terminal, it just connects to ttyS1 or whatever instead of tty1.
Would that work?
Thanks,
pq
Pekka Paalanen
2021-05-22 19:14:27 UTC
Permalink
On Sat, 22 May 2021 09:04:42 -0400
Post by nerdopolis
Post by Pekka Paalanen
On Fri, 21 May 2021 21:29:09 -0400
Post by nerdopolis
Sorry, I got the terminology mixed up again. I am still using TTYs to run the
instances of `cage`. It's the kernel mode VT emulators I am replacing with the
user mode terminal emulators (running under a fullscreen Wayland compositor)
Hi,
I'm trying to clarify things for everyone here, since I think I can
guess what you want to achieve, but you have a hard time explaining
your original goal. I hope you don't mind.
That's fine. Thanks!
Post by Pekka Paalanen
1.a Have a system service, that takes over VT 1, changes user to
'vtty', and runs 'cage' which is a Wayland compositor, mostly
unprivileged.
OR
1.b Have a system service, that takes over a seat directly, as the
kernel has the VT system disabled (or the seat is not seat0).
Changes user to 'vtty' and runs 'cage' mostly unprivileged.
2. Inside cage, you run a Wayland terminal emulator as user 'vtty',
so mostly unprivileged. The terminal emulator creates a PTY.
3. Inside that terminal emulator, that is, connecting to that PTY,
you want to be able log in with any user. Therefore the program
running on the PTY should present a login prompt and succeed
in logging a user in and setting up his session, and switching
to a shell running as that user.
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
Not to mention, getting Shift+PgUp back, (and now on multiseat systems,
keyboard input from non-seat0 seats will no longer bleed into seat0 when VT 1-6
are active) :)
Post by Pekka Paalanen
Am I guessing right?
You are guessing correct. Thanks!
Post by Pekka Paalanen
Then the question is, how to organize all this so that it works,
and what program(s) should be used in step 3, and how?
My own proposal for this would be to run everything as systemd
1. Cage runs as a system service, as user 'vtty'. Cage will require
systemd integration so that it can tell systemd when it is ready
to accept Wayland clients.
2. The Wayland terminal runs as another systemd system service,
depending on the cage service, as user 'vtty'.
That's close to what I was trying, but cage is pretty cool in this regard, you
can start
cage -- vte
and cage starts VTE as its only client, so the complexity of starting the
wayland client externally, don't have to worry about that.
But if cage starts the terminal, then systemd does not know when
the terminal is ready to accept a login program, or is there a way
to watch PTYs?

Ideally the terminal too would integrate with systemd start-up
notification IPC. Perhaps let systemd control which PTY to use, so
the login program/service knows to connect to the right one.

There's also auto-respawn, shutdown, cgroups, and more that systemd
can do.
Post by nerdopolis
Post by Pekka Paalanen
3. The login program runs as a third systemd system service,
depending on the terminal service, as user 'root' because it
needs to be able log in a user and set up a session for them.
That would solve the problem of how to get the necessary privileges
to log in a user, but all the other details I'm not sure.
That's what I was aiming to do, wasn't sure how to connect to the service until
I found I can do that with socat a few days after I sent that first email to
the list, but I still feel I should still clarify here.
The socat thing for "connection" sounds quite wild to me. Instead,
I would expect to start a login program with the PTY as its std
in/out/err, just like it works with normal VT TTY logins.

But then you do need to know which PTY it is. I think it would be
best to configure that as the parameter for templatated systemd
units: the terminal unit gets the PTY to listen on, and the login
unit gets the PTY to use as its controlling terminal and std
in/out/err. And the dependency between the two.

One problem here is how are you going to lock a terminal when
switching to another with a different user logged in. So maybe this
whole model is flawed, and you need authentication to work through
the Wayland compositor which is in charge of which terminal is
active.
Post by nerdopolis
and if you're really curious, I have the .service files I made public
https://github.com/n3rdopolis/fakekmscon/tree/master/usr/lib/systemd/system
I looked at the service files, and they don't seem to have much. I
looked at your libexec scripts, and they are much more complicated
than I expected, doing a lot more than I'm willing to try to
understand at this hour. :-)


Thanks,
pq
Post by nerdopolis
Post by Pekka Paalanen
So the main idea here is to not run /bin/login *under* the terminal
emulator or cage, but as a system service which just connects to the
right PTY. I guess it would be like running /bin/login for a serial
terminal, it just connects to ttyS1 or whatever instead of tty1.
nerdopolis
2021-05-22 20:18:35 UTC
Permalink
Post by Pekka Paalanen
On Sat, 22 May 2021 09:04:42 -0400
Post by nerdopolis
Post by Pekka Paalanen
On Fri, 21 May 2021 21:29:09 -0400
Post by nerdopolis
Sorry, I got the terminology mixed up again. I am still using TTYs to run the
instances of `cage`. It's the kernel mode VT emulators I am replacing with the
user mode terminal emulators (running under a fullscreen Wayland compositor)
Hi,
I'm trying to clarify things for everyone here, since I think I can
guess what you want to achieve, but you have a hard time explaining
your original goal. I hope you don't mind.
That's fine. Thanks!
Post by Pekka Paalanen
1.a Have a system service, that takes over VT 1, changes user to
'vtty', and runs 'cage' which is a Wayland compositor, mostly
unprivileged.
OR
1.b Have a system service, that takes over a seat directly, as the
kernel has the VT system disabled (or the seat is not seat0).
Changes user to 'vtty' and runs 'cage' mostly unprivileged.
2. Inside cage, you run a Wayland terminal emulator as user 'vtty',
so mostly unprivileged. The terminal emulator creates a PTY.
3. Inside that terminal emulator, that is, connecting to that PTY,
you want to be able log in with any user. Therefore the program
running on the PTY should present a login prompt and succeed
in logging a user in and setting up his session, and switching
to a shell running as that user.
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
Not to mention, getting Shift+PgUp back, (and now on multiseat systems,
keyboard input from non-seat0 seats will no longer bleed into seat0 when VT 1-6
are active) :)
Post by Pekka Paalanen
Am I guessing right?
You are guessing correct. Thanks!
Post by Pekka Paalanen
Then the question is, how to organize all this so that it works,
and what program(s) should be used in step 3, and how?
My own proposal for this would be to run everything as systemd
1. Cage runs as a system service, as user 'vtty'. Cage will require
systemd integration so that it can tell systemd when it is ready
to accept Wayland clients.
2. The Wayland terminal runs as another systemd system service,
depending on the cage service, as user 'vtty'.
That's close to what I was trying, but cage is pretty cool in this regard, you
can start
cage -- vte
and cage starts VTE as its only client, so the complexity of starting the
wayland client externally, don't have to worry about that.
But if cage starts the terminal, then systemd does not know when
the terminal is ready to accept a login program, or is there a way
to watch PTYs?
Ideally the terminal too would integrate with systemd start-up
notification IPC. Perhaps let systemd control which PTY to use, so
the login program/service knows to connect to the right one.
There's also auto-respawn, shutdown, cgroups, and more that systemd
can do.
Post by nerdopolis
Post by Pekka Paalanen
3. The login program runs as a third systemd system service,
depending on the terminal service, as user 'root' because it
needs to be able log in a user and set up a session for them.
That would solve the problem of how to get the necessary privileges
to log in a user, but all the other details I'm not sure.
That's what I was aiming to do, wasn't sure how to connect to the service until
I found I can do that with socat a few days after I sent that first email to
the list, but I still feel I should still clarify here.
The socat thing for "connection" sounds quite wild to me. Instead,
I would expect to start a login program with the PTY as its std
in/out/err, just like it works with normal VT TTY logins.
Sounds like you would need to make VTE start up with nothing running, and have
VTE report the PTY that it got?
Post by Pekka Paalanen
But then you do need to know which PTY it is. I think it would be
best to configure that as the parameter for templatated systemd
units: the terminal unit gets the PTY to listen on, and the login
unit gets the PTY to use as its controlling terminal and std
in/out/err. And the dependency between the two.
Seems like I would need to elevate to have an unprivileged parameterized
service start a dependant with a _different_ parameter?

With this, it seems you would have ***@.service
where ***@.service replaces ***@.service
(***@.service runs as the system user)

If I have it dependant on ***@.service, it automatically starts it with the
same parameter. (from there I just use a socket with the parameter name)

Not sure how ***@tty1.service would start backend@/dev/pts/0.service ?
And if you start backend first, it's going to need to know the pty still...
Post by Pekka Paalanen
One problem here is how are you going to lock a terminal when
switching to another with a different user logged in. So maybe this
whole model is flawed, and you need authentication to work through
the Wayland compositor which is in charge of which terminal is
active.
Wait, do normal TTYs do locking? CTRL+ALT+FX or chvt, and I've never seen a
lock on them...
Post by Pekka Paalanen
Post by nerdopolis
and if you're really curious, I have the .service files I made public
https://github.com/n3rdopolis/fakekmscon/tree/master/usr/lib/systemd/system
I looked at the service files, and they don't seem to have much. I
looked at your libexec scripts, and they are much more complicated
than I expected, doing a lot more than I'm willing to try to
understand at this hour. :-)
Sorry, one hint, Ignore the SIG_WINCH stuff and ptycommandproxy. That's a
separate FIFO for allowing the unprivileged account for using stty to set
the size of the server pty to be the same as the frontend pty so text mode
applications like nmtui and text editors work correctly...

Those do make the script more complex
Post by Pekka Paalanen
Thanks,
pq
Post by nerdopolis
Post by Pekka Paalanen
So the main idea here is to not run /bin/login *under* the terminal
emulator or cage, but as a system service which just connects to the
right PTY. I guess it would be like running /bin/login for a serial
terminal, it just connects to ttyS1 or whatever instead of tty1.
Pekka Paalanen
2021-05-24 07:56:44 UTC
Permalink
On Sat, 22 May 2021 16:18:35 -0400
Post by nerdopolis
Post by Pekka Paalanen
On Sat, 22 May 2021 09:04:42 -0400
Post by nerdopolis
Post by Pekka Paalanen
On Fri, 21 May 2021 21:29:09 -0400
Post by nerdopolis
Sorry, I got the terminology mixed up again. I am still using TTYs to run the
instances of `cage`. It's the kernel mode VT emulators I am replacing with the
user mode terminal emulators (running under a fullscreen Wayland compositor)
Hi,
I'm trying to clarify things for everyone here, since I think I can
guess what you want to achieve, but you have a hard time explaining
your original goal. I hope you don't mind.
That's fine. Thanks!
Post by Pekka Paalanen
1.a Have a system service, that takes over VT 1, changes user to
'vtty', and runs 'cage' which is a Wayland compositor, mostly
unprivileged.
OR
1.b Have a system service, that takes over a seat directly, as the
kernel has the VT system disabled (or the seat is not seat0).
Changes user to 'vtty' and runs 'cage' mostly unprivileged.
2. Inside cage, you run a Wayland terminal emulator as user 'vtty',
so mostly unprivileged. The terminal emulator creates a PTY.
3. Inside that terminal emulator, that is, connecting to that PTY,
you want to be able log in with any user. Therefore the program
running on the PTY should present a login prompt and succeed
in logging a user in and setting up his session, and switching
to a shell running as that user.
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
Not to mention, getting Shift+PgUp back, (and now on multiseat systems,
keyboard input from non-seat0 seats will no longer bleed into seat0 when VT 1-6
are active) :)
Post by Pekka Paalanen
Am I guessing right?
You are guessing correct. Thanks!
Post by Pekka Paalanen
Then the question is, how to organize all this so that it works,
and what program(s) should be used in step 3, and how?
My own proposal for this would be to run everything as systemd
1. Cage runs as a system service, as user 'vtty'. Cage will require
systemd integration so that it can tell systemd when it is ready
to accept Wayland clients.
2. The Wayland terminal runs as another systemd system service,
depending on the cage service, as user 'vtty'.
That's close to what I was trying, but cage is pretty cool in this regard, you
can start
cage -- vte
and cage starts VTE as its only client, so the complexity of starting the
wayland client externally, don't have to worry about that.
But if cage starts the terminal, then systemd does not know when
the terminal is ready to accept a login program, or is there a way
to watch PTYs?
Ideally the terminal too would integrate with systemd start-up
notification IPC. Perhaps let systemd control which PTY to use, so
the login program/service knows to connect to the right one.
There's also auto-respawn, shutdown, cgroups, and more that systemd
can do.
Post by nerdopolis
Post by Pekka Paalanen
3. The login program runs as a third systemd system service,
depending on the terminal service, as user 'root' because it
needs to be able log in a user and set up a session for them.
That would solve the problem of how to get the necessary privileges
to log in a user, but all the other details I'm not sure.
That's what I was aiming to do, wasn't sure how to connect to the service until
I found I can do that with socat a few days after I sent that first email to
the list, but I still feel I should still clarify here.
The socat thing for "connection" sounds quite wild to me. Instead,
I would expect to start a login program with the PTY as its std
in/out/err, just like it works with normal VT TTY logins.
Sounds like you would need to make VTE start up with nothing running, and have
VTE report the PTY that it got?
Yes, almost. Hack VTE to use only the PTY you set via systemd. Let VTE
keep on running even if nothing has the PTY open. Systemd will take
care of shutting down the terminal when appropriate (another reason why
let systemd launch the terminal and not cage).

And yes, the whole point is that you *don't* start a login program
from inside cage or the terminal. Cage and terminal are unprivileged
processes, and login requires privileges so you have the problem of
needing to elevate privileges as they have been dropped already.

Instead, letting systemd start the login program directly avoids the
need to raise privileges, because systemd already runs with full
privileges and simply not drop them when starting the login process.
Post by nerdopolis
Post by Pekka Paalanen
But then you do need to know which PTY it is. I think it would be
best to configure that as the parameter for templatated systemd
units: the terminal unit gets the PTY to listen on, and the login
unit gets the PTY to use as its controlling terminal and std
in/out/err. And the dependency between the two.
Seems like I would need to elevate to have an unprivileged parameterized
service start a dependant with a _different_ parameter?
Elevate? No, nothing should need to elevate.

System service *units* are not unprivileged. System service *processes*
might be. I don't think there is any problem making dependencies
between system services, regardless of what they run and how. The thing
you cannot do is to make system services depend on user services, but
that's not a problem here because you only have system services for
this.
Post by nerdopolis
same parameter. (from there I just use a socket with the parameter name)
Yes, I believe you can use the template parameters with Requires/Before
directives, so the terminal service gets auto-launched when you start
the login service for a PTY.
Post by nerdopolis
And if you start backend first, it's going to need to know the pty still...
Not tty1, but my-login@<PTY>.service, depending on
my-terminal@%i.service which depends on cage.service.

tty1 would be for cage only and can be hardcoded in the unit assuming
VTs even exist.
Post by nerdopolis
Post by Pekka Paalanen
One problem here is how are you going to lock a terminal when
switching to another with a different user logged in. So maybe this
whole model is flawed, and you need authentication to work through
the Wayland compositor which is in charge of which terminal is
active.
Wait, do normal TTYs do locking? CTRL+ALT+FX or chvt, and I've never seen a
lock on them...
They don't do locking, that's a big problem I think would be good to
solve. :-)
Post by nerdopolis
Post by Pekka Paalanen
Post by nerdopolis
and if you're really curious, I have the .service files I made public
https://github.com/n3rdopolis/fakekmscon/tree/master/usr/lib/systemd/system
I looked at the service files, and they don't seem to have much. I
looked at your libexec scripts, and they are much more complicated
than I expected, doing a lot more than I'm willing to try to
understand at this hour. :-)
Sorry, one hint, Ignore the SIG_WINCH stuff and ptycommandproxy. That's a
separate FIFO for allowing the unprivileged account for using stty to set
the size of the server pty to be the same as the frontend pty so text mode
applications like nmtui and text editors work correctly...
Those do make the script more complex
I do think using socat here is a problem, not a solution. Look at how
normal gettys and logins connect to the VT TTYs and serial terminals?

AFAIU, they do not so much "connect" but start with their standard
input/output/error streams already connected to the right *TY device
which also becomes their "controlling terminal". That way, they are
directly using the *TY device and can issue tty ioctls (stty etc.)
directly.


Disclaimer: this is all based on my theoretical understanding, not
experience, so I may have got something wrong. Hopefully others on this
mailing list point out any mistakes.


Thanks,
pq
Lennart Poettering
2021-05-27 15:33:35 UTC
Permalink
Post by Pekka Paalanen
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
When you say /bin/login do actually intend to say "getty"? what is
/bin/login good for here? it's a stub that expects you already give it
a user and it then only asks for a pw. It's the second part of a getty
pretty much.

We have multiple services that you can instantiate on ttys, for
example ***@.service (for true VTs), serial-***@.service (for
serial ports), container-getty.service (for /dev/console),
container-***@.service (for gettys on pseudo TTYs, pretty much).

It appears to me that the right approach for your case is to do what
container-***@.service effectively does and instantiate an
appropriate instance of a template service modelled after it for the
"other" side of the pty your terminal app allocates.

Instantiating <yourapp>-***@.service requires privs, but you can use
polkit to grant that to your terminal app's user. THe polkit auth
request carries the unit name as additional metadata, hence that
should be pretty easily done with some minimal polkit JS.

Lennart

--
Lennart Poettering, Berlin
nerdopolis
2021-05-28 02:25:41 UTC
Permalink
Post by Lennart Poettering
Post by Pekka Paalanen
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
When you say /bin/login do actually intend to say "getty"? what is
/bin/login good for here? it's a stub that expects you already give it
a user and it then only asks for a pw. It's the second part of a getty
pretty much.
We have multiple services that you can instantiate on ttys, for
serial ports), container-getty.service (for /dev/console),
It appears to me that the right approach for your case is to do what
appropriate instance of a template service modelled after it for the
"other" side of the pty your terminal app allocates.
polkit to grant that to your terminal app's user. THe polkit auth
request carries the unit name as additional metadata, hence that
should be pretty easily done with some minimal polkit JS.
Lennart
--
Lennart Poettering, Berlin
I guess I meant to say getty, but getty ends up calling /bin/login anyway after
resetting the terminal and reading /etc/issue anyway. Or at least I thought.

Interesting I found some simple enough looking samples for granting users the
ability to start one service. Dang, it might not work with Debian's
fraken-polkit-0.105 they still have.

I am able to tweak up a test copy of container-***@.service,
setting TERM to xterm-256color and doing the XDG_SEAT=seat-vtty workaround so
the logged in session has PAM too, and nmtui doesn't do this
Loading Image...
so that works.

Something like that is what I was originally looking for, so thanks!
but I will admit, one thing I've come to like about the socat client/server
hing is that if say cage or vte takes a segfault during say an apt-get install,
the running command doesn't die...
Lennart Poettering
2021-05-28 05:27:30 UTC
Permalink
Post by nerdopolis
I guess I meant to say getty, but getty ends up calling /bin/login anyway after
resetting the terminal and reading /etc/issue anyway. Or at least I thought.
Interesting I found some simple enough looking samples for granting users the
ability to start one service. Dang, it might not work with Debian's
fraken-polkit-0.105 they still have.
setting TERM to xterm-256color and doing the XDG_SEAT=seat-vtty workaround so
the logged in session has PAM too, and nmtui doesn't do this
https://i.imgur.com/dt7xAMz.png
so that works.
Something like that is what I was originally looking for, so thanks!
but I will admit, one thing I've come to like about the socat client/server
hing is that if say cage or vte takes a segfault during say an apt-get install,
the running command doesn't die...
The service that implements your terminal emulator could upload the
pty master fds to systemd via the fdstore logic. That way the master
will stay open across restart of that service or when it fails.

Lennart

--
Lennart Poettering, Berlin
Pekka Paalanen
2021-05-28 07:13:17 UTC
Permalink
On Thu, 27 May 2021 17:33:35 +0200
Post by Lennart Poettering
Post by Pekka Paalanen
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
When you say /bin/login do actually intend to say "getty"? what is
/bin/login good for here? it's a stub that expects you already give it
a user and it then only asks for a pw. It's the second part of a getty
pretty much.
Yes, sorry. I'm not clear what any of them actually do. Hence, please
replace everything I've called "the login program" or similar with
yours above.


Thanks,
pq
Post by Lennart Poettering
We have multiple services that you can instantiate on ttys, for
serial ports), container-getty.service (for /dev/console),
It appears to me that the right approach for your case is to do what
appropriate instance of a template service modelled after it for the
"other" side of the pty your terminal app allocates.
polkit to grant that to your terminal app's user. THe polkit auth
request carries the unit name as additional metadata, hence that
should be pretty easily done with some minimal polkit JS.
Lennart
--
Lennart Poettering, Berlin
nerdopolis
2021-05-28 12:08:58 UTC
Permalink
Post by Pekka Paalanen
On Thu, 27 May 2021 17:33:35 +0200
Post by Lennart Poettering
Post by Pekka Paalanen
All in all, this stack would replace the usual stack where
/bin/login runs directly on the TTY of a VT, allowing to use a more
featureful terminal, custom display modes, multi-output support,
maybe multiple parallel sessions for different users a la fast user
switching, and more.
When you say /bin/login do actually intend to say "getty"? what is
/bin/login good for here? it's a stub that expects you already give it
a user and it then only asks for a pw. It's the second part of a getty
pretty much.
Yes, sorry. I'm not clear what any of them actually do. Hence, please
replace everything I've called "the login program" or similar with
yours above.
Odd, maybe the /bin/login that ships with Debian does something not standard
then, because, that one does prompt for a username...
Loading Image...
Post by Pekka Paalanen
Thanks,
pq
Post by Lennart Poettering
We have multiple services that you can instantiate on ttys, for
serial ports), container-getty.service (for /dev/console),
It appears to me that the right approach for your case is to do what
appropriate instance of a template service modelled after it for the
"other" side of the pty your terminal app allocates.
polkit to grant that to your terminal app's user. THe polkit auth
request carries the unit name as additional metadata, hence that
should be pretty easily done with some minimal polkit JS.
Lennart
--
Lennart Poettering, Berlin
Lennart Poettering
2021-05-27 15:23:44 UTC
Permalink
Post by nerdopolis
Post by Lennart Poettering
Post by nerdopolis
Hi
I am trying to experiment around replacing the text mode TTYs with usermode
utilities.
I don't follow?
I am sorry, I will try to be more clear. That first email, went through several
drafts, as at first it was longer and rambly, and I didn't want to bombard the
list with a giant wall of text.
(I actually found my solution was to use socat since sending that last email.)
I was seeking some more existing programs I could try to cobble together to
I still donÄt get what the "end goal" is. You start with the tools you
want to reach your end goal, but never specify what precisely that end
goal is.

Do you intend to replace the Linux VT with a userspace implementation
of the same concept?

Or do you want to run a full-screen graphical terminal app on one
Linux graphical VT that behaves like a text VT but renders stuff
graphically?

Lennart

--
Lennart Poettering, Berlin
nerdopolis
2021-05-27 22:06:01 UTC
Permalink
Post by Lennart Poettering
Post by nerdopolis
Post by Lennart Poettering
Post by nerdopolis
Hi
I am trying to experiment around replacing the text mode TTYs with usermode
utilities.
I don't follow?
I am sorry, I will try to be more clear. That first email, went through several
drafts, as at first it was longer and rambly, and I didn't want to bombard the
list with a giant wall of text.
(I actually found my solution was to use socat since sending that last email.)
I was seeking some more existing programs I could try to cobble together to
I still donÄt get what the "end goal" is. You start with the tools you
want to reach your end goal, but never specify what precisely that end
goal is.
Do you intend to replace the Linux VT with a userspace implementation
of the same concept?
Or do you want to run a full-screen graphical terminal app on one
Linux graphical VT that behaves like a text VT but renders stuff
graphically?
Lennart
--
Lennart Poettering, Berlin
Sorry I wasn't clear, it's a full screen graphical terminal that behaves
similar to a text VT.

I replace ***@.service with the front end service that starts the instance
of the display server, and the terminal emulator.

I imagine replacing the whole VT would entail more than a full screen graphical
terminal emulating it...
Loading...