Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSMacOSX / PreferencePane / BonjourPrefTool / BonjourPrefTool.m
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