nbalonso.com

Fixing BootPicker for Yosemite

| Comments

At work we’ve been using Apple BootPicker for years. It is specially useful for computers sitting in public areas where there are many visitors coming in and out. It allows us for example to make the whole library dual-boot.

The problem is that the application has not been updated since 2009, so as one would expect it doesn’t play nice with the most recent version of OS X.

The log from the application reads

BootPicker: BootPicker: Exiting, BootPicker is only supported on Leopard or later.

So yeah… it doesn’t know that 10.10 is > 10.5. The reason is that it is picking up only the first digit after the dot and comparing it against five.

When I saw the error I thought to myself “that it’s a silly comparison error” (which is also the reason Microsoft had to jump to Windows 10) and it could be fixed by simply making the comparison against 10.0.

So I downloaded Hex Fiend, opened the binary, looked for the hex value of 10.5 and replaced it with 10.0; went to test it and works!

Put it all together in a pkg with new images, renamed the LaunchAgent and made the logs go the more reasonable location /var/log/bootpicker.log. You can download my package here.

Note that this package does deploy a sample preference file to /Library/Preferences/bootpicker.plist. It looks like

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>bgPath</key>
  <string>/Library/Desktop Pictures/Milky Way.jpg</string>
  <key>defaultBootOS</key>
  <string></string>
  <key>linJustification</key>
  <string></string>
  <key>linuxPartition</key>
  <string></string>
  <key>mosxJustification</key>
  <string></string>
  <key>timeLimit</key>
  <integer>0</integer>
  <key>title</key>
  <string>Welcome to Macintosh</string>
  <key>userChoosesBootOS</key>
  <true/>
  <key>winJustification</key>
  <string></string>
  <key>windowsPartition</key>
  <string>/dev/disk0s4</string>
</dict>
</plist>

So the computer will end up looking like

You will probably want to replace or edit this file to accommodate your needs.

During my testing, the panel in System Preferences did not seem to work as expected but modifying the plist did.

Bonus: When I was playing with this on a VM I noticed that the log read

1
2
3
4
5
6
7
8
9
10
11
23:38:20 BootPicker: Configuring interface for Windows volume/device: /dev/disk0s4
23:39:00  BootPicker: User chose Windows.
23:39:00  BootPicker: Bless args: (
    "--device",
    "/dev/disk0s4",
    "--setBoot",
    "--legacy",
    "--nextonly"
).
Legacy mode not supported on this system
23:39:00  BootPicker: Failed to set /dev/disk0s4 as the boot device!

So if you ever want to get rid of that --legacy part and make OS X still trust the binary you could replace it with zeros and the log will end up with something like

1
2
3
4
5
6
7
8
9
23:44:45 BootPicker: User chose Windows.
23:44:45  BootPicker: Bless args: (
    "--device",
    "/dev/disk0s4",
    "--setBoot",
    "",
    "--nextonly"
).
23:44:45  BootPicker: Flagging slice 4

A VM can’t be blessed so this doesn’t make it work, but this trick might be useful in the future if you need UEFI boots (eg. black Mac Pro)

Did you end up with a cold feeling about how non-secure OS X really can be?

Scripting Evolution

| Comments

Anyone that write scripts to automate things, soon ends up with a folder filled with many old written script that did specific tasks.

This is always a handy thing, because you can re-use scripts or parts to accomplish different tasks quicker, but as it happens when you are learning a new language, reading thing you wrote long time ago makes you realize of mistakes you did. This is usually because you didn’t know better back then.

When this happens to me it causes me to:

  1. Feel ashamed thinking that someone probably did realize your code was crappy
  2. Feel proud that at least now you are at a stage when you see it by yourself.

The reason behind this post is that recently I’ve been trying to autome something with Powershell and felt like this

So yeah. Here some Powershell that (hopefully soon) I won’t be proud of.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# ChangePassword.ps1

#Usage eg.
# .\ChangePassword.ps1 -key 1,0,5,9,6,34,254,211,4,4,192,23,168,54,33,2,1,34,2,7,6,9,35,37

# We must get the decryption key
Param(
  $key
)

######Target user########
$user = "ITadmin"
#########################

if (-not $key) {
  write-host "`r`nYou must pass the decryption key as parameter`r`n"
  exit
}

# Don't display errors!
$ErrorActionPreference = "SilentlyContinue"
# Stop on errors
# $ErrorActionPreference = "stop"

$password = (Get-Content $PSScriptRoot/Encrypted.bin | ConvertTo-SecureString -key $key)
if (-not $password) {
  write-host "`r`nThe provided decryption key is incorrect`r`n"
  exit
}
$computer = $env:COMPUTERNAME


# Returns a SecureString as a String.
function ConvertTo-String {
  param(
    [System.Security.SecureString] $secureString
  )
  $marshal = [System.Runtime.InteropServices.Marshal]
  try {
    $intPtr = $marshal::SecureStringToBSTR($secureString)
    $string = $marshal::PtrToStringAuto($intPtr)
  }
  finally {
    if ( $intPtr ) {
      $marshal::ZeroFreeBSTR($intPtr)
    }
  }
  $string
}

##First check wether user exists
$objComputer = [ADSI]"WinNT://$computer,computer"
$colUsers = ($objComputer.psbase.children | Where-Object {$_.psBase.schemaClassName -eq "User"} | Select-Object -expand Name)
$userFound = $colUsers -contains $user
if (! $userFound) {
  write-host "The $user account did not exist."
  write-host "Creating $user"
  $objOu = [ADSI]"WinNT://$computer"
  $objUser = $objOU.Create("User", $user)
  $objUser.setpassword((ConvertTo-String $password))
  $objUser.SetInfo()
}
else {
  write-host "The $user account exists."
  write-host "Changing it's password"
  $objUser = [ADSI]"WinNT://$computer/$user,user"
  try {
   $objUser.SetPassword((ConvertTo-String $password))
   $objUser.SetInfo()
  }
  catch [System.Management.Automation.MethodInvocationException] {
   write-host "Cannot reset password for '$computer\$user' due the following error: '$($_.Exception.InnerException.Message)'"
   exit
  }
}

#Now that the user exists and has the new password:
$objUser = [ADSI]("WinNT://$computer/$user")
$objGroup = [ADSI]("WinNT://$computer/Administrators")
#Adding to admin group
$objGroup.PSBase.Invoke("Add",$objUser.PSBase.Path)
# ADS_UF_DONT_EXPIRE_PASSWD http://support.microsoft.com/kb/305144
$objUser.UserFlags = 65536
$objUser.SetInfo()

write-host "`r`nSuccess!`r`n"

Blog Migration

| Comments

If you ever visited this site before you might have noticed a slight change in the looks of it.

I recently decided to move the blog to Octopress.

Initially it all started with a RapidWeaver template in a paid shared hosting; then I moved to a Wordpress and now to Octopress in Red Hat’s OpenShift.

The website is hosted in a free small diy cartridge with a custom install of Nginx, cached for free by CloudFare. All for just static content! so yeah speed :)

And here is a graphical view of the evolution over these years

The website has lost the built-in search capability but… meh