looto: Look Up What’s Dependent On A Binary

Ever wonder what binaries have dependencies on a given binary? The otool command allows you to look up what dependencies a binary has, but there’s some extra work to get to reversing it. So looto.sh. 


Add Jamf Pro Smart Group to a Google Doc Using Zapier

In this article, we’ll cover how to use Zapier to connect data from your Jamf Account to a Google sheet. Once you build a WebHooks receiver in Zapier, you don’t have to use Google as the third party service that your WebHook triggers. You could use any other service that Zapier integrates as well, including Mailchimp, WordPress, Shopify, Todoist, ZenDesk, SurveyMonkey, Freshdesk, Quickbooks, Basecamp, and about 1,200 other solutions. In other words, you can link a WebHook from Jamf Pro into pretty much any automated service that you can think of!

So what’s a WebHook? A WebHook is an HTTP callback, or an HTTP POST that is fired when an event happens. The goal of WebHooks is that they are simple event notifications, typically sending a small amount of json to a destination web server that’s then ; a simple event-notification via HTTP POST. A web application listening for that event will then receive the WebHooks and perform a task in the background. Zapier is a great little tool that connects web apps. For modern software apps, most of this is done via acting as a WebHooks receiver and sending an API call to another tool. 

To follow along with this article, you will need a Zapier account, Jamf account and a Google account. Since we’ll be using Zapier to connect Jamf Pro and Google. 

Google Sheet Setup

  1. Signup/Login to your google account at https://docs.google.com/spreadsheets.
  2. Create new spreadsheet.
  3. Add any column names of fields you will want to store on your google sheet about your device—i.e. Date, Group, Name, Mac Address, IP Address, Make, Model, etc. We will use these columns in the Zap to map our data to the correct column.

Zapier Setup

  1. Signup/Login to your Zapier account at https://zapier.com
  2. Click “Make a Zap!” button in top right-hand corner.
  3. You will start my setting up the webhook for catching the smart group change.

Catching Smart Group Membership Change Zap

  1. Name your Zap
  2. Add Note (optional) – Optionally it might be good to add some details about what you zap does. You can do this by clicking the link “Add Note” under the name.
  3. Example Note:Catches POST from Smart Group Change Zap and gets the Id of the computer added and/or removed from the group, to get all the computer details and save to Google Sheet.
  4. Setup your trigger step. Choose Webhooks under Built-In Apps.
  5. Select Catch Hook.
  6. Continue pass the “Pick Off a Child Key” as there is nothing specific we need to select off the hook.
  7. Zapier will provide an URL to send requests to. This URL will need to be copied and pasted in your webhook settings in Jamf.
  8. Open up a new window to begin setup of Jamf webhook, leave this zap open as you will return to it.

Jamf Setup of Webhook

  1. After copying the URL from the zap. Open up a new window and login to your Jamf account.
  2. Click the cog in the top right corner and go to your settings.
  3. Under Global Management click on the Webhooks icon.
  4. Click “New” button.
  5. Add a Display Name.
  6. Check “Enabled”.
  7. Paste the URL from the previous zap to the Webhook URL input.
  8. Set Authentication Type to “None”
  9. Fill in your preferred connection and read timeout
  10. Set Content Type to “JSON”
  11. Select the Webhook event from the dropdown – Set to “SmartGroupComputerMembershipChange”
  12. Set up the target smart computer group. You can select a group or apply to all groups.
  13. Save and return to your Zapier window with your previous zap.

Catching Smart Group Membership Change Zap (continued)

  1. After completing setup of Jamf webhook. Click “Ok, I did this” to begin a test and pull in a test sample. Then return to your Jamf window and trigger the webhook. The webhook can be triggered in two ways.
    1. Trigger the webhook by going to Computers – > Search Inventory -> (Select a computer) -> Edit -> Update site to a new site that is in a different computer group and Save
    2. Trigger the webhook by going to Computers -> Smart Computer Groups – > (Select a Group) -> Update site to a new site that is in a different computer group and Save.
  2. If the event is triggered correctly you will see a test result/message like below:

  1. Next setup an action step. Select Code under Built-In Apps.
  2. Select “Run Javascript”
  3. Use the following Input Data Parameters
    1. eventName : Select “Event Name” from Field Options
    2. addedComputers: Select “Event Group Added Device Ids” from Field Options
    3. removedComputers: Select “Event Group Removed Device Ids” from Field Options
  4. In the code section. Copy and paste the following code:

** The highlighted url will be replaced by another url in a later zap.

var added = [];
var removed = [];
if(inputData.addedComputers) {
added = inputData.addedComputers.split(',');
if(inputData.removedComputers) {
removed = inputData.removedComputers.split(',');
var otherZapURL = "https://hooks.zapier.com/hooks/catch/3491337/wk7qh8/";
for(var i = 0; i< added.length; i++) {
var addedBody = JSON.stringify({
computer: added[i],
status: "added",
await fetch(otherZapURL, {method:'POST', body:addedBody});
for(var i = 0; i< removed.length; i++) {
var removedBody = JSON.stringify({
computer: removed[i],
status: "removed",
await fetch(otherZapURL, {method:'POST', body:removedBody});
return [{status: 'ok'}];

  1. This zap is done.

Saving Computer Details to Google Sheet

  1. Start a new zap.
  2. Add Note (optional) – Optionally it might be good to add some details about what you zap does. You can do this by clicking the link “Add Note” under the name.
  3. Example Note:Catches POST from Smart Group Change Zap and gets the Id of the computer added and/or removed from the group, to get all the computer details and save to Google Sheet.
  4. Setup your trigger step. Choose Webhooks under Built-In Apps.
  5. Select Catch Hook.
  6. Continue pass the “Pick Off a Child Key” as there is nothing specific we need to select off the hook.
  7. Zapier will provide an URL to send requests to. This URL will need to be copied and pasted in your previous zap in the code section where the highlighted url was listed.
  8. Setup an action step. Select Webhooks under “Built-In Apps”
  9. Select “GET” action type.
  10. Fill in the following input:
    1. URL : Copy and Paste https://kryptedjamf.jamfcloud.com/JSSResource/computers/id/(replace your kryptedjamf.jamfcloud.com with your role)
      1. Select “Computer” from field options
      2. See below as sample:

  1. Query String Params – leave blank
  2. Send As JSON – Select Yes
  3. JSON key – enter “json”
  4. Unflatten – Select Yes
  5. Basic Auth –separate your username and password with a pipe character
  6. Headers – leave blank
  1. Continue to through to Test Step and make sure data was received about the computer.
  2. If successful, continue to add a third action step by clicking the plus icon under you previous step and selection Action.
  3. Search for Google sheets in Search for Apps.
  4. Select Google Sheets and select the action type “Create Spreadsheet Row”.
  5. Connect your Google Account you used to create your Google sheet in the previous steps. See Google Sheets Setup section earlier in this document.
  6. Select Spreadsheet you set up under Spreadsheet input.
  7. Select the worksheet that has your columns names.
  8. After the worksheet is selected, each column will appear as an input option to map fields to. You will need to map each column to the appropriate field by selecting the field from the field options menu to the right of the input.
  9. After you’ve finished the mapping, select Continue to Test the step. If the test was successful, you should see your new record on your google sheet.
  10. Turn both of your zaps on and you are ready to automatically record all your smart group changes!

This was written for a specific use case, but because it’s useful for a number of apps and many of those can be hooked to other apps providing a nearly infinite number of use cases to link Jamf Pro Smart Group changes (one of the most valuable things that Jamf does) to other solutions!


The ins and outs of using tmutil to backup, restore, and review Time Machine backups

Since some of the more interesting features of Time Machine Server are gone, let’s talk about doing even more than what was previously available in that interface by using the command line to access Time Machine.

As with any other command, you should probably start by reading the man page. For Time Machine, that would be:

man tmutil

Sometimes, the incantation of the command you’re looking for might even be available at the bottom of the man page. Feel free to use the space bar a few times to skip to the bottom, or q to quit the man interface.

In addition to the man page, there’s a help command, which can be used in conjunction with any of the command verbs (which makes me think of “conjunction junction, what’s your function”). For example, you can tell tmutil to compare backups using the compare verb. To see more on the usage of the compare verb, use tmutil followed by compare (the verb, or action you wish the command to perform), followed by help:

/usr/bin/tmutil compare help

Before you start using Time Machine, you’ll want to set a backup source and destination. Before you do, check the destination that’s configured:

/usr/bin/tmutil destinationinfo

The output will include

Name: TimeMachineBackup
Kind: Network URL: afp://;AUTH=No%20User%20Authent@MyCloud-YAZ616._afpovertcp._tcp.local/TimeMachineBackup
ID: 265438E6-73E5-48DF-80D7-A325372DAEDB

Once you’ve checked the destination, you can set a destination. For example, the most common destination will be something like /Volumes/mybackupdrive where mybackupdrive is a drive you plugged into your computer for Time Machine. 

sudo /usr/bin/tmutil setdestination /Volumes/mybackupdrive

Once you’ve configured a destination for your backups, it’s time to enable Time Machine. The simplest verbs to use are going to be the enable and disable verbs, which you might guess turn Time Machine on and off respectively. For these, you’ll need elevated privileges. To turn Time Machine on:

sudo /usr/bin/tmutil enable

To then disable Time Machine:

sudo /usr/bin/tmutil disable

You can also kick off a backup manually. To do so, use the startbackup verb as follows:

sudo /usr/bin/tmutil startbackup

To see the status, once you’ve kicked off a backup (this one is gonna’ be hard to remember) use the status verb:

sudo /usr/bin/tmutil status

Or to stop a backup that is running (e.g. if your computer is running slowly and you think it’s due to a backup running), you’d use the stopbackup verb:

sudo tmutil stopbackup

Once backups are complete, you can see the directory they’re being stored in with the machinedirectory verb. This will become important when we go to view information about backups and compare backups, which require that directory to be available as those options check local files and databases for information directly. The tmutil verb to do that is machinedirectory:

sudo /usr/bin/tmutil machinebackup

Other options you can enable, include the ability to exclude files or directories from your backups. For example, you won’t likely want to backup your music or movies that were purchased on iTunes as they take up a lot of space and are dynamically restored from Apple in the event that such a restore is necessary. The verb to do so is addexclusion and this also requires sudo. So to exclude the user krypted’s ~/Music directory, you’d use a command as follows:

sudo /usr/bin/tmutil addexclusion /Users/krypted/Music

To then check if a directory is excluded, use the isexcluded verb and define the path:

sudo /usr/bin/tmutil isexcluded /Users/krypted/Music

If you make an errant exclusion do the opposite to remove, leveraging the removeexclusion verb:

/usr/bin/tmutil removeexclusion /Users/krypted/Music

Once a backup is complete, you can also check various information about the backups. This can be done using a few different verbs. One of the more common manual tasks that is run is listing the recent backups that can be restored. This is done using the listbackups verb with no operators (the backup directory needs to be available when run, so cd into that before using listbackups).

/usr/bin/tmutil listbackups

You can also view the latest backup, which can then be grabbed by your management tool, which is provided in the YYYY-MM-DD-HHMMSS format.
/usr/bin/tmutil latestbackup

You can also compare backups so you can see the files that have been changed, added, and removed, as well as the size of the drift between the two backups. To do so, use the compare verb and provide the paths between the two backups that were obtained when using the listbackups verb, as follows:

/usr/bin/tmutil compare “/Volumes/mybackupdrive/Backups.backupdb/Krypted/2018–04–24–051014” “/Volumes/mybackupdrive/Backups.backupdb/Krypted/2018–04–24–061015”

In the above paths, we’re using the mybackupdrive and krypted is the source volume name. You can also look at all of the backups (and potentially derive future space requirements based on a trend line) by using the calculatedrift verb:

/usr/bin/tmutil calculatedrift /Volumes/mybackupdrive/Backups.backupdb/Krypted

At times, you may end up replacing infrastructure. So you might move backups to a new location, or move backups to a new solution. You can use the inherent backups to claim a new machine directory. So if you moved your backups from /Volumes/mybackupdrive/Backups.backupdb/Krypted to /Volumes/mylargerbackupdrive/Backups.backupdb/Krypted during an upgrade you might run the following so you don’t have to start backing up all over again and end up wiping out your backup history:

/usr/bin/tmutil inheritbackup /Volumes/mylargerbackupdrive/Backups.backupdb/Krypted

Or if you have both available at once, use the associatedisk verb with the new volume followed by the old volume:

sudo /usr/bin/tmutil associatedisk "/Volumes/mylargerbackupdrive/Backups.backupdb/Krypted" "/Volumes/mybackupdrive/Backups.backupdb/Krypted"

Or if you do want to start over but want to clear out old backups, you can use the delete verb followed by the path to the backup or snapshot, as follows:

sudo /usr/bin/tmutil delete /Volumes/mybackupdrive/Backups.backupdb/Krypted

There are also a few more verbs available, mostly for apfs. The localsnapshot command creates new snapshots of APFS volumes, and is used with no operators, as follows:

sudo /usr/bin/tmutil localsnapshot

To then see the snapshots, use the listlocalsnapshots verb,

sudo /usr/bin/tmutil listlocalsnapshots

Which outputs as follows:

Or to constrain the output for easier parsing, use listlocalsnapshotdates:

sudo /usr/bin/tmutil listlocalsnapshotdates

Which outputs as follows

And you can delete a snapshot with the deletesnapshot

sudo tmutil deletelocalsnapshots 2018-04-20-061417

Now, thinning out your backups is always an interesting task. And in my experience your mileage may vary. Here, you can use the thinlocalsnapshots verb to prune the oldest data from backups. In the following example, we’re going to purge 10 gigs of data:

sudo /usr/bin/tmutil thinlocalsnapshots / 10000000000

Finally, let’s talk about automated restores. You could use this type of technology to do a rudimentary form of imaging or rolling users into a new machine. To restore a backup, you would use the (shocking here) restore verb. First, let’s look at restoring a single file. In the following example, we’ll restore a file called mysuperimportantfile from a computer called mycomputername and provide the date of the snapshot we’re restoring from:

sudo /usr/bin/tmutil restore /Volumes/mybackupdrive/Backups.backupdb/mycomputername/2018-04-24-051015/Macintosh\ HD/Users/krypted/Desktop/mysuperimportantfile

Now, let’s look at restoring a volume. Here, we’re going to change our working directory to the root of our latest backup, not booted to the volume we’re about to erase and overwrite with a backup):

cd "/Volumes/Time Machine Backup Disk/Backups.backupdb/mycomputername/Latest/Macintosh HD"

And then (this is dangerous, as it wipes out what’s on the old volume with the backed up data):

sudo /usr/bin/tmutil restore -v "/Volumes/Time Machine Backup Disk/Backups.backupdb/mycomputername/Latest/Macintosh HD" "/Volumes/Macintosh HD"

Now, let’s talk about what’s realistic. If I were to programmatically erase one of my coworkers data. I’d really, really want to verify that everything they need is there. So I’d run a checksum against the source and keep a copy of it only once I verify that absolutely everything is going where I want it to go. I would trust a cloning tool, but would I want to basically write my own archival solution using tmutil? No. I’ve simply seen too many strange little tidbits here and there that make me not… exactly… trust it with other people’s data. With my own data, though… sure! <3

DNS: Install BIND on macOS

The DNS service in macOS Server was simple to setup and manage. It’s a bit more manual in macOS without macOS Server. The underlying service that provides DNS is Bind. Bind will require a compiler to install, so first make sure you have the Xcode command line tools installed. To download Bind, go to ISC at https://www.isc.org/downloads/. From there, copy the installer locally and extract the tar file. Once that’s extracted, run the configure from within the extracted directory:

./configure --enable-symtable=none --infodir="/usr/share/info" --sysconfdir="/etc" --localstatedir="/var" --enable-atomic="no" --with-gssapi=yes --with-libxml2=no

Next, run make:


Then run make install:

make install

Now download a LaunchDaemon plist (I just stole this from the org.isc.named.plist on a macOS Server, which can be found at /Applications/Server.app/Contents/ServerRoot/System/Library/LaunchDaemons/org.isc.named.plist or downloaded using that link). The permissions for a custom LaunchDaemon need to be set appropriately:

chmod root:wheel /Library/LaunchDaemons/org.isc.named.plist

Then start it up and test it!

launchctl load -w /Library/LaunchDaemons/org.isc.named.plist

Now you can manage the server as we described at http://krypted.com/mac-os-x-server/export-dns-records-macos-server/.

Backup A Mac With Acronis True Image

Acronis True Image is a cloud-based backup solution. Acronis True Image is available at 

https://www.acronis.com/en-us/support/trueimage/2018mac/. To install, download it and then open the zip. 

Drag the Acronis True Image application to your /Applications directory. Then open Acronis True Image from /Applications. The first time you open it, you’ll be prompted to access the licensing agreement.

Once accepted, you’ll be prompted to create an account with Acronis. Provide your credentials or enter new ones to create a trial account. 

At the activation screen, provide a serial or click Start Trial.

At the main screen, you’ll first want to choose the source (by default it’s the drive of the machine) and then click on the panel to the right to choose your destination.

For this example, we’re going to use the Acronis cloud service. 

Click on the cog wheel icon at the top of the screen. Here, you can set how and when the backup occurs. Click Schedule.

At the schedule screen, select the time that backups will run. Note that unless you perform file level backups, you can’t set the continual backup option. For that, I’d recommend not doing the whole computer and instead doing directories where you store data. Click on Clean Up.

Here, you’ll define your retention policies. How many backups will you store and for how long. Click Encryption.

Here you’ll set a password to protect the disk image that stores your backups. The disk image can’t be unpacked without it, so don’t forget the password! Click on Exclusions.

Here, use the plus sign icon to add any folders you want skipped in the backups. This could be stuff you don’t need backed up (like /Applications) or things you intentionally don’t want backed up. Click Network. 

Here you can throttle the speed of network backups. We’ll skip this for now. Now just click on the Back Up button to get your first backup under way!

If you want to automate certain configuration options, check for the com.acronis.trueimageformac.plist at ~/Libarary/Preferences to see if the app has been launched, as you can see from the defaults domain contents:

{  SUEnableAutomaticChecks = 1;
SUHasLaunchedBefore = 1;
SULastCheckTime = “2018-04-07 21:33:01 +0000”; }

There are also log settings available at 
/Applications/Acronis True Image.app/Contents/MacOS/acronis_drive.config:

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<channel id=”ti-rpc-client” level=”info” enabled=”true” type=”logscope” maxfiles=”30″ compress=”old” oneday=”true”/>
<channel id=”http” level=”info” enabled=”true” type=”logscope” maxfiles=”30″ compress=”old” oneday=”true”/>
<channel id=”ti_http_srv_ti_acronis_drive” level=”info” enabled=”true” type=”logscope” maxfiles=”30″ compress=”old” oneday=”true”/>
<channel id=”ti-licensing” level=”info” enabled=”true” type=”logscope” maxfiles=”30″ compress=”old” oneday=”true”/>
<channel id=”acronis_drive” level=”info” type=”logscope” maxfiles=”10″ compress=”old” oneday=”true” />  <!–max 10 files, ?MB–></logging>


Migrate From macOS To A Synology Based VPN

Synology is able to do everything a macOS Server could do, and more. So if you need to move your VPN service, it’s worth looking at a number of different solutions. The most important question to ask is whether you actually need a VPN any more. If you have git, mail/groupware, or file services that require remote access then you might want to consider moving these into a hosted environment somewhere. But if you need access to the LAN and you’re a small business without other servers, a Synology can be a great place to host your VPN services. 

Before you setup anything new, first snapshot your old settings. Let’s grab  which protocols are enabled, running the following from Terminal:

sudo serveradmin settings vpn:Servers:com.apple.ppp.pptp:enabled

sudo serveradmin settings vpn:Servers:com.apple.ppp.l2tp:enabled

Next, we’ll get the the IP ranges used so we can mimic those (or change them) in the new service:

sudo serveradmin settings vpn:Servers:com.apple.ppp.pptp:IPv4:DestAddressRanges

Now let’s grab the DNS servers handed out so those can be recreated:

sudo serveradmin settings vpn:Servers:com.apple.ppp.pptp:DNS:OfferedServerAddresses:_array_index
sudo serveradmin settings vpn:Servers:com.apple.ppp.l2tp:DNS:OfferedServerAddresses:_array_index

Finally, if you’re using L2TP, let’s grab the shared secret:

sudo serveradmin settings vpn:Servers:com.apple.ppp.l2tp:L2TP:IPSecSharedSecretValue

Once we have all of this information, we can configure the new server using the same settings. To install the VPN service on a Synology, first open the Synology and click on Package Center. From there, click on All and search for VPN.

Then click on the Install button for VPN. Once installed, open VPN Server from the application launcher in the upper left-hand corner of the screen. Initially, you’ll see a list of the services that can be run, which include the familiar PPTP and L2TP, along with the addition of Open VPN.

Before we potentially open up dangerous services to users we might not want to have access to, click on Privilege. Here, enable each service for each user that you want to have access to the VPN services.

Now that we can safely enable and disable each of the services, click on PPTP in the sidebar of the VPN Server app (if you want to provide PPTP-based services to clients).

Here, check the box for “Enable PPTP VPN server” and enter the following information:
  • Dynamic IP address: The first DHCP address that will be given to client computers
  • Maximum connection number: How many addresses that can be handed out (and therefore the maximum number of clients that can connect via PPTP).
  • Maximum number of connections with the same account: How many sessions a given account can have (1 is usually a good number here).
  • Authentication: Best to leave this at MS-CHAP v2 for compatibility, unless you find otherwise.  
  • Encryption: Leave as MPPE optional unless all clients can do MPPE and then you can enforce it for a stronger level of encryption.
  • MTU: 1400 is a good number.
  • Use manual DNS: If clients will connect to services via names once connected to the VPN, I’d put your primary DNS server in this field.

Click Apply and open port 1723 so clients can connect to the service. If you’ll be using L2TP over IPSec, click on “L2TP/IPSec” in the sidebar. The settings are the same as those above, but you can also add a preshared key to the mix. Go ahead and check the enable checkbox, provide the necessary settings from the PPTP list, and provide that key and then click on Apply. Note that the DHCP pools are different between the two services. Point UDP ports 1701, 500, and 4500 at the new server to allow for remote connections and then test that clients can connect.

That’s it. You’ve managed to get a new VPN setup and configured. Provided you used the same IP address, same client secret, and the ports are the same, you’ll then be able to probably use the same profile to install clients that you were using previously.

Install Directory Services on a Synology

People who have managed Open Directory and will be moving to Synology will note that directory services really aren’t nearly as complicated was we’ve made them out to be for years. This is because Apple was protecting us from doing silly things to break our implementations. It was also because Apple bundled a number of seemingly disparate technologies into ldap. It’s worth mentioning that LDAP on a Synology is LDAP. We’re not federating services, we’re not kerberizing services, we’re not augmenting schemas, etc. We can leverage the directory service to provide attributes though, and have that central phone book of user and group memberships we’ve come to depend on directory services to provide.

To get started, open the Package Center and search for Directory. Click Install for the Directory Server and the package will be installed on the Synology.

When the setup is complete, open the Directory Server from the launcher available in the upper right hand corner of the screen. 

The LDAP server isn’t yet running as you need to configure a few settings before starting. At the Settings screen, you can enable the LDAP service by checking the box to “Enable LDAP Service” and providing the hostname (FQDN) of the service along with a password.

Once the service is configured, you’ll have a base DN and a bind DN. These are generated based on the name provided in that FQDN field. For example, if the FQDN is “synology.krypted.com”, its Base DN will be “dc=synology,dc=krypted,dc=com”. And the Bind DN would add a lookup starting a root, then moving into the users container and then the hostname: uid=root,cn=users,dc=synology,dc=krypted,dc=com

If this is for internal use, then it’s all setup. If you’ll be binding external services to this LDAP instance, make sure to open ports 389 (for LDAP) and/or 636 (for LDAP over SSL) as well. 

Once you have information in the service, you’ll want to back it up. Click on Backup and Restore. Then click on Configure.

At the Configure screen, choose a destination.

I prefer using a directory I can then backup with another tool. Once you have defined a place to store your backups using the Destination field, choose a maximum number of backups and configure a schedule for the backups to run (by default backups run at midnight). Then click OK. You now have a functional LDAP service. To create Groups, click on the Group in the left sidebar. 

Here, you can easily create groups by clicking on the Create button. At the wizard, provide a group name and then enter the name of a group (accounting in this example).

Click Next, then Apply to finish creating the group. One you have created your groups, click on User to start entering your users. Click Create. At the User Information screen, enter the name, a description if needed, and the password for a user. You can also restrict password changes and set an expiration for accounts. Click Next to create the user. 

At the next screen, choose what groups the new user will be in and click Next.

Enter any extended attributes at the next screen, if you so choose (useful for directories).

Click Next and then Apply.

For smaller workgroups, you now have a functional LDAP service! If you’d like a nice gui to access more options, look at FUM ( 

https://github.com/futurice/futurice-ldap-user-manager ), LAM ( https://www.ldap-account-manager.org/lamcms/ ), LinID ( http://www.linid.org/welcome/index.html )or other tools. I wrote an article on LDAP SACLs awhile back, so I’ll try and track that down and update it for Synology soon!

Export data from Open Directory for migrating users and groups

Before we have this conversation, I want to give you some bad news. Your passwords aren’t going to migrate. The good news is that you only do directory services migrations every decade or two. The better news is that I’m not actually sure you need a directory service in the traditional sense that you’ve built directory services. With Apple’s Enterprise Connect and Nomad, we no longer need to bind in order to get Kerberos functionality. With MCX long-dead(ish) you’re now better off doing policies through configuration profiles. 

So where does that leave us? There are some options.
  • On Prem Active Directory. I can setup Active Directory in about 10 minutes. And I can be binding Mac clients to it. They’ll get their Kerberos TGTs and authenticate into services and the 90s will be as alive on your server as they are in Portland. Here’s the thing, and I kinda’ hate to say it, but no one ever got fired for doing things the old reliable way. 
  • OpenLDAP. There are some easy builds of OpenLDAP to deploy. You can build a new instance from scratch on a Mac (probably a bad idea) or on a very small Linux box. This is pretty easy, but to get all the cool stuff working, you might need some tweaking.
  • Appliances. I’m already working on an article for installing OpenLDAP on a Synology.
  • Microsoft Azure Active Directory. If you’re a primarily Microsoft shop, and one that is trying to go server-less, then this is probably for you. Problem is, I can’t guide you through binding a client to Active Directory in Azure just yet. 
  • Okta/Ping/other IAMs. Some of these can act as a directory service of sorts ( https://help.okta.com/en/prod/Content/Topics/Directory/About_Universal_Directory.htm ). As with Azure, you’re likely not going to bind to them (although Nomad has some interesting stuff if you feel like digging into that).
  • A hosted directory service provider (Directory as a Service) like Jumpcloud.
There are probably dozens of other options as well (please feel free to add them in the comments section of this article). No matter what you do, if you have more than a dozen or two users and groups, you’re going to want to export them. So let’s check out what that process looks like. The easy way to export data is to dump all of the services out with one quick command:

sudo slapconfig -backupdb ~/Desktop/slapexport/

This process produces the exact same results as exporting Open Directory from the Server App. To do so, open the Server app and click on the Open Directory entry. From there, click on the cog-wheel icon and choose the option to Archive Open Directory Master. 

When prompted, enter your directory administrator (e.g. diradmin) credentials.

Once you have authenticated, provide a path and a password to export the data.

Now you’ll see a sparse image in your export path. Open it to see the backup.ldif file.

That’s the main thing you’re looking for. The ldif file can be imported into another openldap system, or once you have an ldif file, you can also get that over into csv. To help with this, I wrote a little ldif to csv converter and posted it here.

Finally, you could export just users or groups, or specific objects from the Server App.

That option is more built for importing into other macOS servers, but if you’d like to try, click on Users in the left sidebar and then click on Export Users from the cog wheel icon towards the bottom of the screen.

Then select what to export and where to export the file to. 

You can also repeat this process for Groups, if needed.

Install DNS Services on Synology

DNS is an integral service to most modern networks. The Domain Name System, or DNS is comprised of hierarchical and decentralized Domain Name Servers, or DNS Servers. This is how we connect to computers and the websites that reside on computers by their names, rather than having to memorize the IP addresses of every single computer out there. So you get to type krypted.com and come to my website instead of typing the IP address. Or more likely, Facebook.com, but just because my website is older, I’m not mad about that. No really…

So you have a macOS Server and you need to take your DNS records out of it and move them to another solution. Luckily, DNS on any operating system is one of the easiest to manage. So let’s start by dumping all of our DNS records:

/Applications/Server.app/Contents/ServerRoot/System/Library/PrivateFrameworks/DNSManager.framework/dnsconfig list

    directory: /Library/Server/named
    allow-recursion: com.apple.ServerAdmin.DNS.public 
    allow-transfer: none 
                    allow-transfer: none 
                    allow-update: none 
                Resource Recs:
                        testalias.test.com (CNAME)
                        test.com (SOA)
                        test.com (NS)
                        test.com (MX)
                        test.test.com (A)
                Resource Recs:
                    no resource recs
                    allow-update: none 
                Resource Recs:
                        0.0.127.in-addr.arpa (SOA)
                        0.0.127.in-addr.arpa (NS)
                    allow-transfer: none 
                    allow-update: none 
                Resource Recs:
                        0.0.10.in-addr.arpa (SOA)
                        0.0.10.in-addr.arpa (NS)

Now that we have our records, let’s think of how to use them in the new server. In the above example, we list test.com as a zone. And in that zone we have an A record for test.test.com and a CNAME for testalias.test.com that points to test.test.com – but we don’t know where test.test.com resolves to. Each of those domains has a corresponding file that starts with db. followed by the name of the domain in the /Library/Server/named directory. So we can cat the test.com file as follows:

cat /Library/Server/named/db.test.com

test.com.       10800 IN SOA test.com. admin.test.com. (
     10800 IN NS test.test.com.
     10800 IN MX 0 test.test.com.
test.test.com.       10800 IN A
testalias.test.com.       10800 IN CNAME test.test.com.

Now we know the IP address that each record points to and can start building them out in other systems. If you only have 5-20 records, this is pretty quick and easy. If you have hundreds, then you’re in luck, as those db files per domain are portable between hosts. Some of the settings to look out for from macOS Server include:
  • Primary Zone: The DNS “Domain”. For example, www.krypted.com would likely have a primary zone of krypted.com.
  • Machine Record: An A record for a computer, or a record that tells DNS to resolve whatever name is indicated in the “machine” record to an IP address, whether the IP address is reachable or not.
  • Name Server: NS record, indicates the authoritative DNS server for each zone. If you only have one DNS server then this should be the server itself.
  • Reverse Zone: Zone that maps each name that IP addresses within the zone answer with. Reverse Zones are comprised of Reverse Mappings and each octal change in an IP scheme that has records mapped represents a new Reverse Zone.
  • Reverse Mapping: PTR record, or a record that indicates the name that should respond for a given IP address. These are automatically created for the first IP address listed in a Machine Record.
  • Alias Record: A CNAME, or a name that points to another name.
  • Service Record: Records that can hold special types of data that describe where to look for services for a given zone. For example, iCal can leverage service records so that users can just type the username and password during the setup process.
  • Mail Exchanger Record (aka MX record): Mail Exchanger, points to the IP address of the mail server for a given domain (aka Primary or Secondary Zone).
  • Secondary Zone: A read only copy of a zone that is copied from the server where it’s a Primary Zone when created and routinely through what is known as a Zone Transfer.
The settings for the domains are as follows:
  • allow-transfer Takes one or more address match list entry. Address match list entries consist of any of these forms: IP addresses, Subnets or Keywords.
  • allow-recursion Takes one or more address match list entry.
  • allow-update Takes one or more address match list entry.
  • allow-query Takes one or more address match list entry.
  • allow-query-cache Takes one or more address match list entry.
  • forwarders Takes one or more IP addresses, e.g.
  • directory Takes a directory path
  • tkey-gssapi-credential Takes a kerberos service principal
  • tkey-domain Takes a kerberos realm
  • update-policy Takes one complete update-policy entry where you can grant or deny various matched objects and specify the dentity of the user/machine that is allowed/disallowed to update.. You can also identify match-type (Type of match to be used in evaulating the entry) and match-name (Name used to match) as well as rr-types (Resource record types that can be updated)
Now, let’s get to setting up the new server. We’ll open the Synology and then click on Package Center. Then we’ll click All in the sidebar and search for DNS, as you can see below.

Click Install and the service will be installed on your NAS. Once installed, use the menu item in the upper left corner of the screen to bring up DNS Manager. Here, you can create your first zone. We’ll recreate test.com. To get started, click on Create and then Master Zone.

At the Master Zone screen, select Forward Zone if you’re creating a zone with a name or Reverse Zone if you’re creating a zone for IP addresses to resolve back to names (or PTR records). Since test.com is a name, we’ll select Forward Zone and then enter test.com in the “Domain name” field. Enter the IP address of the NAS in the “Master DNS server” field and leave the serial format as-is unless you have a good reason not to.

There are some options to secure connectivity to the service as well: 
  • Limit zone transfer: Restrict this option only to slave servers for each zone.
  • Limit source IP service: Restrict this option only to hosts that should be able to lookup records for the zone (which is usually everyone so this isn’t often used).
  • Enable slave zone notification: Identify all the slave servers so they get a notification about changes to zone files and can update their files based on those on the server.
  • Limit zone update: Only specify other servers that are allowed to update the zone files on your server.
Click OK when you’ve configured the zone as you’d like.

Double-click the zone to load a list of records and create new ones. 

Click Create to see a list of record types:

Record types include the following:
  • A Type: Resolve a name to an IPv4 address
  • AAAA Type: Resolve a name to an IPv6 address
  • CNAME: Resolve a name to a name
  • MX: Define the mail server for a domain
  • NS: Define DNS servers for a domain
  • SPF: Define what mail servers are allowed to send mail from a domain
  • SRV: Service records (e.g. the Active Directory or Exchange server for a domain)
  • TXT: Text records
  • CAA: Define the Certificate Authorities (CAs) for a domain
Click A Type to create that test.test.com record.

At the record screen, provide the hostname, along with the IP address that the name should resolve to. Notice that the TTL is a number of seconds. This is how many seconds before another DNS server expires their record. So when they cache them, they aren’t looking the records up against your server every time a client needs to resolve the address. I like the number provided, but when I’m about to move a service I’ll usually come back and reduce that a few days before the move. The nice thing about a high number of seconds before the next refresh though, is it can save on your bandwidth and on the bandwidth of the servers looking to yours to refresh their records. Once you’ve configured the record, click OK.

Click on Create and then CNAME. Enter the name that you’re pointing to another record (in this case CNAMEtest) in the Name: field and then the name that it’s pointing to (in this case test.test.com) in the Cononical Name: field. Click OK.

Now let’s get that MX record created. Click Create and select MX. Enter the name of the server you want to get mail (in this case test.test.com will be our mail server. Then provide a TTL (I usually use lower numbers for mail servers), the priority (if this is the only server I usually use 0 but if there’s a backup then I’ll use a number like 20), and finally the name of the domain. Click OK.

You’ll you can see all of your records. I know that Apple was always tinkering with the Server app to make DNS records display differently, trying to hide the complexity. But to be honest, I always considered this type of view (which is standard amongst most network appliances) to be much more logical. That might be because I’m just used to looking at db files back in the pre-GUI days. But it makes sense to me. 

Notice in the sidebar, you have an option for Resolution. This is if the server is going to be used to resolve addresses upstream. What are those upstream servers. This is where you configure them. Don’t enable this option if the DNS server is only used by external clients to resolve names hosted on the server. Do use this if there will be clients on your network attempting to resolve against your server.

Use the Views option to configure bind views. We’ll cover this at some point, but since this article is getting a bit long, let’s just say that this is where you configure different zone files for different subnets based on the source of the subnet. Useful if you want to use the same DNS server to host external and internal addressing, and you want the internals to point to LAN addresses and the externals to point to WAN addresses.

Finally, if this DNS server will be providing services to external hosts, then point port 53 to the new server and set the name server record to the IP address on the WAN with the registrar.