bennettp123

 

OS X Recovery shenanigans: sshd, ramdisks, and screenshots

The Problem:

You want to take screenshots during the OS X recovery process.

The Solution:

The screencapture command can be used to create screenshots from the Terminal.

(To launch the Terminal: hover the cursor at the top edge to show the menu bar, then select Utilities → Terminal).

Type the following:

screencapture -W /path/to/screenshot.png

then click the window you want to capture.

But wait— the recovery environment allows only one app to run at a time. If you want screenshots of Terminal, then this method works great. However, if you want screenshots of something else, you’re out of luck.

Fortunately, the recovery partition includes sshd. It’s not running by default, but starting it is easy:

/usr/sbin/sshd -o UsePAM=no

(The absolute path is required; if you leave it out, then sshd bails out with an error).

OK, but the root account has a random password. And you can’t reset it, since the filesystem is read-only.

New problem:

You want to ssh into recovery, but you can’t set the root account password.

The solution:

Pubkey authentication!

First, create a writeable ramdisk:

rdsize=$((16*1024*1024/512)) # 16 megabytes
dev=`hdik -drivekey system-image=yes -nomount "ram://$rdsize"`
echo $?; echo $dev # check for errors!
newfs_hfs "$dev"
eval `/usr/bin/stat -s /var/root` # store perms for old mountponit
mount -t hfs -o union -o nobrowse "$dev" /var/root # magic happens here
chown "$st_uid:$st_gid" /var/root
chmod "$st_mode" /var/root

Next, add your key to /var/root/.ssh/authorized_keys.

mkdir /var/root/.ssh
cat /Volumes/THUMBDRIVE/id_rsa.pub > /var/root/.ssh/authorized_keys

You can now use your private key to authenticate to sshd.

Quit Terminal, and the ssh sessions will remain connected. You can now use the screencapture command at any time!

A few notes:

You can create screenshots in /var/root, but the ramdisk is only 16 megabytes. If this is too small, increase the rdsize before creating the ramdisk.

Of course, since this is a ramdisk, all modifications will be lost upon reboot. You might want to save the screenshots to a USB device instead. (Or scp/sftp, etc).

Your ssh key should be located on the client machine at ~/.ssh/id_rsa.pub. If it’s not there, it can be created using ssh-keygen. (You might also see a file called id_rsa—that’s the private key; do not copy it).

I’m sure you can think of many other uses for ramdisks. :)

Sources:

Raspberry Pi won’t boot? Try this.

In /boot/config.txt:

initial_turbo=180

This disables dynamic overclocking for the first 180 seconds after boot. This should help devices to boot from a poor‑quality power supply.

My rasberry pi recently stopped booting after a (successful!) firmware update.

This fixed it.

math_is_hard.c

#include <stdio.h>
int main()
{
        printf("0.57 * 100 = %d\n", 0.57 * 100);
        printf("Math is hard!\n");
        return 0;
}

Error 0x80070652 while installing Windows 8.1

The Windows 8.1 Upgrade Assistant is running. Quit the upgrade assistant and try again.

I wish this was a joke.

UNIX one-liner: fake smtp server

For my own future reference:

python -m smtpd -n -c DebuggingServer localhost:25

Source: http://stackoverflow.com/a/6344240/2454476

sudo will be required for ports under 1024

sshd: fatal: Access denied for user foo by PAM account configuration [preauth]

Symptoms:

Oct 13 06:27:07 dl sshd[44354]: fatal: Access denied for user foo by PAM account configuration [preauth]

Solution:

If an entry is missing, you can create a new one using the passwd utility.

Alternatively, if no password is required, create a dummy entry like this:

foo:!:15991:0:99999:7:::

For more info:

man 5 shadow

Bash error: value too great for base

Consider the following:

#!/bin/bash
month='08'

for m in $( seq 1 $(( ${month} - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

When run, it produces the following error:

$ /bin/bash ./test.sh
test.sh: line 6: 08: value too great for base (error token is "08")

According to man 1 bash:

Constants with a leading 0 are interpreted as octal numbers.

Solution 1: force the number to be interpreted as decimal:

#!/bin/bash
month='08'

for m in $( seq 1 $(( 10#${month} - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

Solution 2: strip the leading zero:

#!/bin/bash
month='08'

for m in $( seq 1 $(( ${month#0} - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

(or if there are multiple leading zeros:)

#!/bin/bash
month='08'

for m in $( seq 1 $(( $(echo "${month}" | sed 's/^0*//') - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

Source

More Netboot Shenanigans: Mac network boot without a netboot server

Sometimes you want to boot a Mac from the network without running a netboot server. You already have a TFTP server set up, and the root image is sitting on a HTTP server. The only missing piece of the puzzle is how to get the Mac to boot from the network.

One option is to deploy an Apple netboot server.

Another option is to fudge it using a Linux DHCP server.

However, if you can’t do either of those things (or if you just don’t want to), then you only other option is to inject it directly into the Mac’s firmware settings.

Fortunately, the bless command has some undocumented arguments to make this easier.

This document assumes you have a netboot bundle on a server somewhere, and HTTP and TFTP already configured.

Netboot bundles will typically contain the following components:

OS X 10.6 bundles typically have a booter, a kernel, and a root filesystem image. The bless command looks like this:

sudo bless --netboot \
   --booter tftp://server/path/to/i386/booter \
   --kernel tftp://server/path/to/i386/mach.macosx \
   --options rp=http://server/path/to/NetInstall.sparseimage

The mkext doesn’t need to be specified; the firmware attempts to load it automatically.

This is explained in further detail in the Mactips article How to NetBoot Across Subnets.

Some time around 10.7 or 10.8, Apple removed the kernel and replaced it with the kernelcache:

sudo bless --netboot \
   --booter tftp://server/path/to/i386/booter \
   --kernelcache tftp://server/path/to/i386/x86_64/kernelcache \
   --options rp=http://server/path/to/NetInstall.sparseimage

However, what if you want to boot to a Mountain Lion netboot image from Snow Leopard? Unfortunately, the bless command in Snow Leopard does not support the --kernelcache option, and if you specify the kernelcache in the --kernel option, then the firmware treats it as a kernel, which fails.

To get kernelcache working from Snow Leopard, you need to get creative:

sudo bless --netboot \
   --booter tftp://server/path/to/i386/booter \
   --kernel tftp://server/path/to/i386/x86_64/kernelcache \
   --options rp=http://server/path/to/NetInstall.sparseimage
sudo nvram "$( sudo nvram efi-boot-file \
   | sed -E 's/^efi-boot-file[[:space:]]*/efi-boot-kernelcache=/' )"
sudo nvram -d efi-boot-file

This command uses bless to put the kernelcache into the wrong nvram variable. Next, it uses the nvram command to copy the kernelcache into the correct nvram variable. Finally, it uses the nvram command to delete the incorrect variable.

The end result is the same as if the --kernelcache option was used in Mountain Lion.

True Story

True story.
“Do these servers have sensors in them?”

O Fortuna Misheard Lyrics


sweet

IPv6 Certification Badge for bennettperkins

the future is now

ipv6 ftw
IPv6 ftw

Netboot Shenanigans: Mac network boot using ISC-DHCP as a BSDP server

This article by Pepijn Oomen describes how to get a netboot image to show up in the ⌥‑boot menu of the MacMini3,1, using nothing but the standard ISC‑DHCP server.

Why would you do this? Well, the ISC‑DHCP server is the standard DHCP server in many Linux distributions. :)

This method worked great until I updated the firmware on my iMac12,1. I could still boot the image, but it would not appear in the boot menu.

However, I was able to get it working by modifying the BSDP packet.

Pepijn’s configuration has the following characteristics:

  1. When the Mac requests the image list, the DHCP server returns the list of images available on the server. In Pepijn’s case, one image is listed, with id “1” and name “netboot”:
    option vendor-encapsulated-options
          01:01:01:               # bsdp_msgtype_list
          09:0c:81:00:00:01:07:6e:65:74:62:6f:6f:74; # netboot
        
  2. Otherwise, it returns the select boot image (index 1):
    option vendor-encapsulated-options
          01:01:02:               # bsdp_msgtype_select
          08:04:81:00:00:01;      # bsdptag_selected_boot_image
        

This worked fine with the new firmware when the Mac was booted holding ‘N’, but to get it to appear in the ⌥‑boot menu, I had to make the following modifications:

  1. I modified the bsdp_msgtype_list so the id and name matched my image, and I added the server priority (BSDP option 4) and default image (BSDP option 7):
    # bsdp image list message:
    # one image, plus one default image (both are the same)
    option vendor-encapsulated-options 
        01:01:01:                                 # bsdp_msgtype_list
        04:02:                                    # bsdp option code 4 (length 02) server priority
            80:00:                                #     Priority (32768)
        07:04:                                    # bsdp option code 7 (length 04) default image id
            81:00:00:89:                          #     Image ID (137)
        09:0e:                                    # bsdp option code 9 (length 0e) image list
            81:00:00:89:                          #     Image ID (137)
                09:54:68:65:2d:49:6d:61:67:65;    #         Name (length 09) 'The-Image'
        
  2. I added the machine name to the bsdp_msgtype_select reply (and modified the index to match the change above).
    # details about the selected image
    # 
    option vendor-encapsulated-options
        01:01:02:                          # bsdp_msgtype_select 
            08:04:                             # bsdptag_selected_boot_image
                81:00:00:89:                   #     Image ID (137)
            82:09:                             # Machine Name (length 09)
                54:68:65:2d:49:6d:61:67:65;    #     'The-Image'
    

… voilà! The image appears in the boot menu.

The following pages were extremely helpful when figuring out how to modify the bsdp packets:

Finally, I have included the entire dhcpd.conf below. It also includes a (commented) message list which contains multiple images. The two images appear separately in the boot menu, but I can’t figure out an easy way to differentiate between them during bsdp_msgtype_select.

#
# Apple BSDP server. Does NOT give out IP addresses
#

ddns-update-style none;
ddns-updates off;
ignore client-updates;
allow booting;
authoritative;
boot-unknown-clients on;
ping-check off;
one-lease-per-client on;
default-lease-time 7200;
max-lease-time 7200;
allow-unknown-clients;

subnet 0.0.0.0 netmask 0.0.0.0 { 
    pool {
        # DON'T supply an IP address!
        range 0.0.0.0 0.0.0.0;
        allow members of "netboot";
    }
}

class "netboot" {

    match if substring (option vendor-class-identifier, 0, 9) = "AAPLBSDPC";
    option dhcp-parameter-request-list 1,3,17,43,60;
    
    if (option dhcp-message-type = 1) {
        option vendor-class-identifier "AAPLBSDPC";
        option vendor-encapsulated-options
            08:04:81:00:00:89;    # bsdp option 8 (length 04) -- selected image id;
    } elsif (option dhcp-message-type = 8) {
        option vendor-class-identifier "AAPLBSDPC";
        if (substring(option vendor-encapsulated-options, 0, 3) = 01:01:01) {
            log(debug, "bsdp_msgtype_list");
            
            # bsdp image list message:
            # one image, plus one default image (both are the same)
            option vendor-encapsulated-options 
                01:01:01:                                 # bsdp_msgtype_list
                04:02:                                    # bsdp option code 4 (length 02) server priority
                    80:00:                                #     Priority (32768)
                07:04:                                    # bsdp option code 7 (length 04) default image id
                    81:00:00:89:                          #     Image ID (137)
                09:0e:                                    # bsdp option code 9 (length 0e) image list
                    81:00:00:89:                          #     Image ID (137)
                        09:54:68:65:2d:49:6d:61:67:65;    #         Name (length 09) 'The-Image'
            
            # bsdp image list message:
            # TWO images, plus one default image (both are the same)
            #option vendor-encapsulated-options 
            #    01:01:01:                # bsdp_msgtype_list
            #    04:02:                    # bsdp option code 4 (length 02) -- server priority
            #        80:00:                #     Priority (32768)
            #    07:04:                    # bsdp option code 7 (length 04) -- default image id
            #        81:00:00:89:            #     Image ID (137)
            #    09:1b:                    # bsdp option code 9 (length 1b) -- image list
            #        81:00:00:89:            #     Image ID (137)
            #            09:54:68:65:2d:49:6d:61:67:65:    #         Name (length 09) 'The-Image'
            #        81:00:04:31:            #     Image ID (1073)
            #            08:44:53:52:2d:31:30:37:33;    #         Name (length 08) 'DSR-1073'
            # option-boot lists both images, but 
                     
        } else {
            log(debug, "bspd_msgtype_select");

            # details about the selected image
            # 
            option vendor-encapsulated-options
                01:01:02:                          # bsdp_msgtype_select 
                08:04:                             # bsdptag_selected_boot_image
                    81:00:00:89:                   #     Image ID (137)
                82:09:                             # Machine Name (length 09)
                    54:68:65:2d:49:6d:61:67:65;    #     'The-Image'

            if (substring(option vendor-class-identifier, 10, 4) = "i386") {
                filename "/osx/i386/booter";
                next-server 10.25.64.32;
                option root-path = "http://10.25.64.32/build.sparseimage";
            } elsif (substring(option vendor-class-identifier, 10, 3) = "ppc") {
                filename "nil";
            }
        }
    }
}

Update 06 Feb 2013:

Brandon’s Tinkerings has a solution for handling multiple images correctly. Awesome! :)

Update 21 Feb 2013:

The server priority is in fact BSDP option 4, not option 2.

Update 09 April 2014:

The Brandon’s Tinkerings solution appears to be offline. :(
→ Mirror here.

How to create a user account in lion from single user mode

Here’s how:

Boot into single user mode (⌘S), and run the following commands:

# Mount the filesystem; start opendirectoryd:
/sbin/fsck -fy && /sbin/mount -uw /
launchctl load /System/Library/LaunchDaemons/com.apple.opendirectoryd.plist

# Create the user account:
dscl . -create /Users/localadmin
dscl . -create /Users/localadmin UserShell /bin/bash
dscl . -create /Users/localadmin RealName "Local Admin"
dscl . -create /Users/localadmin UniqueID 502
dscl . -create /Users/localadmin PrimaryGroupID 20
dscl . -create /Users/localadmin NFSHomeDirectory /Users/localadmin

# Create the home directory:
cp -R "/System/Library/User Template/English.lproj" /Users/localadmin
chown -R localadmin:staff /Users/localadmin

# Set the password:
dscl . -passwd /Users/localadmin newPassword

# Grant admin access (optional):
dscl . -append /Groups/admin GroupMembership localadmin

Notes:

You may see this error message, but don’t worry, it can be safely ignored:

launchctl: Couldn't stat("/System/Library/LaunchDaemons/com.apple.DirectoryServicesLocal.plist"): No such file or directory
nothing found to load

To get the next unused UniqueID, run this command:

maxid=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -ug | tail -1)
newid=$((maxid+1))
echo $newid

To get the group id for the staff group, run this command:

dscacheutil -q group -a name staff

(make a note of the uid — usually 20)

Sources:
http://support.apple.com/kb/HT4749
http://serverfault.com/questions/20702/how-do-i-create-user-accounts-from-the-terminal-in-mac-os-x-10-5

building cntlm from subversion using macports

Why do it the easy way?

Update: I originally wrote this post because of an overflow bug which caused files over 2GB to fail silently, and the fix hadn’t yet been released. Well, the fix has now been released, so it’s probably a better idea to use that version, since this portfile does not work properly with selfupdate.

Instructions

  1. Install and configure macports. Note that selfupdate doesn’t work from svn.

  2. Create a local repository:

    mkdir -p ~/ports/net/cntlm/files
    
  3. Copy the Portfile and patch to the repository (contents below):

    cp /path/to/Portfile ~/ports/net/cntlm
    cp /path/to/patch-trunk-Makefile.diff ~/ports/net/cntlm/files
    
  4. Configure the local repository. Add the following line to /opt/local/etc/macports/sources.conf, then sync the repository:

    file:///Users/localadmin/ports
    
    sudo port -d sync
    
  5. Install cntlm:

    sudo port -v install cntlm
    

Portfile

    # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
    # $Id$
    PortSystem              1.0
    name                    cntlm
    version                 HEAD
    license                 gpl
    categories              net
    platforms               darwin
    maintainers             xs4all.nl:hbruinsma
    homepage                http://cntlm.sourceforge.net/
    description             Cntlm is an NTLM / NTLM Session Response / NTLMv2 authenticating HTTP proxy
    svn.url                 https://cntlm.svn.sourceforge.net/svnroot/cntlm/cntlm/trunk
    svn.revision            HEAD
    fetch.type              svn
    worksrcdir              trunk
    patchfiles              patch-trunk-Makefile.diff
    depends_lib             port:coreutils
    build.target            {}
    build.args              SYSCONFDIR=/opt/local/etc BINDIR=/opt/local/sbin \
            MANDIR=/opt/local/man
    destroot.args           SYSCONFDIR=/opt/local/etc BINDIR=/opt/local/sbin \
            MANDIR=/opt/local/man
    
    startupitem.create      yes
    startupitem.name        cntlm
    startupitem.executable  "${prefix}/sbin/cntlm"

patch-trunk-Makefile.diff

    -- Makefile    2011-10-14 19:45:26.000000000 +0800
    +++ Makefile.old        2011-12-06 17:11:08.000000000 +0800
    @@ -44,10 +44,10 @@
                    install -M 644 -f $(MANDIR)/man1 doc/$(NAME).1; \
                    install -M 600 -c $(SYSCONFDIR) doc/$(NAME).conf; \
            else \
    -               install -D -m 755 -s $(NAME) $(BINDIR)/$(NAME); \
    -               install -D -m 644 doc/$(NAME).1 $(MANDIR)/man1/$(NAME).1; \
    +               install -m 755 -s $(NAME) $(BINDIR)/$(NAME); \
    +               install -m 644 doc/$(NAME).1 $(MANDIR)/man1/$(NAME).1; \
                    [ -f $(SYSCONFDIR)/$(NAME).conf -o -z "$(SYSCONFDIR)" ] \
    -                       || install -D -m 600 doc/$(NAME).conf $(SYSCONFDIR)/$(NAME).conf; \
    +                       || install -m 600 doc/$(NAME).conf $(SYSCONFDIR)/$(NAME).conf; \
            fi
            @echo; echo "Cntlm will look for configuration in $(SYSCONFDIR)/$(NAME).conf"

Note that macports does not recommend building from subversion, since the results will not be reproducible. However, for testing, it should work fine.

My Song 4

More Greasemonkey scripting

More work-related scripting.

    // ==UserScript==
    // @name           CI Manager Fixes
    // @namespace      https://bennettp123.com
    // @description    Fixes some of the broken CSS in CI Manager. Very much a work in progress.
    // @include        http://cimanager.REDACTED/*
    // ==/UserScript==
    
    function addCSS(cssString)
    {
        var head = document.getElementsByTagName('head')[0];
        if (!head) { return null; }
        var newCSS = document.createElement('style');
        newCSS.type = "text/css";
        newCSS.innerHTML = cssString;
        head.appendChild(newCSS);
    }
    
    // delete an element by ID and return its parent
    function removeByID(elementId)
    {
        var element = document.getElementById(elementId);
        if (!element) { return null; }
        var parent = element.parentNode;
        parent.removeChild(element);
        return parent;
    }
    
    // delete the stupid placeholder image, replace it with some regular text
    var imageID = "ctl00_MainContent_ctl00_imgNoRelationData"
    try {
        // (removeByID returns the parent of the element removed.)
        removeByID(imageID).innerHTML = "No relationship data available";
    }
    catch (error) {
        // who cares?
    }
    
    // add an empty placeholder to the end of the menu
    // **** EDIT: doesn't work properly with floats; disabled ****
    //        var menu = document.getElementById("menu");
    //        if (menu) {
    //            var placeholder = document.createElement('div');
    //            placeholder.id = "menu_placeholder";
    //            placeholder.innerHTML = " ";
    //            menu.appendChild(placeholder);
    //        }
    
    // add some custom CSS
    addCSS (
    '   div#page { overflow:auto!important } \n\
        div#main { float:none!important; \n\
                   background-image:none!important; \n\
                   width:auto!important; } \n\
        div#menu { margin-right:25px!important } \n\
        //div#menu_placeholder { height:1000px } \n\
        //td { width:auto!important } \n\
        //select,textarea,input { width:auto!important } \n\
        \n\
        #ctl00_MainContent_ctl00_txtNotes, \n\
        #ctl00_MainContent_ctl00_txtSiteName, \n\
        #ctl00_MainContent_ctl00_lstRelations, \n\
        #ctl00_MainContent_ctl00_pnlNoRelationData \n\
        { width:auto!important } \n\
        \n\
        #ctl00_MainContent_ctl00_lstRelations { min-width:140px } \n\
        \n\
        #ctl00_MainContent_ctl00_ddlStatus, \n\
        #ctl00_MainContent_ctl00_ddlClassification \n\
        { width:146px!important } \n\
        \n\
        #ctl00_MainContent_ctl00_txtCreationDate, \n\
        #ctl00_MainContent_ctl00_txtModifiedDate \n\
        { width:138px!important } \n\
        \n\
        #ctl00_MainContent_ctl00_chkAdditionalServices, \n\
        #ctl00_MainContent_ctl00_chkCAPUTemplates \n\
        { text-align:right } \n\
        \n\
        label + input { white-space:nowrap } \n\
        \n\
        //table * * div { width:auto!important } \n\
        \n\
        #ctl00_MainContent_pnlInitialView>table, \n\
        #ctl00_MainContent_pnlInitialView>table>tbody, \n\
        { width:58%!important } \n\
        \n\
        #ctl00_MainContent_pnlInitialView>table * td \n\
        { width:auto!important } \n\
        \n\
        #ctl00_MainContent_pnlInitialView>table * td>div \n\
        { overflow:hidden!important; \n\
          text-overflow:ellipsis!important; \n\
          white-space:nowrap!important; \n\
        } \n\
        #ctl00_MainContent_pnlInitialView>table * td h5, \n\
        #ctl00_MainContent_pnlInitialView>table * td div \n\
        { width:68%!important; } \n\
        \n\
        #ctl00_MainContent_pnlInitialView>table * td>hr \n\
        { visibility:hidden; } \n\
        \n\
        //#ctl00_MainContent_pnlInitialView>table>tbody, \n\
        //#ctl00_MainContent_pnlInitialView>table>tr \n\
        //{ width:78%!important ); \n\
        '
    );