Typefaces for Terminal and text editing

Many users on Twitter pointed out a new typeface designed for terminals and text editors called Hack. It looks nice but I thought I’d make a list of other useful open source typefaces:

  • Source Code Pro from Adobe is designed for code editing. This is my favorite and I have set it in Terminal and BBEdit. It has many different weights, italics, and also related typefaces Source Sans Pro and Source Serif Pro in case you want proportional typefaces as well. These are regularly updated with minor improvements and new glyphs.

  • Courier Prime is an improvement on the standard Courier typeface. There are also sans serif and code versions available.

  • Hack is the new typeface which inspired this post. The characters seem much larger than similar fonts at the same point size, but according to the page that is intentional.

Hack will be nice to have around, but for now Source Code Pro remains my favorite.

(If you, like me, are curious when to use ‘typeface’ vs ‘font’ then read this helpful article.)

Mount a dmg off a web server

I saw this project by Douglas Nerad which stream lines the bootstrapping installation of Munki, so that you can do it while booted from the Recovery partition. This is useful to inject munkitools on a new Mac without having to go through setting up a user.

The read me recommends to put the script and other resources on a USB key, which works fine, as long you have only one USB key. If you have to share this tool among multiple admins keeping the keys up to date (and in your pocket) can be a pain.

If you put all the resources and the script in an dmg file on a web server, you can run

hdiutil attach http://webserver/path/to/InstallThis.dmg

and then run scripts and installer pkgs from the attached volume.

installer -pkg /Volumes/InstallThis/munkitools2-latest.pkg
/Volumes/InstallThis/setupEverything.sh

Note that you cannot run python scripts from the Recovery partition. It is best to use shell or bash scripts.

Check Python Syntax in BBEdit with flake8

There are existing scripts out there that will run flake8 against a python file in BBEdit, but none of them worked quite the way I wanted. So here is mine:

Before you can run this, you need to install flake with sudo easy_install flake8. Then you need to drop this script in ~/Library/Application Support/BBEdit/Scripts. You can launch it from the menu with the script icon.

On Internet Shortcut Files

If you are managing Macs and PCs, then you will frequently connect to other computers or virtual machines through screen sharing, secure shell or other means. Here is a simple trick to make those connections easier:

Open your favored UI text editor (Text Edit will do) and type

vnc://<username>@<hostname>

Replace <username> and <hostname> with your username and hostname for a Mac you frequently share the screen with.

Then select the entire text and drag it to the desktop. It will create a file with “@” sign on the icon. When you double click this file, Screen Sharing opens and asks for the password (unless it is stored in the Keychain) and connects the remote session.

Now rename this file to VNC <hostname>. Then activate Spotlight (cmd-space) and start typing “VNC” and the hostname. After a few characters the VNC link file should be the top result. Hit return and the session starts.

As an extra bonus you can put these files in a folder in your cloud file system of choice (iCloud Drive, Dropbox, Google Drive, Box, etc.) and they will sync to all your Macs.

Other Protocols

You can do the same with any URI scheme:

ssh://<username>@<hostname>:<port>

afp://<username>@<hostname>/<share>

smb://<username>@<hostname>/<share>

http://<hostname/<path>

Microsoft Remote Desktop/RDP

The new Microsoft Remote Desktop application available in the Mac App Store also supports rdp URI schemes, however the syntax is a bit odd. To connect to a remote host you have to use:

rdp://full%20address=s:<hostname>&username=s:<username>

You can find more options for this URI scheme in this technote. One I have found useful is screen mode id where a value of 1 means to open the remote screen in a window a value of 2 means full screen mode.

Looking into the files

If inspect the file generated by dragging, you can see that it is a property list file with a single key URL and a string value containing the link.

Files for a vnc URI get the .vncloc extension, http[s] URIs get the .webloc extension, ftp URIs get the .ftploc extension and everything else seems to get .inetloc extensions. (There may be more, let me know if you find any.)

This makes it easy to write a short script that simplifies the creation of these internet location files:

Sample use:

./create_netloc.py vnc://user@host.example.com

will create VNC host.vncloc

./create_netloc.py http://munki.example.com/munkireport-php/ Munkireport

will create Munkireport.webloc

./create_netloc.py "rdp://full%20address=s:host.example.com&username=s:name&screen%20mode%20id=i:1"

will create RDP host.inetloc

Note on rdp links: since the ‘&’ is special in shell commands you need to quote the uri if any are present.

Fun with find and git

find ~ -type d -name .git -exec dirname {} \;

will show you all folders in your home directory which have a .git subfolder — i.e. they are git repositories.

This is useful, but can be extended to:

find ~ -type d -name .git -exec dirname {} \; | tr '\n' '\000' | xargs -0 -n1 -I % git -C "%" status

to show the git status output of all your git repositories.

Time to clean up!

Control ssh access with munki nopkg scripts

Often you want to control settings on client machine with scripts rather than packages. One such example is controlling ssh acces, aka ‘Remote Login’ in the OS X UI.

Note: please consider supporting the author of this site by purchasing one of my books! Thank you!

Having ssh access to the clients allows for remote access for trouble shooting and analysis. You can also remotely start or stop processes, like initiating managedsoftwareupdate right now instead of waiting.

However, since there is potential to abuse ssh, we should restrict ssh access to a subset of users. The OS X UI allows you restrict ssh access to a list of users or groups. In our example we will enable Remote Login and give access to any user with administrative privileges, i.e. the admin group.

You could write the scripts to enable these settings and put them in a so called “payload free package.” However, Munki has a simpler and more flexible way of handling this. Ironically, you create a pkginfo file with the nopkg setting.

Building the Install_Check script

Usually when you create the pkginfo for a package or dmg installation, Munki will analyze the files you give it and create conditions on which to install. If the dmg contains an application Firefox, it will look in /Applications for an application named Firefox and compare versions. If the application on the client is not present or of an older version, Munki will perform the installation.

For configurations other than files or applications, we can provide a script that runs and can tell Munki wether to perform the installation first. It might seem a little odd, but it makes a lot of sense to develop this install_check script first.

We need to check wether

  • Remote Login/ssh is enabled
  • access is not set to ‘All Users’
  • the admin user group is allowed access

Open your favorite text editor and create a new script called ssh_install_check.sh and start typing:

#!/bin/bash

PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki export PATH

# this will run as a munki install_check script
# exit status of 0 means install needs to run
# exit status not 0 means no installation necessary

So if the script runs and returns 0 as the exit code, Munki will perform the installation. If the script returns any non-zero code, then Munki will assume everything is alright and not perform the installation.

First thing we want to test for is wether Remote Login/ssh is enabled. The CLI tool systemsetup has a command for that:

systemsetup -getremotelogin

Will return Remote Login: On/Off depending on the status. Testing for this is easy enough. Add these lines to the script:

# Is SSH enabled
if [[ $(systemsetup -getremotelogin) = 'Remote Login: Off' ]]; then
    echo 'Remote login is off!'
    exit 0
fi

You can save and test the script on your Mac right now. Use the UI in System Preferences > Sharing to toggle Remote Login and see what the script returns.

Next we want to test wether the access is set to ‘All Users’. There is a group called com.apple.access_ssh on your Mac that contains the users which are allowed ssh access. However, if the access is set to ‘All Users’ the OS renames this group to com.apple.access_ssh-disabled. Add these lines to the script:

ssh_group="com.apple.access_ssh"

# Does a group named "com.apple.access_ssh" exist?
if [[ $(dscl /Local/Default list /Groups | grep "${ssh_group}-disabled" | wc -l) -eq 1 ]]; then
    echo "access set to 'All Users'"
    exit 0
elif [[ $(dscl /Local/Default list /Groups | grep "$ssh_group" | wc -l) -eq 0 ]]; then
    echo "no group '$ssh_group'"
    exit 0
fi

First we defined a variable with the name ofthe group test for, this saves a lot of typing, reduces errors and makes the code more re-usable incase you want to use this for other control groups as well.

Then we run dscl /Local/Default list Groups and grep for the names to see if these groups exist. Then we do the same again in case the group does not exist at all (it really should, but it cannot hurt to test).

You can save and run the script to test again. Switch from ‘All Users’ to ‘Only these users’ in the UI. and see the results of the script.

Finally we want to test wether the admin group is allowed for ssh. We need to see if the group ‘admin’ is contained in the access_ssh group. This is a bit harder than it sounds. We can list nested groups using dscl /Local/Default read Groups/com.apple.access_ssh NestedGroups, but this will list long UUID strings, not the names of the groups.

To get the UUID of the admin we can use dsmemberutil getuuid -G admin. and then rest is easy. Add these lines to your script:

# does the group contain the admin group?
admin_uuid=$(dsmemberutil getuuid -G admin)
if [[ $(dscl /Local/Default read Groups/com.apple.access_ssh NestedGroups | grep "$admin_uuid" | wc -l) -eq 0 ]]; then
    echo 'admin group not nested in $ssh_group!'
    exit 0
fi

Sidenote 1: this will only test wether the admin group is directly nested in the access_ssh group. You could have another group in the access_ssh group, which itself contains the admin group. So the admin group would have the privilege to use ssh, but this script would still fail. You could also have all members of the admin group listed directly in the access_ssh group, and the script would not check for that. Either way the script will fail and cause Munki to add the admin group (we will learn how later) and it wouldn’t change access, so we are ok with this somewhat superficial test.
Sidenote 2: this script will also ignore other groups or users in the access_ssh group. If you wanted to enforce stricter access policies, you might want to test wether admin is the only group nested in access_ssh.

Finally the script should return a non-zero value when all the tests are passed. Our final script will look like this (cleaning it up a bit):

#!/bin/bash

PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki export PATH

# this will run as a munki install_check script
# exit status of 0 means install needs to run
# exit status not 0 means no installation necessary

ssh_group="com.apple.access_ssh"

# Is SSH enabled
if [[ $(systemsetup -getremotelogin) = 'Remote Login: Off' ]]; then
    echo 'Remote login is off!'
    exit 0
fi

# Does a group named "com.apple.access_ssh" exist?
if [[ $(dscl /Local/Default list /Groups | grep "${ssh_group}-disabled" | wc -l) -eq 1 ]]; then
    echo "access set to 'All Users'"
    exit 0
elif [[ $(dscl /Local/Default list /Groups | grep "$ssh_group" | wc -l) -eq 0 ]]; then
    echo "no group '$ssh_group'"
    exit 0
fi

# does the group contain the admin group?
admin_uuid=$(dsmemberutil getuuid -G admin)
if [[ $(dscl /Local/Default read Groups/com.apple.access_ssh NestedGroups | grep "$admin_uuid" | wc -l) -eq 0 ]]; then
    echo 'admin group not nested in $ssh_group!'
    exit 0
fi

echo "everything seems as it should be, no install needed"
exit 1

Building the postinstall_script

Now that we have a script that tests wether we need to change settings, we can start building the actual script to do the changes. The good news is that while writing the install_check script we already built the outline for the actual install script. We use the same same tests, but instead of merely reporting and exiting, we now perform the necessary change:

#!/bin/bash

PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki export PATH

ssh_group="com.apple.access_ssh"

# enable ssh
if [[ $(systemsetup -getremotelogin) = 'Remote Login: Off' ]]; then
    echo "turning on Remote Login/SSH"
    systemsetup -setremotelogin On
fi

# Does a group named "com.apple.access_ssh" exist?
if [[ $(dscl /Local/Default list /Groups | grep "${ssh_group}-disabled" | wc -l) -eq 1 ]]; then
    #rename this group
    echo "renaming group '${ssh_group}-disabled'"
    dscl localhost change /Local/Default/Groups/${ssh_group}-disabled RecordName ${ssh_group}-disabled $ssh_group
elif [[ $(dscl /Local/Default list /Groups | grep "$ssh_group" | wc -l) -eq 0 ]]; then
    # create group
    echo "creating group $ssh_group"
    dseditgroup -o create -n "/Local/Default" -r "Remote Login Group" -T group $ssh_group
fi

# does the group contain the admin group?
admin_uuid=$(dsmemberutil getuuid -G admin)
if [[ $(dscl /Local/Default read Groups/$ssh_group NestedGroups | grep "$admin_uuid" | wc -l) -eq 0 ]]; then
    echo "adding admin group to $ssh_group"
    dseditgroup -o edit -n "/Local/Default" -a admin -t group $ssh_group
fi

exit 0

Note that we use dseditgroup instead of manipulating the NestedGroup property with dscl. This is the official and safe way to manipulate groups in OS X.

Save this as ssh_postinstall.sh. Open the Remote Login Sharing UI in System Preferences > Sharing, change the settings and then run this script. To see the changes from the script reflected in the Preference you have to quit and restart System Preferences.

Building the pkginfo file

Now we that we have a script to test and another to change the settings we have to build a pkginfo file that will explain all of this to Munki. Let’s use makepkginfo to get us started:

makepkginfo --name EnableSSH --nopkg --pkgvers=1.0 --installcheck_script=ssh_install_check.sh --postinstall_script=ssh_postinstall.sh --unattended_install > enableSSH.pkginfo

--nopkg sets the install_type and tells Munki that this item has no pkg or dmg file associated with it. The two scripts we built are included in the plist. Munki will read this pkginfo and execute the code when necessary.

You can change or add some more keys (such as description or displayname) and then copy the file to your Munki repository and run makecatalogs. Then add EnableSSH to a manifest on your test machine(s) and run Managed Software Update on it. EnableSSH should appear and run the postinstall script. Check wether SSH works now.

Further, you can go in the UI and change some setting for Remote login, then run Managed Software Update again (or logout to make it run). Notice how our scripts detect that the settings changed from what they are supposed to be and re-ran our postinstall script to re-set them.

more options

You could add a third script to the pkginfo to ‘uninstall’ the settings. That way you could revert your settings to the default. There is even an option for a uninstallcheck_script that will check wether Munki should uninstall your settings.

Summary

The nopkg option allows us to run scripts with Munki, without need to bundle a pkg or dmg payload. Using an installcheck_script allows us to give Munki very precise instructions on when to run the script and repeatedly enforce configurations.