Jon
Jon

Reputation: 1489

How can I tell programmatically if a Mac OS X machine is bound to an Active Directory domain?

This command: dsconfigad -show does what I need but I need admin rights to run it.

The above command outputs some information I'm interested in:

You are bound to Active Directory:
      Active Directory Forest        = xx.xxxxxx.local
      Active Directory Domain        = xx.xxxxxx.local
      Computer Account               = (computer name)

I'd like to be able to get the Active Directory Domain seen above programatically, and preferably without having to have sudo permissions.

Any suggestions? I've browsed the Open Directory docs and it is not entirely obvious to me how to do this. I also tried some code examples just to query the AD for something without success... I'll continue to work on it but I was hoping someone here had some knowledge to share.

Upvotes: 5

Views: 3186

Answers (2)

Paul Nelson
Paul Nelson

Reputation: 61

If you are searching for this, here is some Swift code returning extra info with actual bound computer name. If nil is returned the Mac isn't bound.

import Foundation
import OpenDirectory

struct ComputerAccount {
    let name: String
    let domain: String
    let distinguishedName: String?
    let dnsName: String?
    let networkAddresses: [String]
    let smbsid: String?
    
    static func with(record: ODRecord, domain: String) -> ComputerAccount {
        // note: record.recordName has a dollar sign appended to it
        // instead of assuming that, we just use the real name if we can get it
        let computerName: String
        if let name = try? record.values(forAttribute: "dsAttrTypeStandard:RealName").first as? String {
            computerName = name
        } else {
            computerName = record.recordName
        }
        let distinguishedName = try? record.values(forAttribute: "dsAttrTypeNative:distinguishedName").first as? String
        let dnsName = try? record.values(forAttribute: kODAttributeTypeDNSName).first as? String
        let networkAddresses = try? record.values(forAttribute: "dsAttrTypeNative:networkAddress") as? [String]
        let smbsid = try? record.values(forAttribute: kODAttributeTypeSMBSID).first as? String
        return ComputerAccount(name: computerName, domain: domain, distinguishedName: distinguishedName, dnsName: dnsName, networkAddresses: networkAddresses ?? [], smbsid: smbsid)
    }
}

func activeDirectoryComputerAccount() -> ComputerAccount? {
    var trustAccounts = [String]()
    let session = ODSession.default()!
    guard let activeDirectory = try? ODNode(session: session, name: "/Active Directory") else { return nil }
    guard let domainNames = try? activeDirectory.subnodeNames() as? [String] else { return nil }
    for domainName in domainNames {
        if let configuration = session.configuration(forNodename: domainName) {
            if let trustAccount = configuration.trustAccount {
                trustAccounts.append(trustAccount)
                if let globalCatalog = try? ODNode(session: session, name: domainName + "/Global Catalog") {
                    let attrs = ["dsAttrTypeStandard:RealName",
                                 "dsAttrTypeNative:distinguishedName",
                                 "dsAttrTypeNative:networkAddress",
                                 kODAttributeTypeSMBSID]
                    if let record = try? globalCatalog.record(withRecordType: kODRecordTypeComputers, 
                                                              name: trustAccount,
                                                              attributes: attrs) {
                        let dom = domainName.components(separatedBy: "/").last ?? ""
                        return ComputerAccount.with(record: record, domain: dom)
                    }
                }
            }
        }
    }
    return nil
}

Upvotes: 0

Simon Urbanek
Simon Urbanek

Reputation: 13932

Without node authentication you should at least see if AD is bound by looking at the active OD plugins - it should include AD if it is bound. It may or may not show the domain (typically it does for LDAP but I don't have AD to test here so your mileage may vary):

Swift

import Foundation
import OpenDirectory

let mySession = ODSession.default()
do {
    print(try mySession?.nodeNames())
}
catch {
    print("error: \(error)")
}

Objective-C

#include <Foundation/Foundation.h>
#include <OpenDirectory/OpenDirectory.h>

int main(int ac, char **av) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  ODSession *mySession = [ODSession defaultSession];
  NSError *err = 0;
  NSArray *nodeNames = [mySession nodeNamesAndReturnError:&err];
  if (err) NSLog(@"error: %@", err);
  if (nodeNames) NSLog(@"nodes: %@", nodeNames);
  [pool release];
  return 0;
}

Upvotes: 2

Related Questions