2024-06-15 Old tech: UUCP

@lkh@social.sdfeu.org, @kyonshi@dice.camp and I have been trying to connect our servers using old tech for quite a while.

UUCP

The latest effort has been in connecting our servers using *Unix to Unix copy* (UUCP). The benefit is that once you have that, you can also have *remote command execution over UUCP* using `uux` and it is as terrifying as it sounds.

Let's see whether I can reconstruct my setup.

I use Debian.

lkh has a "travelling laptop" that is mostly offline, but sometimes it's online. That's when he wants to exchange stuff with us. The laptop is called Dwalin.

My server is Campaign Wiki.

The documentation for peering between news servers via UUCP is available via `man 8 send-uucp`.

/var/spool/uucp/.ssh/authorized_keys

This allows Dwalin to connect via ssh.

lkh sent me this.

# dwalins public key, ssh executes the remote
# uucico and hands over my login:
restrict,command="/usr/sbin/uucico -u Udwalin -l" ssh-rsa another-long-string-of-stuff uucp@dwalin

/etc/uucp/passwd

This is where Dwalin's password is stored. This is important because there's no actual Dwalin user on my system.

lkh sent me this.

# dwalins login on campaignwiki
Udwalin	some-long-string-of-stuff

/etc/sys

I kept the defaults and added Dwalin.

# dwalins system entry, no Port or
# credentials are given, since dwalin
# is expected to always call in.
system dwalin
commands rmail rnews rsmtp
called-login Udwalin
local-send /
local-receive /var/spool/uucppublic
remote-send /
remote-receive /var/spool/uucppublic
time any
forward ANY
protocol i

/etc/port

I don't have a modem so I commented out all the stuff I don't need and just left this:

port TCP
type tcp

/etc/uucp/config

This is where I set my own node name. Everything else is left to defaults.

nodename campaignwiki

Testing it

In our case, lkh's Dwalin is connected to kyonshi's Erebor system and here's me sending a file to Erebor via Dwalin (since I'm not connected to Erebor directly):

uucp some-local-file 'dwalin!ereborbbs.duckdns.org!~/'

News

Yes, we want to exchange news. That means we need to install INN.

Look at the requisites:

perldoc /usr/lib/news/bin/send-uucp.pl

/etc/news/send-uucp.cf

This define the sites to send news to, how to compress them and how big the batches should be.

Add the following:

dwalin      gzip        1048576

/etc/news/newsfeeds

Determine the newsgroups to send to Dwalin:

# newsfeed entry for dwalin
dwalin\
    :casa.*,campaignwiki.*,erebor.*\
    :Tf,Wnb,B4096/1024:

/var/lib/news/active

Add the new newsgroups. We don't do control messages.

Use `ctlinnd` to control the INN daemon.

ctlinnd newgroup erebor.talk y
ctlinnd newgroup erebor.test y

/var/lib/news/newsgroups

Give the new newsgroups a tag line.

Add the following:

erebor.talk             General talk for EreborBBS
erebor.test             Testing connectivity with EreborBBS

/etc/news/readers.conf

Make sure the users connecting via NNTP can read the new groups, too. This is not necessary if you read news via the local spool, I think.

Add `erebor.*` to the "readonly" section.

auth "foreignokay" {
    auth: "ckpasswd -f /var/lib/news/newsusers"
    default: "<unauthenticated>"
}

access "authenticatedpeople" {
    users: "*"
    newsgroups: "*,!junk,!control,!control.*"
}

access "readonly" {
    users: "<unauthenticated>"
    read: "local.*,campaignwiki.*,casa.*,cosmic.*,erebor.*,rec.*,de.*,alt.*"
}

Testing it

Check `uulog`. Here's where a news article is put into the queue and a few minutes later, Dwalin calls and the enqueued article is sent:

uux dwalin news (2024-06-15 10:22:01.34 3832004) Queuing rnews (D.000R)
uucico - - (2024-06-15 11:05:07.00 3842142) Incoming call (login Udwalin port stdin)
uucico dwalin - (2024-06-15 11:05:07.05 3842142) Handshake successful (protocol 'i' sending packet/window 1024/16 receiving 1024/16)
uucico dwalin news (2024-06-15 11:05:07.05 3842142) Sending rnews (D.000R) (1548 bytes)
uucico dwalin - (2024-06-15 11:05:07.10 3842142) Protocol 'i' packets: sent 8, resent 0, received 6
uucico dwalin - (2024-06-15 11:05:07.10 3842142) Call complete (0 seconds 1548 bytes 0 bps)

E-Mail

Oh yes, we do.

Debian comes with Exim. Exim uses Perl's "taint" mechanism wherein user-supplied values cannot be used for commands. They must be untainted by a lookup. For example, a user supplied sender name like "alex" is tainted, but if you look it up in `/etc/passwd` it becomes untainted. Perl keeps track of this for you, if you want to. Once you run into the error, however, you need to figure out where you could be looking up the values you have. Is the local part a user on the system, is the domain a local domain? I spent way too much time on this.

/etc/exim4/update-exim4.conf.conf

This is the file generated by `update-exim4.conf`.

The result of me answering the questions:

dc_eximconfig_configtype='local'
dc_other_hostnames='alexschroeder.ch;campaignwiki.org;communitywiki.org;transjovian.org;campaignwiki'
dc_local_interfaces='127.0.0.1 ; ::1'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname=''
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'

That is to say: it only handles local mail and mail via UUCP and NNCP, not SMTP.

/etc/exim4/conf.d/router/110_exim4-config_uucp

A new router for UUCP mail that has to come before `200_exim4-config_primary`. If it comes after the primary, then it won't work because the primary router ends with `no_more` and as the comment at the end of the file says:

The `no_more` above means that all later routers are for domains in the local_domains list

This router only accepts mail destined for domains listed in the new file `/etc/exim4/uucp` and passes it to the `rmail` transport (see below).

### uucp      
### based on /usr/share/doc/exim4-base/README.Debian.gz

uucp_router:
    debug_print = "R: uucp_router for $local_part@$domain"
    driver=accept
    require_files = +/usr/bin/uux
    domains = wildlsearch;/etc/exim4/uucp
    transport = rmail

/etc/exim4/uucp

This is a file that translates the domain names I use for recipients to UUCP names.

dwalin	dwalin
dwalin.uucp	dwalin
erebor	dwalin!erebor

This means that a mail for `lkh@dwalin` gets recognised as such (because of the first column) and it will be sent to the UUCP system `dwalin` (because of the second column).

The UUCP system `dwalin` is correct because `/etc/uucp/sys` has a section for `system dwalin` (see above).

/etc/exim/conf.d/transport/40_exim4-config_uucp

The route above says that the transport to use is `rmail`.

Define this using a new transport config file:

rmail:
    debug_print = "T: rmail for $pipe_addresses"
    driver=pipe
    command = /usr/bin/uux - -r -a${lookup{$sender_address_local_part}lsearch,ret=key{/etc/passwd}} -gC $domain_data!rmail $pipe_addresses
    return_fail_output
    user=uucp

This was the biggest problem for me. The examples I saw for the `-a` argument to `uux` used `$sender_address`, resulting in an error about the third argument to `uux` being tainted. You can see these error messages in the exim main log (followed by a log entry showing that exim sends me a en error message):

2024-06-15 00:37:11 1sIFXj-00CzBd-26 <= alex@alexschroeder.ch U=alex P=local S=461
2024-06-15 00:37:11 1sIFXj-00CzBd-26 ** lkh@dwalin R=uucp_router T=rsmtp: Tainted arg 3 for rsmtp transport command: '-aalex@alexschroeder.ch'
2024-06-15 00:37:11 1sIFXj-00CzBh-2Q <= <> R=1sIFXj-00CzBd-26 U=Debian-exim P=local S=1695
2024-06-15 00:37:11 1sIFXj-00CzBd-26 Completed
2024-06-15 00:37:11 1sIFXj-00CzBh-2Q => alex <alex@alexschroeder.ch> R=local_user T=mail_spool
2024-06-15 00:37:11 1sIFXj-00CzBh-2Q Completed

I guess the examples I had seen would only work for older Exim versions that didn't do taint checking.

The code I'm using means that I'm looking up the sender local part ("alex" or "root") in `/etc/passwd` and if a match is found, the untainted key is returned (instead of the value from the password list).

You can test these expressions on the command-line:

exim -d+all -be '${lookup{$sender_address_local_part}lsearch,ret=key{/etc/passwd}}'

I also used to have rsmtp there, with `use_bsmtp` and `batch_max=100`. But who knows, perhaps that doesn't work all that well. Let's use `rmail` instead.

Testing it

As an ordinary user, use `mail` on the command line to send mail to `lkh@dwalin`.

Poor `lkh`. So many test mails.

As `root`, check the exim log:

root@sibirocobombus:~# tail /var/log/exim4/mainlog

Here's a mail being enqueued successfully:

2024-06-15 14:08:42 1sISD4-00GIbQ-1a <= alex@alexschroeder.ch U=alex P=local S=513
2024-06-15 14:08:42 1sISD4-00GIbQ-1a => lkh <lkh@dwalin> R=uucp_router T=rmail
2024-06-15 14:08:42 1sISD4-00GIbQ-1a Completed

Note the `uucp_router` and the `rmail` transport being used.

Check `uulog`. Here's where four mails are put into the queue and a few minutes later, Dwalin calls the enqueued messages are sent:

uux dwalin uucp (2024-06-15 09:50:47.05 3824697) Queuing rmail (D.000N)
uux dwalin uucp (2024-06-15 09:53:57.11 3824786) Queuing rmail (D.000O)
uux dwalin uucp (2024-06-15 09:53:57.14 3824790) Queuing rmail (D.000P)
uux dwalin uucp (2024-06-15 09:53:57.16 3824794) Queuing rmail (D.000Q)
uucico - - (2024-06-15 10:05:09.11 3828242) Incoming call (login Udwalin port stdin)
uucico dwalin - (2024-06-15 10:05:09.16 3828242) Handshake successful (protocol 'i' sending packet/window 1024/16 receiving 1024/16)
uucico dwalin uucp (2024-06-15 10:05:09.16 3828242) Sending rmail (D.000N) (552 bytes)
uucico dwalin uucp (2024-06-15 10:05:09.16 3828242) Sending rmail (D.000O) (538 bytes)
uucico dwalin uucp (2024-06-15 10:05:09.16 3828242) Sending rmail (D.000P) (530 bytes)
uucico dwalin uucp (2024-06-15 10:05:09.16 3828242) Sending rmail (D.000Q) (545 bytes)
uucico dwalin - (2024-06-15 10:05:09.21 3828242) Protocol 'i' packets: sent 14, resent 0, received 10
uucico dwalin - (2024-06-15 10:05:09.23 3828242) Call complete (0 seconds 2165 bytes 0 bps)

​#Administration ​#UUCP