sshd(8) has a very nice feature that is often
overlooked. That feature is the ability to allow a ssh user to run a specified
command and nothing else, not even a login shell.
This is really easy to use and the magic happens in the file
authorized_keys which can be used to restrict commands per public key.
For example, if you want to allow someone to run the “uptime” command on your
server, you can create a user account for that person, with no password so the
password login will be disabled, and add his/her ssh public key in
~/.ssh/authorized_keys of that new user, with the following content.
restrict,command="/usr/bin/uptime" ssh-rsa the_key_content_here
The user will not be able to log-in, and doing the command ssh remoteserver
will return the output of uptime
. There is no way to escape this.
While running uptime is not really helpful, this can be used for a much more
interesting use case, like allowing remote users to use vmctl without
giving a shell account. The vmctl command requires parameters, the configuration
will be slightly different.
restrict,pty,command="/usr/sbin/vmctl $SSH_ORIGINAL_COMMAND" ssh-rsa the_key_content_here"
The variable SSH_ORIGINAL_COMMAND contains the value of what is passed as
parameter to ssh. The pty keyword also make an appearance, that will be
explained later.
If the user connects to ssh, vmctl with no parameter will be output.
$ ssh remotehost
usage: vmctl [-v] command [arg ...]
vmctl console id
vmctl create "path" [-b base] [-i disk] [-s size]
vmctl load "path"
vmctl log [verbose|brief]
vmctl reload
vmctl reset [all|vms|switches]
vmctl show [id]
vmctl start "name" [-Lc] [-b image] [-r image] [-m size]
[-n switch] [-i count] [-d disk]* [-t name]
vmctl status [id]
vmctl stop [id|-a] [-fw]
vmctl pause id
vmctl unpause id
vmctl send id
vmctl receive id
If you pass parameters to ssh, it will be passed to vmctl.
$ ssh remotehost show
ID PID VCPUS MAXMEM CURMEM TTY OWNER NAME
1 - 1 1.0G - - solene test
$ ssh remotehost start test
vmctl: started vm 1 successfully, tty /dev/ttyp9
$ ssh -t remotehost console test
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?
The ssh connections become a call to vmctl and ssh parameters become vmctl
parameters.
Note that in the last example, I use “ssh -t”, this is so to force allocation
of a pseudo tty device. This is required for vmctl console to get a fully
working console. The keyword restrict does not allow pty allocation, that
is why we have to add pty after restrict, to allow it.
In this article I will present you the rcs
tools and we will use it for versioning files in /etc to track changes between
editions. These tools are part of the OpenBSD base install.
Prerequisites
You need to create a RCS
folder where your files are, so the files
versions will be saved in it. I will use /etc in the examples, you
can adapt to your needs.
# cd /etc
# mkdir RCS
The following examples use the command ci -u
. This will be explained
later why so.
Tracking a file
We need to add a file to the RCS directory so we can track its
revisions. Each time we will proceed, we will create a new revision
of the file which contain the whole file at that point of time. This
will allow us to see changes between revisions, and the date of each
revision (and some others informations).
I really recommend to track the files you edit in your system, or even
configuration file in your user directory.
In next example, we will create the first revision of our file with
ci, and we will have to write some message about
it, like what is doing that file. Once we write the message, we need to
validate with a single dot on the line.
# cd /etc
# ci -u fstab
fstab,v <-- fstab
enter description, terminated with single '.' or end of file:
NOTE: This is NOT the log message!
>> this is the /etc/fstab file
>> .
initial revision: 1.1
done
Editing a file
The process of edition has multiples steps, using
ci and co:
- checkout the file and lock it, this will make the file available
for writing and will prevent using
co
on it again (due to lock)
- edit the file
- commit the new file + checkout
When using ci
to store the new revision, we need to write a small
message, try to use something clear and short. The log messages can be
seen in the file history, that should help you to know which change
has been made and why. The full process is done in the following
example.
# co -l fstab
RCS/fstab,v --> fstab
revision 1.1 (locked)
done
# echo "something wrong" >> fstab
# ci -u fstab
RCS/fstab,v <-- fstab
new revision: 1.4; previous revision: 1.3
enter log message, terminated with a single '.' or end of file:
>> I added a mistake on purpose!
>> .
revision 1.4 (unlocked)
done
View changes since last version
Using previous example, we will use rcsdiff
to check the changes since the last version.
# co -l fstab
RCS/fstab,v --> fstab
revision 1.1 (locked)
done
# echo "something wrong" >> fstab
# rcsdiff -u fstab
--- fstab 2018/10/28 14:28:29 1.1
+++ fstab 2018/10/28 14:30:41
@@ -9,3 +9,4 @@
52fdd1ce48744600.j /usr/src ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.e /var ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.m /data ffs rw,dev,wxallowed,nosuid 1 2
+something wrong
The -u
flag is so to produce an unified diff, which I find easier to
read. Lines with +
shows additions, and lines with -
show
deletions (there are none in the example).
Use of ci -u
The examples were using ci -u
this is because, if you use ci
some_file
, the file will be saved in the RCS folder but will be
missing in its place. You should use co some_file
to get it back (in
read-only).
# co -l fstab
RCS/fstab,v --> fstab
revision 1.1 (locked)
done
# echo "something wrong" >> fstab
# ci -u fstab
RCS/fstab,v <-- fstab
new revision: 1.4; previous revision: 1.3
enter log message, terminated with a single '.' or end of file:
>> I added a mistake on purpose!
>> .
done
# ls fstab
ls: fstab: No such file or directory
# co fstab
RCS/fstab,v --> fstab
revision 1.5
done
# ls fstab
fstab
Using ci -u
is very convenient because it prevent the user to forget
to checkout the file after commiting the changes.
Show existing revisions of a file
# rlog fstab
RCS file: RCS/fstab,v
Working file: fstab
head: 1.2
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 2; selected revisions: 2
description:
new file
----------------------------
revision 1.2
date: 2018/10/28 14:45:34; author: solene; state: Exp; lines: +1 -0;
Adding a disk
----------------------------
revision 1.1
date: 2018/10/28 14:45:18; author: solene; state: Exp;
Initial revision
=============================================================================
We have revisions 1.1 and 1.2, if we want to display the file in its
1.1 revision, we can use the following command:
# co -p1.1 fstab
RCS/fstab,v --> standard output
revision 1.1
52fdd1ce48744600.b none swap sw
52fdd1ce48744600.a / ffs rw 1 1
52fdd1ce48744600.l /home ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.d /tmp ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.f /usr ffs rw,nodev 1 2
52fdd1ce48744600.g /usr/X11R6 ffs rw,nodev 1 2
52fdd1ce48744600.h /usr/local ffs rw,wxallowed,nodev 1 2
52fdd1ce48744600.k /usr/obj ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.j /usr/src ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.e /var ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.m /data ffs rw,dev,wxallowed,nosuid 1 2
done
Note that there is no space between the flag and the revision! This
is required.
We can see that the command did output some extra informations about
the file and “done” at the end of the file. Thoses extra
informations are sent to stderr while the actual file content is sent
to stdout. That mean if we redirect stdout to a file, we will get the
file content.
# co -p1.1 fstab > a_file
RCS/fstab,v --> standard output
revision 1.1
done
# cat a_file
52fdd1ce48744600.b none swap sw
52fdd1ce48744600.a / ffs rw 1 1
52fdd1ce48744600.l /home ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.d /tmp ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.f /usr ffs rw,nodev 1 2
52fdd1ce48744600.g /usr/X11R6 ffs rw,nodev 1 2
52fdd1ce48744600.h /usr/local ffs rw,wxallowed,nodev 1 2
52fdd1ce48744600.k /usr/obj ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.j /usr/src ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.e /var ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.m /data ffs rw,dev,wxallowed,nosuid 1 2
Show a diff of a file since a revision
We can use rcsdiff using -r flag to tell it to show the
changes between last and one specific revision.
# rcsdiff -u -r1.1 fstab
--- fstab 2018/10/29 14:45:18 1.1
+++ fstab 2018/10/29 14:45:34
@@ -9,3 +9,4 @@
52fdd1ce48744600.j /usr/src ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.e /var ffs rw,nodev,nosuid 1 2
52fdd1ce48744600.m /data ffs rw,dev,wxallowed,nosuid 1 2
+something wrong
With the new OpenSMTPD syntax change which landed with OpenBSD 6.4
release, changes are needed for making opensmtpd to act as a lan relay
to a smtp server. This case wasn’t covered in my previous article
about opensmtpd, I was only writing about relaying from the local
machine, not for a network. Mike (a reader of the blog) shared that it
would be nice to have an article about it. Here it is! :)
A simple configuration would look like the following:
listen on em0
listen on lo0
table aliases db:/etc/mail/aliases.db
table secrets db:/etc/mail/secrets.db
action "local" mbox alias <aliases>
action "relay" relay host smtps://myrelay@remote-smtpd.tld auth <secrets>
match for local action "local"
match from local for any action "relay"
match from src 192.168.1.0/24 for action relay
The daemon will listen on em0 interface, and mail delivered from the
network will be relayed to remote-smtpd.tld.
For a relay using authentication, the login and passwords must be
defined in the file /etc/mail/secrets like this: myrelay
login:Pa$$W0rd
smtpd.conf(5) explains creation
of /etc/mail/secrets like this:
touch /etc/mail/secrets
chmod 640 /etc/mail/secrets
chown root:_smtpd /etc/mail/secrets
If you are using opensmtpd on a device not
always connected on the internet, you may want to see what mail did not go, and
force it to be delivered NOW when you are finally connected to the
Internet.
We can use smtpctl to show the current queue.
$ doas smtpctl show queue
1de69809e7a84423|local|mta|auth|so@tld|dest@tld|dest@tld|1540362112|1540362112|0|2|pending|406|No MX found for domain
The previous command will report nothing if the queue is empty.
In the previous output, we see that there is one mail from me to
dest@tld which is pending due to “NO MX found for domain” (which is
normal as I had no internet when I sent the mail).
We need to extract the first field, which is 1de69809e7a84423 in the
current example.
In order to tell opensmtpd to deliver it now, we will use the
following command:
$ doas smtpctl schedule 1de69809e7a84423
1 envelope scheduled
$ doas smtpctl show queue
My mail was delivered, it’s not in the queue anymore.
If you wish to deliver all enveloppes in the queue, this is as simple as:
$ doas smtpctl schedule all
The default OpenBSD partition layout uses a pre-defined template. If
you have a disk more than 356 GB you will have unused space with the
default layout (346 GB before 6.4).
It’s possible to create a new partition to use that space if you did
not modify the default layout at installation. You only need to start
disklabel with flag -E* and type a to add a partition,
default will use all remaining space for the partition.
# disklabel -E sd0
Label editor (enter '?' for help at any prompt)
> a
partition: [m]
offset: [741349952]
size: [258863586]
FS type: [4.2BSD]
> w
> q
No label changes.
The new partition here is m. We can format it with:
# newfs /dev/rsd0m
Then, you should add it to your /etc/fstab, for that, use the same
uuid as for other partitions, it would look something like
52fdd1ce48744600
52fdd1ce48744600.e /data ffs rw,nodev,nosuid 1 2
It will be auto mounted at boot, you only need to create the folder
/data. Now you can do
# mkdir /data
# mount /data
and /data is usable right now.
You can read disklabel(8) and
newfs for more informations.
Simple command line to display your installed packages listed by size
from smallest to biggest.
$ pkg_info -sa | paste - - - - | sort -n -k 5
Thanks to sthen@ for the command, I was previously using one involving
awk which was less readable. paste is often forgotten, it has very
specifics uses which can’t be mimic easily with other tools, its
purpose is to joins multiples lines into one with some specific rules.
You can easily modify the output to convert the size from bytes to
megabytes with awk:
$ pkg_info -sa | paste - - - - | sort -n -k 5 | awk '{ NF=$NF/1024/1024 ; print }'
This divides the last element (using space separator) of each line
twice by 1024 and displays the line.
Today I will write about my blog itself. While I started it as my own
documentation for some specific things I always forget about (like
“How to add a route through a specific interface on FreeBSD”) or to
publish my dot files, I enjoyed it and wanted to share about some
specific topics.
Then I started the “port of the week” things, but as time goes, I find
less of those software and so I don’t have anything to write
about. Then, as I run multiples servers, sometimes when I feel that
the way I did something is clean and useful, I share it here, as it is
a reminder for me I also write it to be helpful for others.
Doing things right is time consuming, but I always want to deliver a
polished write. In my opinion, doing things right includes the
following:
- explain why something is needed
- explain code examples
- give hints about potential traps
- where to look for official documentation
- provide environment informations like the operating system version
used at the writing time
- make the reader to think and get inspired instead of providing a
material ready to be copy / pasted brainlessly
I try to keep as much as possible close to those guidelines. I even
update from time to time my previous articles to check it still works
on the latest operating system version, so the content is still
relevant. And until it’s not updated, having the system version let
the reader think about “oh, it may have changed” (or not, but it
becomes the reader problem).
Now, I want to share about some OpenBSD specifics features, in a way
to highlight features. In OpenBSD everything is documented
correctly, but as a Human, one can’t read and understand every man
page to know what is possible. Here come the highlighting articles,
trying to show features, how to use it and where they are documented.
I hope you, reader, like what I write. I am writing here since two
years and I still like it.
Following a discussion on the OpenBSD mailing list misc, today I
will write about how to manage the priority (as in nice priority) of
your daemons or services.
In man page rc(8), one can read:
Before init(8) starts rc, it sets the process priority, umask, and
resource limits according to the “daemon” login class as described in
login.conf(5). It then starts rc and attempts to execute the sequence of
commands therein.
Using /etc/login.conf we can manage some limits for services and
daemon, using their rc script name.
For example, to make jenkins at lowest priority (so it doesn’t
make troubles if it builds), using this line will set it to nice 20.
jenkins:priority=20
If you have a file /etc/login.conf.db you have to update it from
/etc/login.conf using the software cap_mkdb
. This creates a
hashed database for faster information retrieval when this file is
big. By default, that file doesn’t exist and you don’t have to run
cap_mkdb
. See login.conf(5) for
more informations.
In this article I will show how to configure OpenSMTPD, the default mail server
on OpenBSD, to relay mail sent locally to your smtp server. In pratice, this
allows to send mail through “localhost” by the right relay, so it makes also
possible to send mail even if your computer isn’t connected to the internet.
Once connected, opensmtpd will send the mails.
All you need to understand the configuration and write your own one is in the
man page smtpd.conf(5). This is only a
highlight on was it possible and how to achieve it.
In OpenBSD 6.4 release, the configuration of opensmtpd changed drasticaly, now
you have to defines rules and action to do when a mail match the rules, and you
have to define those actions.
In the following example, we will see two kinds of relay, the first is through
smtp over the Internet, it’s the most likely you will want to setup. And the
other one is how to relay to a remote server not allowing relaying from
outside.
/etc/mail/smtpd.conf
table aliases file:/etc/mail/aliases
table secrets file:/etc/mail/secrets
listen on lo0
action "local" mbox alias <aliases>
action "relay" relay
action "myserver" relay host smtps://myrelay@perso.pw auth <secrets>
action "openbsd" relay host localhost:2525
match mail-from "@perso.pw" for any action "myserver"
match mail-from "@openbsd.org" for any action "openbsd"
match for local action "local"
match for any action "relay"
I defined 2 actions, one from “myserver”, it has a label “myrelay” and we use
auth <secrets>
to tell opensmtpd it needs authentication.
The other action is “openbsd”, it will only relay to localhost on port 2525.
To use them, I define 2 matching rules of the very same kind. If the mail that
I want to send match the @domain-name, then choose relay “myserver” or
“openbsd”.
The “openbsd” relay is only available when I create a SSH tunnel, binding the
local port 25 of the remote server to my port 2525, with flags
-L 2525:127.0.0.1:25
.
For a relay using authentication, the login and passwords must be defined in
the file /etc/mail/secrets like this: myrelay login:Pa$$W0rd
smtpd.conf(5) explains creation
of /etc/mail/secrets like this:
touch /etc/mail/secrets
chmod 640 /etc/mail/secrets
chown root:_smtpd /etc/mail/secrets
Now, restarts your server. Then if you need to send mails, just use “mail”
command or localhost as a smtp server. Depending on your From address, a
different relay will be used.
Deliveries can be checked in /var/log/maillog log file.
See mails in queue
doas smtpctl show queue
Try to deliver now
doas smtpctl schedule all
Today I will cover a specific topic on OpenBSD networking. If you are using a
laptop, you may switch from ethernet to wireless network from time to time.
There is a simple way to keep the network instead of having to disconnect /
reconnect everytime.
It’s possible to aggregate your wireless and ethernet devices into one trunk
pseudo device in failover mode, which give ethernet the priority if connected.
To achieve this, it’s quite simple. If you have devices em0 and iwm0
create the following files.
/etc/hostname.em0
up
/etc/hostname.iwm0
join "office_network" wpakey "mypassword"
join "my_home_network" wpakey "9charshere"
join "roaming phone" wpakey "something"
join "Public Wifi"
up
/etc/hostname.trunk0
trunkproto failover trunkport em0 trunkport iwm0
dhcp
As you can see in the wireless device configuration we can specify multiples
network to join, it is a new feature that will be available from 6.4 release.
You can enable the new configuration by running sh /etc/netstart
as root.
This setup is explained in trunk(4)
man page and in the
OpenBSD FAQ as well.