]>
Commit | Line | Data |
---|---|---|
12c5fa7a A |
1 | /* |
2 | * | |
3 | * Copyright (c) 2016 Apple Inc. All rights reserved. | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | #import "BonjourPrefTool.h" | |
19 | #import "BonjourSCStore.h" | |
20 | #import <Security/Security.h> | |
21 | #import <dns_sd.h> | |
22 | ||
23 | #define DYNDNS_KEYCHAIN_DESCRIPTION "Dynamic DNS Key" | |
24 | ||
25 | #pragma mark - Keychain Funcs | |
26 | ||
27 | static SecAccessRef | |
28 | MyMakeUidAccess(uid_t uid) | |
29 | { | |
30 | // make the "uid/gid" ACL subject | |
31 | // this is a CSSM_LIST_ELEMENT chain | |
32 | CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = { | |
33 | CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, // selector version | |
34 | CSSM_ACL_MATCH_UID, // set mask: match uids (only) | |
35 | uid, // uid to match | |
36 | 0 // gid (not matched here) | |
37 | }; | |
38 | CSSM_LIST_ELEMENT subject2 = { NULL, 0, 0, {{0,0,0}} }; | |
39 | subject2.Element.Word.Data = (UInt8 *)&selector; | |
40 | subject2.Element.Word.Length = sizeof(selector); | |
41 | CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID, {{0,0,0}} }; | |
42 | ||
43 | ||
44 | // rights granted (replace with individual list if desired) | |
45 | CSSM_ACL_AUTHORIZATION_TAG rights[] = { | |
46 | CSSM_ACL_AUTHORIZATION_ANY // everything | |
47 | }; | |
48 | // owner component (right to change ACL) | |
49 | CSSM_ACL_OWNER_PROTOTYPE owner = { | |
50 | // TypedSubject | |
51 | { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, | |
52 | // Delegate | |
53 | false | |
54 | }; | |
55 | // ACL entries (any number, just one here) | |
56 | CSSM_ACL_ENTRY_INFO acls = | |
57 | { | |
58 | // CSSM_ACL_ENTRY_PROTOTYPE | |
59 | { | |
60 | { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, // TypedSubject | |
61 | false, // Delegate | |
62 | { sizeof(rights) / sizeof(rights[0]), rights }, // Authorization rights for this entry | |
63 | { { 0, 0 }, { 0, 0 } }, // CSSM_ACL_VALIDITY_PERIOD | |
64 | "" // CSSM_STRING EntryTag | |
65 | }, | |
66 | // CSSM_ACL_HANDLE | |
67 | 0 | |
68 | }; | |
69 | ||
70 | SecAccessRef a = NULL; | |
71 | (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &a); | |
72 | return a; | |
73 | } | |
74 | ||
75 | static OSStatus | |
76 | MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef a, UInt32 serviceNameLength, const char *serviceName, | |
77 | UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData) | |
78 | { | |
79 | char * description = DYNDNS_KEYCHAIN_DESCRIPTION; | |
80 | UInt32 descriptionLength = strlen(DYNDNS_KEYCHAIN_DESCRIPTION); | |
81 | UInt32 type = 'ddns'; | |
82 | UInt32 creator = 'ddns'; | |
83 | UInt32 typeLength = sizeof(type); | |
84 | UInt32 creatorLength = sizeof(creator); | |
85 | OSStatus err; | |
86 | ||
87 | // set up attribute vector (each attribute consists of {tag, length, pointer}) | |
88 | SecKeychainAttribute attrs[] = { { kSecLabelItemAttr, serviceNameLength, (char *)serviceName }, | |
89 | { kSecAccountItemAttr, accountNameLength, (char *)accountName }, | |
90 | { kSecServiceItemAttr, serviceNameLength, (char *)serviceName }, | |
91 | { kSecDescriptionItemAttr, descriptionLength, (char *)description }, | |
92 | { kSecTypeItemAttr, typeLength, (UInt32 *)&type }, | |
93 | { kSecCreatorItemAttr, creatorLength, (UInt32 *)&creator } }; | |
94 | SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; | |
95 | ||
96 | err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, a, NULL); | |
97 | return err; | |
98 | } | |
99 | ||
100 | static int | |
101 | SetKeychainEntry(NSDictionary * secretDictionary) | |
102 | // Create a new entry in system keychain, or replace existing | |
103 | { | |
104 | CFStringRef keyNameString; | |
105 | CFStringRef domainString; | |
106 | CFStringRef secretString; | |
107 | SecKeychainItemRef item = NULL; | |
108 | int result = 0; | |
109 | char keyname[kDNSServiceMaxDomainName]; | |
110 | char domain[kDNSServiceMaxDomainName]; | |
111 | char secret[kDNSServiceMaxDomainName]; | |
112 | ||
113 | keyNameString = (__bridge CFStringRef)[secretDictionary objectForKey:(NSString *)SC_DYNDNS_KEYNAME_KEY]; | |
114 | require(keyNameString != NULL, exit); | |
115 | ||
116 | domainString = (__bridge CFStringRef)[secretDictionary objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; | |
117 | require(domainString != NULL, exit); | |
118 | ||
119 | secretString = (__bridge CFStringRef)[secretDictionary objectForKey:(NSString *)SC_DYNDNS_SECRET_KEY]; | |
120 | require(secretString != NULL, exit); | |
121 | ||
122 | CFStringGetCString(keyNameString, keyname, kDNSServiceMaxDomainName, kCFStringEncodingUTF8); | |
123 | CFStringGetCString(domainString, domain, kDNSServiceMaxDomainName, kCFStringEncodingUTF8); | |
124 | CFStringGetCString(secretString, secret, kDNSServiceMaxDomainName, kCFStringEncodingUTF8); | |
125 | ||
126 | result = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); | |
127 | if (result == noErr) | |
128 | { | |
129 | result = SecKeychainFindGenericPassword(NULL, strlen(domain), domain, 0, NULL, 0, NULL, &item); | |
130 | if (result == noErr) | |
131 | { | |
132 | result = SecKeychainItemDelete(item); | |
133 | if (result != noErr) fprintf(stderr, "SecKeychainItemDelete returned %d\n", result); | |
134 | } | |
135 | ||
136 | result = MyAddDynamicDNSPassword(NULL, MyMakeUidAccess(0), strlen(domain), domain, strlen(keyname)+1, keyname, strlen(secret)+1, secret); | |
137 | if (result != noErr) fprintf(stderr, "MyAddDynamicDNSPassword returned %d\n", result); | |
138 | if (item) CFRelease(item); | |
139 | } | |
140 | ||
141 | exit: | |
142 | return result; | |
143 | } | |
144 | ||
145 | ||
146 | @implementation BonjourPrefTool | |
147 | ||
148 | - (void) setKeychainEntry:(NSDictionary *_Nonnull)secretDictionary withStatus:(void (^ _Nonnull)(OSStatus))status | |
149 | { | |
150 | OSStatus result; | |
151 | ||
152 | result = SetKeychainEntry (secretDictionary); | |
153 | // NSLog(@"setKeychainEntry: %@ result: %d", secretDictionary, result); | |
154 | ||
155 | status (result); | |
156 | } | |
157 | ||
158 | @end |