blob: 8d5c7325884078613602c2a9b266775850acd811 [file] [log] [blame]
Hector Carmonac3565bc42019-02-01 23:31:211// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/enterprise_util.h"
6
7#import <OpenDirectory/OpenDirectory.h>
8
9#include "base/logging.h"
10#include "base/mac/foundation_util.h"
11#include "base/mac/sdk_forward_declarations.h"
12
13namespace base {
14
15bool IsMachineExternallyManaged() {
16 @autoreleasepool {
17 ODSession* session = [ODSession defaultSession];
18 if (session == nil) {
19 DLOG(WARNING) << "ODSession default session is nil.";
20 return false;
21 }
22
23 NSError* error = nil;
24
25 NSArray<NSString*>* all_node_names =
26 [session nodeNamesAndReturnError:&error];
27 if (!all_node_names) {
28 DLOG(WARNING) << "ODSession failed to give node names: "
29 << error.localizedDescription.UTF8String;
30 return false;
31 }
32
33 NSUInteger num_nodes = all_node_names.count;
34 if (num_nodes < 3) {
35 DLOG(WARNING) << "ODSession returned too few node names: "
36 << all_node_names.description.UTF8String;
37 return false;
38 }
39
40 if (num_nodes > 3) {
41 // Non-enterprise machines have:"/Search", "/Search/Contacts",
42 // "/Local/Default". Everything else would be enterprise management.
43 return true;
44 }
45
46 ODNode* node = [ODNode nodeWithSession:session
47 type:kODNodeTypeAuthentication
48 error:&error];
49 if (node == nil) {
50 DLOG(WARNING) << "ODSession cannot obtain the authentication node: "
51 << error.localizedDescription.UTF8String;
52 return false;
53 }
54
55 // Now check the currently logged on user.
56 ODQuery* query = [ODQuery queryWithNode:node
57 forRecordTypes:kODRecordTypeUsers
58 attribute:kODAttributeTypeRecordName
59 matchType:kODMatchEqualTo
60 queryValues:NSUserName()
61 returnAttributes:kODAttributeTypeAllAttributes
62 maximumResults:0
63 error:&error];
64 if (query == nil) {
65 DLOG(WARNING) << "ODSession cannot create user query: "
66 << base::mac::NSToCFCast(error);
67 return false;
68 }
69
70 NSArray* results = [query resultsAllowingPartial:NO error:&error];
71 if (!results) {
72 DLOG(WARNING) << "ODSession cannot obtain current user node: "
73 << error.localizedDescription.UTF8String;
74 return false;
75 }
76 if (results.count != 1) {
77 DLOG(WARNING) << @"ODSession unexpected number of user nodes: "
78 << results.count;
79 }
80 for (id element in results) {
81 ODRecord* record = base::mac::ObjCCastStrict<ODRecord>(element);
82 NSArray* attributes =
83 [record valuesForAttribute:kODAttributeTypeMetaRecordName error:nil];
84 for (id attribute in attributes) {
85 NSString* attribute_value =
86 base::mac::ObjCCastStrict<NSString>(attribute);
87 // Example: "uid=johnsmith,ou=People,dc=chromium,dc=org
88 NSRange domain_controller =
89 [attribute_value rangeOfString:@"(^|,)\\s*dc="
90 options:NSRegularExpressionSearch];
91 if (domain_controller.length > 0) {
92 return true;
93 }
94 }
95
96 // Scan alternative identities.
97 attributes =
98 [record valuesForAttribute:kODAttributeTypeAltSecurityIdentities
99 error:nil];
100 for (id attribute in attributes) {
101 NSString* attribute_value =
102 base::mac::ObjCCastStrict<NSString>(attribute);
103 NSRange icloud =
104 [attribute_value rangeOfString:@"CN=com.apple.idms.appleid.prd"
105 options:NSCaseInsensitiveSearch];
106 if (!icloud.length) {
107 // Any alternative identity that is not iCloud is likely enterprise
108 // management.
109 return true;
110 }
111 }
112 }
113 }
114 return false;
115}
116
117} // namespace base