code: fqa.9front.org

ref: 07be35d18f3946b1012a5e9c127ee4ac33db5779
dir: /fqa7.ms/

View raw version
.\" This troff source is processed to create all forms of the
.\" 9FRONT DASH 1 book and the http://fqa.9front.org website.
.\" NOTE: Purely experimental. Methods employed may change.
.\" troff -ms -mpictures fqa7.ms | page
.\" htmlroff -u -ms -mhtml fqa7.ms >fqa7.html
.de FG	\" .FG <basename>
.ie h .html - <img src="\\$1.\\$2" />
.el .BP \\$1.ps
.br
..
.po 1i \" page offset (from left)
.fp 1 R LucidaSans
.fp 2 I LucidaSansI
.fp 3 B LucidaSansB
.fp 4 BI LucidaSansI
.fp 5 CW LucidaCW
.paragraph 0
.margin 0
.HTML "FQA 7 - System Management
.html - <style type="text/css">body{font-size:10pt}; a{font-size:10pt}</style>
.html - <a href="fqa.html">FQA INDEX</a> |
.html - <a href="fqa6.html">FQA 6 - Networking</a> |
.html - <a href="fqa8.html">FQA 8 - Using 9front</a>
.html - <hr />
.SH
.LG
.ihtml h1 <h1>
FQA 7 - System Management
.ihtml h1
.NL
.R
.html - <a href="fqa7.html">html</a> |
.html - <a href="fqa7.pdf">pdf</a> |
.html - <a href="fqa7.ms">troff</a>

.FG orgchart jpg


.html - <a name="7.1" />
.ihtml h2 <h2>
.SH
7.1 - Plan 9 Services Overview
.R
.ihtml h2
.html - <br />
.FG plan9network png

In order to be an effective system manager it is a good idea to understand how the system is designed, and how it is intended to be used.

A Plan 9 installation consists of a disk file server, an authentication server, and one or more cpu servers and terminals\(emall sharing the same disk file system.

That said, Plan 9 services may be run on separate machines, all together on one machine, or in various combinations. The original design of Plan 9 assumed that each network service would run on separate hardware; by design, individual components of the system are generally unaware if they co-exist on the same machine or are distributed amongst separate machines.

This document will describe individual services as if they are all running separately.

Read:
.ihtml a <a href="http://doc.cat-v.org/plan_9/1st_edition/designing_plan_9">
.I
Designing Plan 9,
.R
.ihtml a
.ihtml a <a href="http://doc.cat-v.org/plan_9/4th_edition/papers/9">
.I
Plan 9 From Bell Labs,
.R
.ihtml a
.ihtml a <a href="http://doc.cat-v.org/plan_9/4th_edition/papers/net">
.I
The Organization of Networks in Plan 9
.R
.ihtml a

.html - <a name="7.1.1" />
.ihtml h3 <h3>
.SH
7.1.1 - What is the kernel?
.R
.ihtml h3

The kernel is a service that provides processes and resources to users active on an individual machine. Every Plan 9 machine boots a kernel.

At boot time the kernel takes on the identify of
.CW $user
(the user who logs in at the console), which becomes the
.CW hostowner
of the system. The
.CW hostowner
in turn 1.) controls access to the kernel's resources, 2.) serves as the auth identity (\f(CWauthid\fR) of the machine and the services it provides.

.B Note:
The
.CW hostowner
differs from the concept of
.CW root
on a UNIX system, where a single user
.CW root
may take control of all processes
.I and
files on the system. By contrast, even the
.CW hostowner
of a Plan 9 file server cannot violate file permissions on the file server, except when permissions checking is disabled on the console or when entering special commands at the console of the file server. The
.CW hostowner
controls only the
.I processes
running on the local machine. This fundamental separation between control of processes and file permissions is exploited throughout the Plan 9 system, but can be confusing for users coming from a UNIX background.

.html - <a name="7.1.2" />
.ihtml h3 <h3>
.SH
7.1.2 - What is the file server?
.R
.ihtml h3

In a traditional Plan 9 network there is one disk file server, typically the only machine with a physical hard disk, that serves files to all other machines on the network. In most cases, other machines are either diskless or only use their disks for local caching. Ken Thompson's original Plan 9 file server ran a unique, special-purpose kernel that
.I only
served files, and whose configuration could only be changed at the console. In 9front, the file server runs a normal kernel and typically also runs as a cpu server (for remote access).

9front supports two different disk file systems for use on the file server:
.CW cwfs
and
.CW hjfs .
.CW cwfs
is a userspace port of Ken Thompson's original Plan 9 file server.
.CW hjfs
is a new, experimental file server that stores both the cache and worm on a single partition (and thus requires less disk space to be used effectively). Both are reasonably robust.

Read:
.ihtml a <a href="http://doc.cat-v.org/plan_9/4th_edition/papers/fs">
.I
The Plan 9 File Server
.R
.ihtml a
(deprecated, but partially applies to \f(CWcwfs\fR),
.ihtml a <a href="http://man.9front.org/4/cwfs">
.CW cwfs(4) ,
.ihtml a
.ihtml a <a href="http://man.9front.org/4/hjfs">
.CW hjfs(4)
.ihtml a

.B Note:
Since most Plan 9 systems have no disk, security of the file server is largely protected from breaches of security in its clients. The fewer the programs that run on the file server, the more isolated it can be from security holes in programs.

.B Note:
Users seeking access to the file server must be added as a user on the file system itself, and, if auth is enabled, added to the auth server's user database.

.B Note:
Some users choose to run remote cpu or auth servers as stand-alone systems, each with their own local disk file systems. The distinction between all these types of systems is fuzzy and can become even fuzzier as services are enabled and disabled in different combinations.

.html - <a name="7.1.3" />
.ihtml h3 <h3>
.SH
7.1.3 - What is the auth server?
.R
.ihtml h3

The auth server manages authentication for an entire Plan 9 network. It boots a normal kernel but is usually run on a separate, diskless machine that performs no other functions, in order to reduce the danger of a security breach compromising its kernel processes. That said, the auth server is usually also configured as a cpu server, for remote access.

.B Note:
The
.ihtml a <a href="http://man.9front.org/8/cron">
.CW cron(8)
.ihtml a
service should be run only on the auth server, where it can authenticate itself to access any of the other machines on the network.

Read:
.ihtml a <a href="http://doc.cat-v.org/plan_9/4th_edition/papers/auth">
.I
Security in Plan 9,
.R
.ihtml a
.ihtml a <a href="http://man.9front.org/8/auth">
.CW auth(8)
.ihtml a

.html - <a name="7.1.4" />
.ihtml h3 <h3>
.SH
7.1.4 - What is the cpu server?
.R
.ihtml h3

The cpu server is used for remote computation. A cpu server's kernel runs processes in isolation, on only that machine. The boot process of a cpu server (defined as such by setting
.CW service=cpu
in the machine's
.CW plan9.ini
or equivalent) may be examined by reading the
.CW /rc/bin/cpurc
script, which is executed at boot time. Running as a cpu server causes the kernel to adjust certain resource values that ultimately determine the behavior of the machine. For example, the
.CW cpurc
script starts certain programs only if the machine is recognized as a cpu server.

Common use cases for a separate cpu server are: To execute programs compiled for a different architecture than that of the terminal; To execute programs closer to the data they are operating upon (for example, if the terminal is running over a slow link but the cpu server is on the same ethernet segment as the file server); To execute processes in physical isolation from other processes. In the early days of Plan 9, a cpu server was often significantly more powerful than the (often, special-purpose) hardware used for diskless terminals. Today, terminals are typically powerful computers in their own right, and the need for a separate machine running only as a cpu server is less common. That said, it can be useful to execute unstable or unpredictable programs on a separate machine so that frequently crashing and/or rebooting does not affect one's immediate workspace environment\(emespecially when testing new code. In the case of remote (mail, web, etc.) servers, it is also likely that cpu access would be desired.

In practice, the disk file server, the auth server, and even some terminals will often run their own cpu listeners, to enable remote access to the processes controlled by their kernels.

.B Note:
Users seeking access to a cpu server must first be added on the file system of the cpu server's corresponding file server (for permission to access and modify files) as well as the user database of its designated auth server (for login authentication).

Read:
.ihtml a <a href="http://doc.cat-v.org/plan_9/4th_edition/papers/net/">
.I
The Organization of Networks in Plan 9,
.R
.ihtml a
.ihtml a <a href="http://man.9front.org/1/cpu">
.CW cpu(1) ,
.ihtml a
.ihtml a <a href="http://man.9front.org/4/exportfs">
.CW exportfs(4)
.ihtml a

.html - <a name="7.1.5" />
.ihtml h3 <h3>
.SH
7.1.5 - What is a terminal?
.R
.ihtml h3

The terminal is the machine at which the Plan 9 user is most often physically located. Usually diskless, the terminal will almost always run with graphics enabled (for launching the
.CW rio
GUI or other graphical programs). The boot process of a terminal (defined as such by setting
.CW service=terminal
in the machine's
.CW plan9.ini
or equivalent) may be examined by reading the
.CW /rc/bin/termrc
script, which is executed at boot time.

.B Note:
Many Plan 9 users run stand-alone systems that operate \(em effectively \(em as a combined terminal and file server. For example, inside a virtual machine such as qemu, or booted from hard disk on a laptop. In this case the Plan 9 network is entirely self-contained, running one kernel on one machine, which renders auth and cpu services superfluous. This configuration trades some of the inherent security of separate hardware and kernel boundaries for the convenience of combining the whole system into a single, bootable instance.

.B Note:
Terminal users who do not run stand-alone machines or who wish to access Plan 9 network resources must first be added to the file system of the network's file server, and to the user database of the network's auth server.

.html - <a name="7.2" />
.ihtml h2 <h2>
.SH
7.2 - Kernel configuration and maintenance
.R
.ihtml h2

.html - <a name="7.2.1" />
.ihtml h3 <h3>
.SH
7.2.1 - How do I mount the 9fat partition?
.R
.ihtml h3

9front has done away with the scripts
.CW 9fat: ,
.CW c: ,
and so forth, that are found in the
.ihtml a <a href="https://9p.io/plan9/">
Bell Labs Plan 9
.ihtml a
distribution. Instead, use the
.CW 9fs
script to mount the 9fat partition:
.P1
9fs 9fat
.P2

If you are not at the console, or if 
.CW #S
has not already been bound over
.CW /dev :
.P1
bind -b \'#S\' /dev # bind the local hard drive kernel device over /dev
9fs 9fat /dev/sdXX/9fat # specify the full path to the corresponding 9fat
.P2

.B Note:
.CW
9fs 9fat
.R
posts a file descriptor in
.CW /srv/dos .
If this file already exists and is already in use,
.CW
9fs 9fat
.R
will fail. If no other process is using the file it is safe to simply remove it and run
.CW
9fs 9fat
.R
again.

Read:
.ihtml a <a href="http://man.9front.org/4/dossrv">
.CW dossrv(4)
.ihtml a

.html - <a name="7.2.2" />
.ihtml h3 <h3>
.SH
7.2.2 - How do I modify plan9.ini?
.R
.ihtml h3

Mount the
.CW 9fat
partition and then edit the file
.CW /n/9fat/plan9.ini .

.B Note:
The file must end with a newline.

Read:
.ihtml a <a href="http://man.9front.org/8/plan9.ini">
.CW plan9.ini(8)
.ihtml a

.html - <a name="7.2.3" />
.ihtml h3 <h3>
.SH
7.2.3 - Kernel configuration file
.R
.ihtml h3

Kernel configuration files are stored in the kernel directory and share the name of the kernel to which they apply. For example, the configuration file for the
.CW pc
kernel is
.CW /sys/src/9/pc/pc .

.html - <a name="7.2.4" />
.ihtml h3 <h3>
.SH
7.2.4 - Kernel drivers
.R
.ihtml h3

Kernel driver source files are located in the kernel source directory. For example, the
.CW pc
kernel source is located in
.CW /sys/src/9/pc .

.html - <a name="7.2.5" />
.ihtml h3 <h3>
.SH
7.2.5 - How do I install a new kernel?
.R
.ihtml h3

To build and install the new kernel(s) on the file system:

For 386:
.P1
cd /sys/src/9/pc
mk install # kernel is copied to /386/9pc
.P2

For amd64:
.P1
cd /sys/src/9/pc64
mk install # kernel is copied to /amd64/9pc64
.P2

For arm / bcm (Raspberry Pi, etc.):
.P1
cd /sys/src/9/bcm
mk install # kernel is copied to /arm/9pi2
.P2

For arm64 / bcm64 (Raspberry Pi 3):
.P1
cd /sys/src/9/bcm64
mk install # kernel is copied to /arm64/9pi3
.P2

For 386 and amd64 machines with local disk, it may be desired to install the new bootloader and kernels onto the
.CW 9fat
partition, in order to boot directly from disk.
.B Note:
The bootloader needs to be continuous on disk, so simply copying over the original file does not produce the desired effect. Instead:
.P1
9fs 9fat
rm /n/9fat/9bootfat
cp /386/9bootfat /n/9fat/
chmod +al /n/9fat/9bootfat # defrag magic
.P2

then copy the desired kernels:

For 386:
.P1
cp /386/9pc /n/9fat/
.P2

For amd64:
.P1
cp /amd64/9pc64 /n/9fat/
.P2

Finally, if a different kernel is being intsalled than the one currently running, edit
.CW plan9.ini
and change
.CW bootfile
to point to the new kernel.

Read:
.ihtml a <a href="fqa7.html#7.2.2">
.I
FQA 7.2.2 - How do I modify plan9.ini?
.R
.ihtml a

.html - <a name="7.3" />
.ihtml h2 <h2>
.SH
7.3 - Fileserver configuration and maintenance
.R
.ihtml h2

.html - <a name="7.3.1" />
.ihtml h3 <h3>
.SH
7.3.1 - Adding users
.R
.ihtml h3

Add a new user on the file server:

For
.CW cwfs :
.P1
echo newuser username >>/srv/cwfs.cmd
.P2

For
.CW hjfs :
.P1
echo newuser username >>/srv/hjfs.cmd
.P2

If needed, make the new user a member of another group (example: upas):

For
.CW cwfs :
.P1
echo newuser upas +username >>/srv/cwfs.cmd
.P2

For
.CW hjfs :
.P1
echo newuser upas +username >>/srv/hjfs.cmd
.P2

Both file servers store their user database in
.CW /adm/users .
Examine this file, and the contents of the
.CW /usr
directory, to evaluate success.

.B Note:
It is also possible to access the control file interactively:

For
.CW cwfs :
.P1
con -C /srv/cwfs.cmd
.P2

For
.CW hjfs :
.P1
con -C /srv/hjfs.cmd
.P2

From here commands may be entered directly.

Type
.CW
Ctrl-\e
.R
to resume the
.CW con
prompt, followed by
.CW q
to quit.

.B Note:
New users are created without a profile, mail directory, tmp directory (needed to edit files with
.CW sam )
or other confections. To install a default profile for a new user, upon first login as that user, run:
.P1
\&/sys/lib/newuser
.P2
then edit
.CW /usr/username/lib/profile
to your own specifications. The
.CW newuser
file system command is described in the man pages
.ihtml a <a href="http://man.9front.org/8/fs">
.CW fs(8)
.ihtml a
(for \f(CWcwfs\fR) and
.ihtml a <a href="http://man.9front.org/8/hjfs">
.CW hjfs(8) .
.ihtml a
The default system
.CW /lib/namespace
does the following:
.P1
bind -c /n/other/usr/$user/tmp /usr/$user/tmp
.P2
For
.CW cwfs
users, it may be desirable to store the user's
.CW tmp
directory on the
.CW other
partition:
.P1
mkdir /n/other/usr/$user/tmp
.P2

.html - <a name="7.3.2" />
.ihtml h3 <h3>
.SH
7.3.2 - Configuring nvram
.R
.ihtml h3

The cpu kernel checks the
.CW nvram
file for valid auth credentials and attempts to copy them into
.CW factotum
so that the machine may boot without manual intervention. To configure the
.CW nvram ,
run the command
.CW auth/wrkey ,
which will prompt for an
.CW authid ,
.CW authdom ,
.CW
secstore key,
.R
and
.CW password .
The
.CW authid
is a synonym for the
.CW hostowner
of the machine and should be a valid user that has already been (or will be) added to the corresponding auth server, in this case
.CW glenda .
The
.CW authdom
is the authentication domain for the machine, in this case
.CW 9front .
The
.CW
secstore key
.R
and
.CW password
are secret passwords of eight characters or more in length. The
.CW password
is the password belonging to the
.CW authid
user on the auth server responsible for the
.CW authdom
entered above. The
.CW
secstore key
.R
is the password of the user on the secure-store server (Read:
.ihtml a <a href="fqa7.html#7.4.3">
.I
FQA 7.4.3 - secstored).
.R
.ihtml a
If the
.CW secstore
client (Read:
.ihtml a <a href="fqa8.html#8.4.7">
.I
FQA 8.4.7 - secstore)
.R
.ihtml a
is not being used on this machine (for example, if this is the auth server where
.CW secstored
will run), just hit
.CW enter
at the
.CW
secstore key:
.R
prompt.

Run the command
.CW auth/wrkey :
.P1
bad nvram key
bad authentication id
bad authentication domain	# You may not see these errors.
authid: glenda
authdom: 9front
secstore key: [glenda's secstore password]
password: [glenda's password]
.P2

To ensure that the correct nvram partition is found in all cases, an
.CW nvram
line should be added to
.CW /n/9fat/plan9.ini .
.P1
nvram=#S/YOURDRIVE/nvram
.P2

.B Note:
Booting the file system with authentication enabled and an invalid
.CW nvram
file will cause
.CW auth/wrkey
to be run automatically at startup.

Read:
.ihtml a <a href="http://man.9front.org/8/auth">
.CW auth(8)
.ihtml a

.html - <a name="7.3.3" />
.ihtml h3 <h3>
.SH
7.3.3 - Setting up a listener for network connections
.R
.ihtml h3

In order for remote machines to mount the file system of the file server, the file server must first be running a network listener. This section details the steps required to transform a terminal with disk (the result of a default install of 9front) into a disk file server for other machines.

The first step is to switch from the terminal service to the cpu service by editing the
.CW service
line in
.CW /n/9fat/plan9.ini :
.P1
service=cpu
.P2

Read:
.ihtml a <a href="fqa7.html#7.2.2">
.I
FQA 7.2.2 - How do I modify plan9.ini?
.R
.ihtml a

Before rebooting, configure the nvram:
.ihtml a <a href="fqa7.html#7.3.2">
.I
FQA 7.3.2 - Configuring nvram.
.R
.ihtml a
This allows the machine to load auth credentials from the
.CW nvram
file into
.CW factotum ,
so that it can continue to boot without manual intervention.

Reboot:
.P1
fshalt -r
.P2

The next step (on cwfs; not needed on hjfs) is to enable authentication on the file server, to prevent unauthorized users from accessing the disk over the network. At the
.CW bootargs
prompt, retype the default and add the
.CW -c
flag to enter the file server's config mode. At the
.CW config
prompt, type
.CW noauth
twice to toggle  authentication on the file server. Finally, type
.CW end
to continue with the boot process:
.P1
bootargs is (tcp, local!device)
	[local!/dev/sdXX/fscache] local!/dev/sdXX/fscache -c
config: noauth
auth is now disabled
config: noauth
auth is now enabled
config: end
.P2

The machine will now continue to boot.

Once booted, the next step is to configure the file server to listen for connections from remote hosts. Modify the
.CW bootargs
of the file server in
.CW /n/9fat/plan9.ini :

For cwfs:
.P1
bootargs=local!/dev/sdXX/fscache -a tcp!*!564
.P2

For hjfs:
.P1
bootargs=local!/dev/sdXX/fs -m 702 -A -a tcp!*!564
.P2

.B Note:
The
.CW
-m 702
.R
flag for
.CW hjfs
allocates 702 megabytes of memory to be used as a cache. This value is typically automatically calculated by the 9front installer, and may differ on your system. There is no need to change whatever default was already configured.

Read:
.ihtml a <a href="fqa7.html#7.2.2">
.I
FQA 7.2.2 - How do I modify plan9.ini?
.R
.ihtml a

Reboot the file server:
.P1
fshalt -r
.P2

When the system finishes booting it should now be listening for network connections to the file system. Users who have been added to the file server and the auth server should now be able to authenticate and mount the file server (tcp boot, etc.).

Read:
.ihtml a <a href="http://man.9front.org/4/cwfs">
.CW cwfs(4) ,
.ihtml a
.ihtml a <a href="http://man.9front.org/4/hjfs">
.CW hjfs(4) ,
.ihtml a
.ihtml a <a href="fqa6.html#6.7.1">
.I
FQA 6.7.1 - How do I tcp boot?
.R
.ihtml a
.bp
.html - <a name="7.3.3.1" />
.ihtml h3 <h3>
.SH
7.3.3.1 - Stop cwfs from allowing user none to attach without authentication
.R
.ihtml h3

.P1
echo nonone >>/srv/cwfs.cmd
.P2

.html - <a name="7.3.3.1.1" />
.ihtml h3 <h3>
.SH
7.3.3.1.1 - notes on user none
.R
.ihtml h3
.html ul <ul>

[continued on next page following]
.DS
.CW /sys/src/9/port/chan.c:1321,1335

Date: Fri, 22 Jan 2021 15:44:05 -0800
From: Anthony Martin <[email protected]>
To: [email protected]
Subject: [9front] notes on user none
Reply-To: [email protected]

I remembered investigating the restrictions on user none
in the past so I went and dug out my notes. They're only
applicable to fossil and cwfs, though, so someone else
will have to go through the hjfs code to compare.

The notes are attached below.

Cheers,
  Anthony

# from /sys/doc/9.ms
Finally, a special user called none has no password and is always
allowed to connect; anyone may claim to be none. None has restricted
permissions; for example, it is not allowed to examine dump files and
can read only world-readable files.

# from /sys/doc/auth.ms
Factotum is the only process that needs to create capabilities, so all
the network servers can run as untrusted users (e.g., Plan 9's none or
Unix's nobody), which greatly reduces the harm done if a server is
buggy and is compromised.


# kernel
- documented
	- anyone can become none with none(8)
- undocumented
	- eve can change the owner of proc(3) files to none
	- none cannot use proc(3) to view or modify the state of other processes
	- none cannot create shr(3) files on 9front

# cwfs(4) and fossil(4)
- documented
	- none cannot authenticate a connection
		- auth(5) with uname "none" returns Rerror
	- none can be chaperoned on authenticated connections
		- attach(5) with afid NOFID sets uname to "none"
	- none has minimal access permissions (i.e. "world" or "other")
	- users in the "noworld" group are denied world access permissions
- undocumented
	- none cannot be a group leader
		- wstat(5) is limited

# fossil(4)
- documented
	- none cannot attach to an unauthenticated connection
		- unless the -N flag is given to listen or srv
	- users not in the "write" group cannot modify the file system
		- unless the group doesn't exist
- undocumented
	- none cannot modify file status information
		- wstat(5) returns Rerror

# cwfs(4)
- documented
	- none *can* attach to an unauthenticated connection
		- unless the nonone flag is set on 9front (undocumented)
- undocumented
	- none cannot attach to the dump file system
		- attach(5) returns Rerror
.DE
.html ul

.html - <a name="7.3.4" />
.ihtml h3 <h3>
.SH
7.3.4 - Mounting a file system from userspace
.R
.ihtml h3

For cwfs:
.P1
# use the correct path to your fscache
% cwfs64x -n fs -f /dev/sdE0/fscache
% mount /srv/fs /n/fs

.B Note:
Running the above commands will post the file systems's console in
.CW /srv/fs.cmd .
.P2

For hjfs:
.P1
# use the correct path to your fs partition
% hjfs -n hjfs -f /dev/sdE0/fs
% mount /srv/hjfs /n/hjfs
.P2

.html - <a name="7.3.5" />
.ihtml h3 <h3>
.SH
7.3.5 - dump
.R
.ihtml h3

.html - <a name="7.3.5.1" />
.ihtml h3 <h3>
.SH
7.3.5.1 - manually trigger the dump
.R
.ihtml h3

As
.CW hostowner ,

For cwfs:
.P1
% echo dump >>/srv/cwfs.cmd
.P2

For hjfs:
.P1
% echo dump >>/srv/hjfs.cmd
.P2
.bp
.html - <a name="7.4" />
.ihtml h2 <h2>
.SH
7.4 - Auth server configuration and maintenance
.R
.ihtml h2

.html - <a name="7.4.1" />
.ihtml h3 <h3>
.SH
7.4.1 - Configuring an auth server
.R
.ihtml h3

The auth server should be booted with
.CW service=cpu
in
.CW plan9.ini ,
and
.CW ndb
modified to associate the new auth server with the desired
.CW authdom .

If the cpu server machine boots from a local disk, edit the
.CW service
line in in
.CW /n/9fat/plan9.ini :
.P1
service=cpu
.P2

Read:
.ihtml a <a href="fqa7.html#7.2.2">
.I
FQA 7.2.2 - How do I modify plan9.ini?
.R
.ihtml a

If the machine boots via PXE, edit the
.CW service
line in in the file under
.CW /cfg/pxe/
that correspondes to its MAC address. In this case,
.CW /cfg/pxe/000c292fd30c :
.P1
service=cpu
.P2

.B Note:
The contents of
.CW /cfg/pxe/000c292fd30c
serves as the equivalent of
.CW plan9.ini
for the PXE booted machine. Any other settings that would normally be configured in
.CW plan9.ini
may also be entered there.

Next,
.CW ndb
must be modified to associate the new auth server with the desired
.CW authdom .
Assuming the auth server has a MAC address of
.CW 00:0c:29:2f:d3:0c ,
an IP address of
.CW 192.168.0.2 ,
and a default gateway/DNS server of
.CW 192.168.0.1
that are all on the Class C network
.CW 192.168.0.0/24 ,
and that the
.CW authdom
is
.CW 9front ,
edit
.CW /lib/ndb/local
and add the
.CW authdom
and the auth server's IP under the corresponding
.CW ipnet :
.P1
ipnet=9front ip=192.168.0.0 ipmask=255.255.255.0
	ipgw=192.168.0.1
	auth=192.168.0.2 # add auth server's ip
	authdom=9front # add authdom
	fs=192.168.0.3
	cpu=192.168.0.4
	dns=192.168.0.1
	dnsdomain=9front
	smtp=192.168.0.4
.P2

Read:
.ihtml a <a href="http://man.9front.org/6/ndb">
.CW ndb(6)
.ihtml a

Before rebooting, configure the nvram:
.ihtml a <a href="fqa7.html#7.3.2">
.I
FQA 7.3.2 - Configuring nvram.
.R
.ihtml a
This allows the machine to load auth credentials from the
.CW nvram
file into
.CW factotum ,
so that it can continue to boot without manual intervention.

.B Note:
If the auth server's
.CW hostowner
(referred to as
.CW authid
in the
.CW auth/wrkey
dialogue) will be any other user than the default
.CW glenda ,
that user must be authorized (in the auth context) to "speak for" other users. Assuming a hostowner of
.CW sl ,
add a rule to
.CW /lib/ndb/auth :
.P1
hostid=sl
	uid=!sys uid=!adm uid=*
.P2
This rule allows the user
.CW sl
to speak for all users
.I
except for
.R
.CW sys
and
.CW adm .

Read:
.ihtml a <a href="http://man.9front.org/8/auth">
.CW auth(8)
.ihtml a

Reboot:
.P1
fshalt -r
.P2

At boot time, the shell script
.CW /rc/bin/cpurc
consults
.CW ndb
to determine if the machine is an auth server. If it is, the script will launch the
.CW keyfs
process and start listeners for auth connections. If, after booting,
.CW keyfs
is not running, something went wrong.

Finally, create an auth user and configure an auth password for the hostowner of the machine. This auth user should be the same name as the
.CW authid
that was entered at boot time during the
.CW auth/wrkey
dialogue. Likewise, set the
.CW password
to match the
.CW password
that was entered during the
.CW auth/wrkey
dialogue.
.B Note:
If the user and password do not match what was entered during the
.CW auth/wrkey
dialogue, users will not be able to authenticate using this auth server.

Read:
.ihtml a <a href="fqa7.html#7.4.2">
.I
FQA 7.4.2 - Adding users
.R
.ihtml a

.html - <a name="7.4.1.1" />
.ihtml h4 <h4>
.SH
7.4.1.1 - Avoiding an ndb entry for the auth server
.R
.ihtml h4

If an auth server for a given
.CW authdom
is not found in the local
.CW ndb ,
then the
.CW authdial()
function from the
.CW libauthsrv
library (used for resolving auth servers) will default to the dns host name
.CW p9auth.example.com ,
where
.CW p9auth
is the subdomain, and
.CW example.com
is the authdom. This convention (where followed) is useful to avoid having to manually add auth server information for arbitrary remote networks to the local
.CW ndb .

.html - <a name="7.4.2" />
.ihtml h3 <h3>
.SH
7.4.2 - Adding users
.R
.ihtml h3

To add a new user to the auth server, login as the auth server's
.CW hostowner ,
make sure
.CW auth/keyfs
is running in your namespace, and then set an auth password for the user:
.P1
% auth/keyfs
% auth/changeuser username
Password: # type password here, will not echo
Confirm password: # confirm password here, will not echo
assign Inferno/POP secret? (y/n) n
Expiration date (YYYYMMDD or never)[return = never]: 
2 keys read
Post id: 
User's full name: 
Department #: 
User's email address: 
Sponsor's email address: 
user username installed for Plan 9
.P2

.B Note:
Questions that appear after the
.CW
keys read
.R
notice are optional. Hit
.CW Enter
for each one to leave them blank.

Read:
.ihtml a <a href="http://man.9front.org/8/auth">
.CW auth(8),
.ihtml a
.ihtml a <a href="http://man.9front.org/4/keyfs">
.CW keyfs(4)
.ihtml a

.html - <a name="7.4.3" />
.ihtml h3 <h3>
.SH
7.4.3 - secstored
.R
.ihtml h3

Secstore authenticates to a secure-store server using a
password and optionally a hardware token, then saves or
retrieves a file.  This is intended to be a credentials
store (public/private keypairs, passwords, and other
secrets) for a
.CW factotum .

To set up
.CW secstored ,
login to the auth server as
.CW hostowner
and:
.P1
mkdir /adm/secstore
chmod 770 /adm/secstore
.P2

Start
.CW secstored
at boot time by adding the following to
.CW /cfg/$sysname/cpurc
on the auth server:
.P1
auth/secstored
.P2

Read:
.ihtml a <a href="http://man.9front.org/1/secstore">
.CW secstore(1) ,
.ihtml a
.ihtml a <a href="http://man.9front.org/8/secstore">
.CW secstore(8)
.ihtml a

.html - <a name="7.4.3.1" />
.ihtml h4 <h4>
.SH
7.4.3.1 - Adding users to secstore
.R
.ihtml h4

.CW secuser
is an administrative command that runs on the secstore machine,
normally the auth server, to create new accounts and to change status on
existing accounts.  It prompts for account information such as password
and expiration date, writing to
.CW /adm/secstore/who/user
for a given secstore user.

Login to the auth server as
.CW hostowner
and:
.P1
auth/secuser username
.P2
and answer the prompts.

By default,
.CW secstored
warns the client if no account exists.
If you prefer to obscure this information, use
.CW secuser
to create an account
.CW FICTITIOUS .

Read:
.ihtml a <a href="fqa8.html#8.4.7">
.I
FQA 8.4.7 - secstore
.R
.ihtml a
for more information on using the
.CW secstore
client.

.html - <a name="7.4.3.2" />
.ihtml h4 <h4>
.SH
7.4.3.2 - Converting from p9sk1 to dp9ik
.R
.ihtml h4

[continued on next page following]
.P1
Date: Wed, 6 Jan 2016 03:54:08 +0100
From: [email protected]
To: [email protected]
Subject: [9front] new factotum/authsrv/keyfs
Reply-To: [email protected]

i just pushed the new code which adds dp9ik authentication support.

to update a system, the following things need to be done:

# make sure you have the latest libmp/libsec 
cd /sys/src/libmp; mk install
cd /sys/src/libsec; mk install

# rebuild mpc (required for libauthsrv)
cd /sys/src/cmd; mk mpc.install

# rebuild libauthsrv / libauth
cd /sys/src/libauthsrv; mk install
cd /sys/src/libauth; mk install

# rebuild factotum/keyfs/authsrv
cd /sys/src/cmd/auth; mk install

# then rebuild kernel to include the new factotum,
# but dont reboot your authserver just yet...
cd /sys/src/9/pc; mk install

# if your /adm/keydb is still in DES format (cat it to see
# if the keyfile starts with the AES signature), you need to
# convert it to use the new dp9ik protocol:

# make backup
cp /adm/keys /adm/keys.old
auth/convkeys -ap /adm/keys

# now set the aes key in nvram (so authserver can decrypt
# the keydb when it boots)
auth/wrkey

# now you can reboot the AS and once its up, you have to
# set new passwords for the users. logging in with the
# old p9sk1 plan9 password should continue to work if
# you skip this.
passwd [username]

# if there are issues logging in with dp9ik because keydb
# doesnt have the new key yet, you can use delkey(1) to
# remove the dp9ik key from factotum as a work arround.

--
cinap
.P2

.html - <a name="7.5" />
.ihtml h2 <h2>
.SH
7.5 - Cpu server configuration and maintenance
.R
.ihtml h2

.html - <a name="7.5.1" />
.ihtml h3 <h3>
.SH
7.5.1 - Configuring a cpu server
.R
.ihtml h3

.B Note:
Operating a cpu server requires auth services. Read:
.ihtml a <a href="fqa7.html#7.4">
.I
FQA 7.4 - Auth server configuration and maintenance
.R
.ihtml a

The first step in converting a terminal to a cpu server is to switch from the
.CW terminal
service to the
.CW cpu
service.

If the cpu server machine boots from a local disk, edit the
.CW service
line in in
.CW /n/9fat/plan9.ini :
.P1
service=cpu
.P2

Read:
.ihtml a <a href="fqa7.html#7.2.2">
.I
FQA 7.2.2 - How do I modify plan9.ini?
.R
.ihtml a

If the machine boots via PXE, edit the
.CW service
line in in the file under
.CW /cfg/pxe/
that correspondes to its MAC address. In this case,
.CW /cfg/pxe/000c292fd30c :
.P1
service=cpu
.P2

.B Note:
The contents of
.CW /cfg/pxe/000c292fd30c
serves as the equivalent of
.CW plan9.ini
for the PXE booted machine. Any other settings that would normally be configured in
.CW plan9.ini
may also be entered here.

Setting
.CW service=cpu
causes the shell script
.CW /rc/bin/cpurc
to be run at boot time, which in turn launches a listener that scans the
.CW /rc/bin/service
directory for scripts corresponding to various network ports. Read:
.ihtml a <a href="http://man.9front.org/8/listen">
.CW listen(8) .
.ihtml a
The script
.CW tcp17019
handles incoming cpu connections. Authentication for incoming cpu connections is performed by the auth server associated with the
.CW authdom
by
.CW ndb .
Read:
.ihtml a <a href="fqa7.html#7.4.1">
.I
FQA 7.4.1 - Configuring an auth server
.R
.ihtml a

Before rebooting, configure the nvram:
.ihtml a <a href="fqa7.html#7.3.2">
.I
FQA 7.3.2 - Configuring nvram.
.R
.ihtml a
This allows the machine to load auth credentials from the
.CW nvram
file into
.CW factotum ,
so that it can continue to boot without manual intervention.

Reboot:
.P1
fshalt -r
.P2

.html - <a name="7.6" />
.ihtml h2 <h2>
.SH
7.6 - Terminal configuration and maintenance
.R
.ihtml h2

.html - <a name="7.6.1" />
.ihtml h3 <h3>
.SH
7.6.1 - Configuring a terminal
.R
.ihtml h3

The 9front ISO boots into a livecd running the
.CW 9pc
kernel, resulting in the simplest form of terminal running on the 386 architecture. A terminal may also be network booted (the preferred method) or installed to its own stand-alone file system on a local storage device.

Read:
.ihtml a <a href="fqa6.html#6.7">
.I
FQA 6.7 - How do I boot from the network?
.R
.ihtml a

.html - <a name="7.6.2" />
.ihtml h3 <h3>
.SH
7.6.2 - Configuring a Terminal to Accept cpu Connections
.R
.ihtml h3

If the
.CW hostowner
factotum has been loaded with the appropriate key and the system is listening for
.CW cpu
connections, a user may
.CW cpu
into a terminal that is not running auth services. To configure a terminal to accept
.CW cpu
connections in this fashion, substitute your choice of
.CW dom
(this refers to the authdom),
.CW user
and
.CW password ,
below:
.P1
echo \'key proto=dp9ik dom=9front user=glenda !password=p@ssw0rd\' \e
	>/mnt/factotum/ctl
aux/listen1 -t \'tcp!*!rcpu\' /rc/bin/service/tcp17019
.P2

.html - <a name="7.6.3" />
.ihtml h3 <h3>
.SH
7.6.3 - UTC Timesync
.R
.ihtml h3

By default,
.CW /rc/bin/termrc
sets
.CW TIMESYNCARGS=(-rLa1000000) ,
to synchronize 9front time with the real time clock. On many systems this time is saved as UTC, whereas Windows keeps the local time there. If your time is in UTC you should omit the -L: 
Put
.CW TIMESYNCARGS=(-ra1000000)
into
.CW /rc/bin/termrc.local ,
which is executed by
.CW /rc/bin/termrc .

.html - <a name="7.7" />
.ihtml h2 <h2>
.SH
7.7 - Mail server configuration and maintenance
.R
.ihtml h2
.html - <br />
.FG upas gif

Incoming and outgoing mail is handled by
.ihtml a <a href="http://doc.cat-v.org/bell_labs/upas_mail_system/">
upas
.ihtml a
and its related suite of programs. Configuration is handled by a number of files found in
.CW /mail/lib/ ,
while many of
.CW upas'
common functions are carried out by shell scripts that are (relatively) easy to modify.

.B Note:
The user who runs the assorted
.CW upas
programs needs read and write permissions on
.CW /mail/queue
and
.CW /mail/tmp ,
as well as write permissions for any mailboxes where mail will be delivered.

.B Note:
Be sure to configure proper DNS entries for your domains. If Plan 9 will host your DNS, see:
.ihtml a <a href="fqa6.html#6.2.5.2">
.I
FQA 6.2.5.2 - DNS authoritative name server
.R
.ihtml a

Read:
.ihtml a <a href="http://doc.cat-v.org/bell_labs/upas_mail_system/">
.I
Upas - A Simpler Approach to Network Mail,
.R
.ihtml a
.ihtml a <a href="http://man.9front.org/1/mail">
.CW mail(1)
.ihtml a

The following sections describe configuration of basic Internet mail services.

.html - <a name="7.7.1" />
.ihtml h3 <h3>
.SH
7.7.1 - smtpd.conf
.R
.ihtml h3

Some changes to the default
.CW smtpd.conf
are required to accept mail
.I for
Internet domain names, and to relay mail
.I for
remote hosts (most commonly, your own machines). The following lines should be changed to correspond to your network:
.P1
# outgoing mail will be sent from this domain by default
defaultdomain		9front.org

# do not be an open relay
norelay			on

# disable dns verification of sender domain
verifysenderdom		off

# do not save blocked messages
saveblockedmsg		off

# if norelay is on, you need to set the
# networks allowed to relay through 
# as well as the domains to accept mail for
ournets 199.191.58.37/32 199.191.58.42/32 192.168.4.0/24

# domain names for which incoming mail is accepted
ourdomains 9front.org, bell-labs.co, cat-v.org
.P2
.html - Example file: <a href="http://plan9.stanleylieber.com/mail/lib/smtpd.conf">smtpd.conf</a>
Read:
.ihtml a <a href="http://man.9front.org/6/smtpd">
.CW smtpd(6) ,
.ihtml a
.ihtml a <a href="http://man.9front.org/8/smtp">
.CW smtp(8)
.ihtml a

.html - <a name="7.7.2" />
.ihtml h3 <h3>
.SH
7.7.2 - rewrite
.R
.ihtml h3

To act as an Internet mail server, copy
.CW rewrite.direct
to
.CW rewrite
and modify to reflect your site's Internet domain name(s):

[continued on next page following]
.P1
# case conversion for postmaster
pOsTmAsTeR\ alias\ postmaster

# local mail
\el!(.*)\ alias\ \e1
(ttr|9front.org|bell-labs.co|cat-v.org)!(.*)	alias\ \e2
[^!@]+\ translate\ "/bin/upas/aliasmail \'&\'"
local!(.*)\ >>\ /mail/box/\\1/mbox

# we can be just as complicated as BSD sendmail...
# convert source domain address to a chain a@b@c@d...
@([^@!,]*):([^!@]*)@([^!]*)\ alias\ \e2@\e3@\e1
@([^@!]*),([^!@,]*):([^!@]*)@([^!]*)\ alias\ @\e1:\e3@\e4@\e2

# convert a chain a@b@c@d... to ...d!c!b!a
([^@]+)@([^@]+)@(.+)\ alias\ \e2!\e1@\e3
([^@]+)@([^@]+)\ alias\ \e2!\e1

# /mail/lib/remotemail will take care of gating to systems we don't know
([^!]*)!(.*)\ |\ "/mail/lib/qmail \'\e\es\' \'net!\e1\'" "\'\e2\'"
.P2
.html - Example file: <a href="http://plan9.stanleylieber.com/mail/lib/rewrite">rewrite</a>
Read:
.ihtml a <a href="http://man.9front.org/6/rewrite">
.CW rewrite(6)
.ihtml a

.html - <a name="7.7.3" />
.ihtml h3 <h3>
.SH
7.7.3 - names.local
.R
.ihtml h3

To map incoming e-mail addresses to local usernames, edit
.CW names.local
accordingly:
.P1
# postmaster goes to glenda
postmaster	glenda
.P2

.B Note:
\fIpostmaster\fR\f(CW@[any domain]\fR will be delivered to local user
.CW glenda .

.html - Example file: <a href="http://plan9.stanleylieber.com/mail/lib/names.local">names.local</a>
.html - <a name="7.7.4" />
.ihtml h3 <h3>
.SH
7.7.4 - remotemail
.R
.ihtml h3

Finally,
.CW upas
.R
needs to know what to do with mail that cannot be delivered locally. Edit
.CW remotemail
and enter the desired behavior.

To deliver mail directly to the remote server responsible for the Internet domain name in question:
.P1
#!/bin/rc
shift
sender=$1
shift
addr=$1
shift
exec /bin/upas/smtp $addr $sender $*
.P2
.html - Example file: <a href="http://plan9.stanleylieber.com/mail/lib/remotemail">remotemail</a>
Read:
.ihtml a <a href="http://man.9front.org/8/smtp">
.CW smtp(8)
.ihtml a

.html - <a name="7.7.5" />
.ihtml h3 <h3>
.SH
7.7.5 - SMTP over TLS
.R
.ihtml h3

First, make sure you have already
.ihtml a <a href="fqa7.html#7.9">
created TLS certificates
.ihtml a
for your server. 

Next, create a file
.CW /rc/bin/service/tcp587 :
.P1
#!/bin/rc
user=`{cat /dev/user}
exec /bin/upas/smtpd -c /sys/lib/tls/cert -n $3
# to use with listen1, change $3 to $net
.P2

.html - <a name="7.7.6" />
.ihtml h3 <h3>
.SH
7.7.6 - IMAP4 over TLS
.R
.ihtml h3

First, make sure you have already
.ihtml a <a href="fqa7.html#7.9">
created TLS certificates
.ihtml a
for your server. 

Next, create a file
.CW /rc/bin/service/tcp993 :
.P1
#!/bin/rc
exec tlssrv -c/sys/lib/tls/cert -limap4d \e
	-r`{cat $3/remote} /bin/ip/imap4d -p \e
	-r`{cat $3/remote} >>[2]/sys/log/imap4d
	# to use with listen1, change $3 to $net
.P2

.html - <a name="7.7.7" />
.ihtml h3 <h3>
.SH
7.7.7 - Spam Filtering
.R
.ihtml h3

.html - <a name="7.7.7.1" />
.ihtml h4 <h4>
.SH
7.7.7.1 - ratfs
.R
.ihtml h4

From
.ihtml a <a href="http://man.9front.org/4/ratfs">
.CW ratfs(4) :
.ihtml a

.html ul <ul>
.QS
Ratfs starts a process that mounts itself (see bind(2)) on mountpoint
(default /mail/ratify).  Ratfs is a persistent representation of the
local network configuration and spam blocking list.  Without it each
instance of smtpd(6) would need to reread and parse a multimegabyte
list of addresses and accounts.
.QE
.html ul

To configure the spam blocking list, edit
.CW /mail/lib/blocked
as desired, according to the rules laid out in the man page. Example:
.P1
# allow messages from any user at 9front.org
*allow	9front.org!*

# block messages from any user at bell-labs.com
*block	bell-labs.com!*

# block messages from ip block of aol modems
block	152.166.0.0/15
.P2
If
.CW ratfs
is already running, cause it to reload the modified
.CW /mail/lib/blocked :
.P1
echo reload >/mail/ratify/ctl
.P2
For more details, read:
.ihtml a <a href="http://man.9front.org/4/ratfs">
.CW ratfs(4) ,
.ihtml a
.ihtml a <a href="http://man.9front.org/6/smtpd">
.CW smtpd(6)
.ihtml a

To launch
.CW ratfs
at boot time, add the following line to
.CW /cfg/$sysname/cpustart :
.P1
upas/ratfs
.P2
and add the following line to
.CW /lib/namespace :
.P1
mount -c #s/ratify /mail/ratify
.P2
.B Note:
The directory served by
.CW ratfs
must be visible from the
.CW upas
listener's namespace. Usually, this is accomplished by starting
.CW ratfs
.I before
the
.CW upas
listeners.

.html - <a name="7.7.7.2" />
.ihtml h4 <h4>
.SH
7.7.7.2 - scanmail
.R
.ihtml h4

Read:
.ihtml a <a href="http://man.9front.org/8/scanmail">
.CW scanmail(8)
.ihtml a

.html - <a name="7.7.8" />
.ihtml h2 <h2>
.SH
7.7.8 - Troubleshooting the mail server
.R
.ihtml h2

An online tool that evaluates the configuration of a given mail server is available at:
.html a <a href="https://www.mail-tester.com">
.CW https://www.mail-tester.com
.html a

.html - <a name="7.7.9" />
.ihtml h2 <h2>
.SH
7.7.9 - Setting up a mailing list
.R
.ihtml h2

.html - <a name="7.7.9.1" />
.ihtml h2 <h2>
.SH
7.7.9.1 - mlmgr
.R
.ihtml h2

The
.ihtml a <a href="http://lists.9front.org">
9front mailing lists
.ihtml a
are hosted on 9front using the
.ihtml a <a href="http://man.9front.org/1/mlmgr">
.CW
mlmgr(1)
.R
.ihtml a
collection of tools.

Incoming mail to a list is filtered through a custom
.ihtml a <a href="http://plan9.stanleylieber.com/mlmgr/pipeto">
.CW
pipeto,
.R
.ihtml a
which in turn calls a script called
.ihtml a <a href="http://plan9.stanleylieber.com/rc/nml">
.CW
nml.
.R
.ihtml a

Your mileage may vary.

.FG 9mlmgr png

.html - <a name="7.8" />
.ihtml h2 <h2>
.SH
7.8 - Web server configuration and maintenance
.R
.ihtml h2

If you must.

.html - <a name="7.8.1" />
.ihtml h3 <h3>
.SH
7.8.1 - ip/httpd
.R
.ihtml h3

No.

.html - <a name="7.8.2" />
.ihtml h3 <h3>
.SH
7.8.2 - rc-httpd
.R
.ihtml h3

The
.CW rc-httpd
web server is a simple shell script that handles static files, directory listings and drop-in CGI programs such as the
.ihtml a <a href="http://werc.cat-v.org">
werc anti-framework.
.ihtml a
.CW rc-httpd
is run from a file in the directory scanned by
.ihtml a <a href="http://man.9front.org/8/listen">
.CW listen(8) ,
.ihtml a
or called as an argument to
.ihtml a <a href="http://man.9front.org/8/listen">
.CW listen1(8) .
.ihtml a

Read:
.ihtml a <a href="http://man.9front.org/8/rc-httpd">
.CW rc-httpd(8)
.ihtml a

.B Note:
.CW rc-httpd
is employed to serve the
.ihtml a <a href="http://9front.org">
.CW 9front.org
.ihtml a
family of websites.
.bp
.html - <a name="7.9" />
.ihtml h2 <h2>
.SH
7.9 - TLS certificates
.R
.ihtml h2

.FG openssl1 png

To use TLS-enabled services on a Plan 9 mail server (poptls, apoptls, imaps, etc.) you need to generate a certificate and key for your mail server and tell the
.CW factotum
of the server about that key. The following example creates a self-signed certificate:
.P1
ramfs -p
cd /tmp
auth/rsagen -t \'service=tls role=client owner=*\' > key
chmod 600 key
cp key /sys/lib/tls/key # or: store key in secstore
auth/rsa2x509 \'C=US CN=fakedom.dom\' /sys/lib/tls/key | \e
	auth/pemencode CERTIFICATE > /sys/lib/tls/cert
.P2
.B Note:
Here, 
.CW US
is the two-digit country code, and
.CW fakedom.dom
is the fully qualified domain name.

To load the key into the server's
.CW factotum
at boot time, add the following line to
.CW /cfg/$sysname/cpustart :
.P1
cat /sys/lib/tls/key >>/mnt/factotum/ctl
.P2

Read:
.ihtml a <a href="http://man.9front.org/8/rsa">
.CW rsa(8)
.ihtml a

.html - <hr />
.html - <a href="fqa.html">FQA INDEX</a> |
.html - <a href="fqa6.html">FQA 6 - Networking</a> |
.html - <a href="fqa8.html">FQA 8 - Using 9front</a>