Jun 122018
 

This posting is about using the command-line ssh tool for relatively securely copying stuff around, and logging into devices. Many of the tips contained within are things I have had to pry out of the manual page for my own use and these notes are a way of keeping the information around without relying on my brain.

#1: It Comes With Windows

If you are running the latest version of Windows 10, you get the command-line versions of ssh and scp without dropping into the Linux shell :-

Of course you have been able to install ssh clients for Windows for years or even decades, but having it available by default is a big win. Particularly for Windows machines you don’t tweak with your favourite applications.

#2: Public/Private Key Authentication

This the first part of increasing security by only permitting key authentication so that password brute forcing attacks become impossible. With the assistance of an ssh agent (not covered here) or a passphrase-less key pair (not advisable), it is no longer necessary to enter a password.

Of course getting into this sort of thing can be very confusing especially as most instructions tend to get into far too much detail on the cryptography involved. To keep it simple, I shall avoid going on about the cryptography, and concentrate on how to get it to work.

The most important thing to remember about key authentication is that there are two keys – the private key (which should be kept as secure as possible on the client machine) and the public key (which is copied to the devices you want to connect to).

So to get started, you first need to generate a key pair, which can be done with ssh-keygen; this has lots of options, but at this point you can ignore them. After you enter the command, you can simply hit return at all the prompts to generate a key pair :-

Generating public/private rsa key pair.
Enter file in which to save the key (/home/mike/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/mike/.ssh/id_rsa.
Your public key has been saved in /home/mike/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:REMOVED mike@Michelin
The key's randomart image is:
+---[RSA 2048]----+
|=*+o ..  .B*..=o |
|o+++.  . =+o. o+.|
|.BE.+   + .  =  .|
|o+=& . . .    o  |
|. o +   S    .   |
|     .           |
|    SS           |
|              .  |
|     --          |
+----[SHA256]-----+

Of course this is not ideal because there is no passphrase, but to get started with that’s fine. You can ignore most of this output (except for the first item in the following list) but just in case :-

  1. The key pair is saved in the files ~/.ssh/id_rsa (the private key) and ~/.ssh/id_rsa.pub (the public key). The permissions are usually generated properly, but just to be safe you may want to reset the permissions anyway: chmod 0400 ~/.ssh ~/.ssh/id_rsa; chmod u+x ~/.ssh
  2. The key fingerprint can be used to check that when you are connecting that the keys haven’t changed unexpectedly.
  3. Alternatively (and slightly more of a reasonable check) you can check the fingerprint using the “randoart”.

Of course on its own, it doesn’t do much good. You have to copy it into place onto the machine you wish to authenticate to :-

$ ssh username@server mkdir .ssh
$ cat ~/.ssh/id_rsa.pub | ssh username@server cat ">>" .ssh/authorized_keys

Note the quotes around the “>>”; these are significant because you do not want the local machine’s shell to interpret them – they need to be interpreted by the remote machine’s shell. Normally I would simply “scp” the file into place, but appending to a supposedly non-existent file is safer – just in case it does exist and does contain public keys that are currently in use.

There are a whole bunch of options to the command, but the two most important ones are :-

  1. The -t option which is used to specify the key type to generate (dsa, rsa, ecdsa, and ed25519). This is mostly unnecessary, but some older and limited devices do not understand certain key types. And as time goes on, more key types will be declared “insecure”. So you may sometimes find the need to generate more secure keys. The simplest (but not very efficient) process for dealing with such situations is to generate a key for each key type and try each one in turn.
  2. The -f option which is used to specify the output filenames – the private key is saved under the name ‘filename’ and the public key under the name ‘filename.pub’.

#3: SSH Configuration File and Usernames

There are a ton of things that can be done with the ssh configuration file, but for this section I’ll stick with setting the username used to login to specific hosts – not because this is the most interesting thing that can be done, although it is quite useful.

The configuration file can be found (if it has been created) at ~/.ssh/config (with a system-wide version at /etc/ssh/ssh_config). Within that file, you can set global preferences, or host specific preferences :-

Username fred

Host router
  Username admin
Host dns*
  Username fxb
Host ds-* web-*
  Username baileyf
Host *
  Username fred

The first line (Username fred) instructs ssh to use the username ‘fred’ when no username is specified – ssh 192.168.77.98 effectively becomes ssh fred@192.168.77.87.

If you specify the same username within a Host section, the specified username is used for any hosts that the specification following the Host word. In the first case (“Host router”) the username “admin” will be used for any host called “router” but not “router.some.domain”.

In the case of the second clause, a wildcard is used which is very useful for specifying a range of hosts – the example can match “dns01”, “dns01.some.domain”, or even “dns02”. In fact the first Host section is an example of what you should not do – put in a single hostname without a wildcard because it will only activate if the hostname is specified exactly as given. Put a wildcard in there, and it will work whether you use a single hostname or use the fully qualified domain name.

You can also have more than one host specification – as in the “ds-* web-*” list.

And lastly you can (if you choose) use the Host declaration to specify a set of default values – in much the same way that configuration settings in the global context specify default values. Use whatever method you choose.

#4: Cryptographic Incompatibility

I have commented elsewhere on this, but basically the ssh developers have chosen to disable weak encryption by default. Personally I would prefer that ssh throw up huge warnings about weak cryptography, but what is done is done.

If you need to connect to something with weak cryptography, there are three potential ‘fixes’ to allow connections. Each of these is a keyword to add to a specific host section, followed by a specification of what ‘algorithm’ to add.

In each case, a connection attempt will give an indication of what is wrong together with an indication of what algorithm to include :-

» ssh admin@${someswitch}
Unable to negotiate with ${ip} port 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1

In this case, we can see that it is the KexAlgorithms we need to adjust and the algorithm we need to add is “diffie-hellman-group1-sha1” :-

Host someswitch*
  KexAlgorithms +diffie-hellman-group1-sha1

This can be repeated for Ciphers and (rarely) MACs.

#5: X11 and Port Forwarding

Run X11 gooey programs over an ssh connection? Of course .. why not?

This can be enabled on a host-by-host basis (it is off by default because it can be insecure) using the configuration file :-

Host pica*
  ForwardX11 yes

This is just a special case of port forwarding where a network port is connected (via the ssh session) to a remote network port. Port forwarding can be very useful – for example to access an internal web site temporarily that isn’t (and probably shouldn’t be) exposed with a hole through the firewall.

Of course this can be done with a VPN, but ssh may be simpler :-

Host pica*
  LocalForward 8000 8000

When the connection is made, a local port is opened (tcp/8000) and connected to tcp/8000 on the machine you are logging into.
 

Mar 292018
 

For some reason when I look at RADIUS packet captures using Wireshark, the attribute Operator_Name is instead interpreted as Multi-Link-Flag (an integer rather than a string). I’m not sure what this is, but it is much more useful to me to be able to see the Operator_Name properly – and for example, filter on it.

It turns out this is easy to “fix” (if it is a fix) :-

  1. Find the file radius/dictionary.usr (mine was /usr/share/wireshark/radius/dictionary.usr)
  2. Edit that file, and comment out three lines containing “Multi-Link-Flag” which in my case appeared like :-
    1. ATTRIBUTE Multi-Link-Flag 126 integer
    2. VALUE Multi-Link-Flag True 1
    3. VALUE Multi-Link-Flag False 0
  3. Save the modified file.

After a restart, Wireshark now understands it.

It is possible that later versions of Wireshark have fixed this, or not – it is possible that the bug is down to whoever assigned RADIUS attribute codes!

Feb 082018
 

Some time ago, I wrote about using new (for the time) partition tables to create a memory stick with 100 partitions; each with a mountable file system on. And decided the time was right to have another look to see if things have improved … or degraded. After all, things have moved on, and everything has been updated.

I also improved the creation script slightly :-

#!/bin/zsh

disk=/dev/sdb

parted $disk mklabel gpt
for x in {1..99}     
do
  echo Partition: $x
  parted -s $disk mkpart FAT $(($x * 100)) $((x * 100 + 99))
  sleep 0.2
  mkfs -t vfat -n DOOM${x} ${disk}${x} 
  sleep 0.2
done

And I used a zsh-ism – so shoot me.

The script ran fairly well, but :-

  1. The load average shot up through the roof as copies of systemd-udevd started, worked, and closed.
  2. Strangely the links in /dev/disk/by-label (and presumably elsewhere) kept disappearing and re-appearing. As if on each partition change to the disk, all of the disk’s devices were removed and re-created. This is probably not dangerous, but harmful to performance.
  3. Given that I used sleep within my script, it is hard to criticise performance, but it did seem slow. However this is not an area worth optimising for.
  4. Unlike last time, Linux did not refuse to create any file systems.

Now onto trying to stick the memory stick of doom into various systems…

Ubuntu 17.10

This was of course the machine I ran the script on initially.

This did not go so well, with the machine initially freezing momentarily (although it is a cheap and nasty laptop), apparently silently refusing to mount half the file systems, and “Files” (or Nautilus) getting wedged at 100% processor usage.

After some 10 minutes, Nautilus was still stuck with no signs of making any progress.

After I lost patience and restarted “Files”, it came up okay showing the mounted file systems and showing the file systems it had failed to mount. On one occasion the additional file systems were shown as unmounted (and could be mounted) and on another they were shown as mounted (even though they weren’t).

So both “Files” gets a thumb down for getting stuck, and whatever else gets a thumb down for trying and failing (silently) to mount all the file systems.

This is definitely a serious degradation from the previous try, although probably GNOME-specific rather than Linux-specific. Especially as a later mounted all the file systems from the command-line on a different system without an issue.

Windows 10

Windows 10 became unusually sluggish, although it may have been in the mysterious “we’ll run Windows update at the most inconvenient time possible” mode. It did attempt to mount the file systems, and failed miserably – it mounted the first set until it ran out of drive letters.

Which is just about understandable, as there aren’t 100 drive letters. However :-

  1. Where was the message saying “There are 100 partitions in this silly USB stick. You can see the first 22; additional ones can be mounted within folders if there is important data on them.”.
  2. Why is Windows still limiting itself with single letter device names? Okay it is what we’re used to, but when you run out of drive letters, start using the file system label – “DOOM99:”. Hell, I’d like all my removable disks treated that way under Windows.

As for the whole “ran out of drive letters, so don’t bother with the rest”, how many people are aware that drives can be mounted (as Unix does) in directories?

macOS 10.13 (OSX)

Oddly enough (but perhaps sensibly), macOS refused to have anything to do with the memory stick. Indeed it popped up a dialog suggesting initialising the disk, which is perhaps not particularly sensible with a disk that could contain data.

The “Disk Utility” happily showed the disk – increasing the size of the window inconveniently wide in the process – and happily indicated 99 partitions.

At the Terminal prompt, it was apparent that the operating system had created device files for each of the partitions, but for some reason wouldn’t mount them.

Summary

Inserting a “stick of doom” with 100 partitions on it into any machine is still a risky thing to do. It’s also a dumb thing to do, but something operating system developers should be doing.

Linux (or rather GNOME) performs significant worse this time around than previously, and my suspicions are that systemd is to blame.

But however bad Linux does, none of the operating systems actually do sensible things with the “stick of doom”. macOS arguably comes closest with refusing to have anything to do with the disk, but it also encourages you to reformat the disk without saying that it could be erasing data.

Ideally, a gooey would pop up a window listing the file system labels and ask you which you want to mount. That’s not even a bad idea for a more sensibly set up memory stick.

Pebble On Steel

Sep 202017
 

By default, the Awesome window manager sets up 9 tags and uses a rather clever method for setting keyboard shortcuts for those tags.

And that is also one of the irritations of using Awesome because I have gotten into the habit of using more virtual screens (“tags”) than this. After a dumb way of increasing the number, I have come up with a rather improved method that can be used to replace the existing method in the Awesome rc.lua file :-

local taglist = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=" }
-- The list of tags that I use.
…
 awful.tag( taglist, s, awful.layout.layouts[1])
…
for i = 1, #taglist do
  globalkeys = awful.util.table.join(globalkeys,
    awful.key({ modkey}, taglist[i],
                  function ()
                        local screen = awful.screen.focused()
                        local tag = screen.tags[i]
                        if tag then
                           tag:view_only()
                        end
                  end,
                  {description = "view tag", group = "tag"}),
        awful.key({ modkey, "Control" }, taglist[i],
                  function ()
                      local screen = awful.screen.focused()
                      local tag = screen.tags[i]
                      if tag then
                         awful.tag.viewtoggle(tag)
                      end
                  end,
                  {description = "toggle tag", group = "tag"}),
        awful.key({ modkey, "Shift" }, taglist[i],
                  function ()
                      if client.focus then
                          local tag = client.focus.screen.tags[i]
                          if tag then
                              client.focus:move_to_tag(tag)
                          end
                     end
                  end,
                  {description = "move focused client to tag", group = "tag"}),
        awful.key({ modkey, "Control", "Shift" }, taglist[i],
                  function ()
                      if client.focus then
                          local tag = client.focus.screen.tags[i]
                          if tag then
                              client.focus:toggle_tag(tag)
                          end
                      end
                  end,
                  {description = "toggle focused client on tag", group = "tag"})
    )
end

That’s three different parts of the code to change – a list of tags to use at the top of the file, a replacement somewhere in the middle, and a large chunk replacing existing code at the end of the keyboard configuration. I don’t claim this is better than the standard way, but it is handy for me.

The Window

May 202017
 

I just love messing around with run-time languages that I know relatively little about (and if your sarcasm detector isn’t flashing red about now, take it out and give it a good talking to).

The problem detailed here is something that you are unlikely to encounter unless you get into weird stuff like running an odd-ball window manager, aren’t content with the version of said window manager distributed with your Linux distribution, and are used to re-compiling things from scratch.

It all started when I upgraded Ubuntu on my work machine (to Zesty Zapus). The window manager version was upgraded from 3.5 to 4.0, which broke on my configuration file (3.5); not a big problem I thought, as I had already upgraded my window manager at home to 4.1 and reconfigured the configuration file. I copied the updated configuration file from home into place.

And it failed. Apparently I use 4.1-isms within the file. As I was not happy about tinkering with the file to downgrade it (in a language I know relatively little about), I decided to re-compile Awesome 4.1 instead.

Which failed with a weird error :-

» awesome --version
awesome v4.1 (Technologic)
 • Compiled against Lua 5.3.3 (running with Lua 5.3)
 • D-Bus support: ✔
 • execinfo support: ✔
 • xcb-randr version: 1.4
 • LGI version: [string "return require('lgi.version')"]:1: module 'lgi.version' not found:
	no field package.preload['lgi.version']
	no file '/usr/local/share/lua/5.3/lgi/version.lua'
	no file '/usr/local/share/lua/5.2/lgi/version.lua'
	no file '/usr/local/share/lua/5.3/lgi/version/init.lua'
	no file '/usr/local/share/lua/5.2/lgi/version/init.lua'
	no file '/usr/local/lib/lua/5.3/lgi/version.lua'
	no file '/usr/local/lib/lua/5.3/lgi/version/init.lua'
	no file '/usr/share/lua/5.3/lgi/version.lua'
	no file '/usr/share/lua/5.3/lgi/version/init.lua'
	no file './lgi/version.lua'
	no file './lgi/version/init.lua'
	no file '/usr/local/lib/lua/5.3/lgi/version.so'
	no file '/usr/lib/x86_64-linux-gnu/lua/5.3/lgi/version.so'
	no file '/usr/lib/lua/5.3/lgi/version.so'
	no file '/usr/local/lib/lua/5.3/loadall.so'
	no file './lgi/version.so'
	no file '/usr/local/lib/lua/5.3/lgi.so'
	no file '/usr/lib/x86_64-linux-gnu/lua/5.3/lgi.so'
	no file '/usr/lib/lua/5.3/lgi.so'
	no file '/usr/local/lib/lua/5.3/loadall.so'
	no file './lgi.so'

Which had me stumped for a while, and it turns out that DuckDuckGo didn’t have an obvious fix (one of the reasons for writing this).

Eventually I figured out that awesome was not finding the LGI module (I can be slow at times) which was odd because it was definitely installed. However it turns out that it was installed in /usr/share/lua/5.2/lgi. So despite having lua 5.3 installed, extra lua modules can only be seen if you have lua 5.2 installed?

The “fix” for this was to create an environment variable telling LUA to search for files in rather more places before starting Awesome :-

export LUA_PATH="/usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua;/usr/share/lua/5.3/?.lua;/usr/share/lua/5.2/?.lua;/usr/share/lua/5.3/?/init.lua;/usr/share/lua/5.2/?/init.lua;./?.lua;./?/init.lua"

This was created by running lua from the command line and running print(package.path) to display the default setting, and adding the 5.2 equivalent for many elements.

As to whether it works or not, well I cannot be sure (I’m not going into work on a weekend just to check if the window manager fires up), but Awesome itself seems happy with the result :-

» awesome --version
awesome v4.1 (Technologic)
 • Compiled against Lua 5.3.3 (running with Lua 5.3)
 • D-Bus support: ✔
 • execinfo support: ✔
 • xcb-randr version: 1.4
 • LGI version: 0.9.1

So it can find LGI, but whether it can do anything useful with it remains to be seen!