source: rtems-libbsd/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m @ f761b29

55-freebsd-126-freebsd-12
Last change on this file since f761b29 was f761b29, checked in by Sebastian Huber <sebastian.huber@…>, on 09/19/18 at 06:52:21

mDNSResponder: Update to v625.41.2

The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-625.41.2.tar.gz

Update #3522.

  • Property mode set to 100644
File size: 15.3 KB
Line 
1/*
2    File: ddnswriteconfig.m
3
4    Abstract: Setuid root tool invoked by Preference Pane to perform
5    privileged accesses to system configuration preferences and the system keychain.
6    Invoked by PrivilegedOperations.c.
7
8    Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
9
10    Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
11    ("Apple") in consideration of your agreement to the following terms, and your
12    use, installation, modification or redistribution of this Apple software
13    constitutes acceptance of these terms.  If you do not agree with these terms,
14    please do not use, install, modify or redistribute this Apple software.
15
16    In consideration of your agreement to abide by the following terms, and subject
17    to these terms, Apple grants you a personal, non-exclusive license, under Apple's
18    copyrights in this original Apple software (the "Apple Software"), to use,
19    reproduce, modify and redistribute the Apple Software, with or without
20    modifications, in source and/or binary forms; provided that if you redistribute
21    the Apple Software in its entirety and without modifications, you must retain
22    this notice and the following text and disclaimers in all such redistributions of
23    the Apple Software.  Neither the name, trademarks, service marks or logos of
24    Apple Computer, Inc. may be used to endorse or promote products derived from the
25    Apple Software without specific prior written permission from Apple.  Except as
26    expressly stated in this notice, no other rights or licenses, express or implied,
27    are granted by Apple herein, including but not limited to any patent rights that
28    may be infringed by your derivative works or by other works in which the Apple
29    Software may be incorporated.
30
31    The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
32    WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
33    WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34    PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
35    COMBINATION WITH YOUR PRODUCTS.
36
37    IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
38    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
39    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40    ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
41    OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
42    (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
43    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 */
45
46
47#import "PrivilegedOperations.h"
48#import "ConfigurationRights.h"
49
50#import <stdio.h>
51#import <stdint.h>
52#import <stdlib.h>
53#import <unistd.h>
54#import <fcntl.h>
55#import <errno.h>
56#import <sys/types.h>
57#import <sys/stat.h>
58#import <sys/mman.h>
59#import <mach-o/dyld.h>
60#import <dns_sd.h>
61#import <AssertMacros.h>
62#import <Security/Security.h>
63#import <CoreServices/CoreServices.h>
64#import <CoreFoundation/CoreFoundation.h>
65#import <SystemConfiguration/SystemConfiguration.h>
66#import <Foundation/Foundation.h>
67
68
69static AuthorizationRef gAuthRef = 0;
70
71static OSStatus
72WriteArrayToDynDNS(CFStringRef arrayKey, CFArrayRef domainArray)
73{
74    SCPreferencesRef        store;
75        OSStatus                                err = noErr;
76        CFDictionaryRef                 origDict;
77        CFMutableDictionaryRef  dict = NULL;
78        Boolean                                 result;
79        CFStringRef                             scKey = CFSTR("/System/Network/DynamicDNS");
80       
81
82        // Add domain to the array member ("arrayKey") of the DynamicDNS dictionary
83        // Will replace duplicate, at head of list
84        // At this point, we only support a single-item list
85        store = SCPreferencesCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL);
86        require_action(store != NULL, SysConfigErr, err=paramErr;);
87        require_action(true == SCPreferencesLock( store, true), LockFailed, err=coreFoundationUnknownErr;);
88
89        origDict = SCPreferencesPathGetValue(store, scKey);
90        if (origDict)
91        {
92                dict = CFDictionaryCreateMutableCopy(NULL, 0, origDict);
93        }
94   
95        if (!dict)
96        {
97                dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
98        }
99        require_action( dict != NULL, NoDict, err=memFullErr;);
100
101        if (CFArrayGetCount(domainArray) > 0)
102        {
103                CFDictionarySetValue(dict, arrayKey, domainArray);
104        }
105        else
106        {
107                CFDictionaryRemoveValue(dict, arrayKey);
108        }
109       
110        result = SCPreferencesPathSetValue(store, scKey, dict);
111        require_action(result, SCError, err=kernelPrivilegeErr;);
112
113        result = SCPreferencesCommitChanges(store);
114        require_action(result, SCError, err=kernelPrivilegeErr;);
115        result = SCPreferencesApplyChanges(store);
116        require_action(result, SCError, err=kernelPrivilegeErr;);
117
118SCError:
119        CFRelease(dict);
120NoDict:
121        SCPreferencesUnlock(store);
122LockFailed:
123        CFRelease(store);
124SysConfigErr:
125        return err;
126}
127
128
129static int
130readTaggedBlock(int fd, u_int32_t *pTag, u_int32_t *pLen, char **ppBuff)
131// Read tag, block len and block data from stream and return. Dealloc *ppBuff via free().
132{
133        ssize_t         num;
134        u_int32_t       tag, len;               // Don't use ssize_t because that's different on 32- vs. 64-bit
135        int                     result = 0;
136
137        num = read(fd, &tag, sizeof tag);
138        require_action(num == sizeof tag, GetTagFailed, result = -1;);
139        num = read(fd, &len, sizeof len);
140        require_action(num == sizeof len, GetLenFailed, result = -1;);
141
142        *ppBuff = (char*) malloc( len);
143        require_action(*ppBuff != NULL, AllocFailed, result = -1;);
144
145        num = read(fd, *ppBuff, len);
146        if (num == (ssize_t)len)
147        {
148                *pTag = tag;
149                *pLen = len;
150        }
151        else
152        {
153                free(*ppBuff);
154                result = -1;
155        }
156
157AllocFailed:
158GetLenFailed:
159GetTagFailed:
160        return result;
161}
162
163
164
165static int
166SetAuthInfo( int fd)
167{
168        int                             result = 0;
169        u_int32_t               tag, len;
170        char                    *p;
171
172        result = readTaggedBlock( fd, &tag, &len, &p);
173        require( result == 0, ReadParamsFailed);
174        require( len == sizeof(AuthorizationExternalForm), ReadParamsFailed);
175        require( len == kAuthorizationExternalFormLength, ReadParamsFailed);
176
177        if (gAuthRef != 0)
178        {
179                (void) AuthorizationFree(gAuthRef, kAuthorizationFlagDefaults);
180                gAuthRef = 0;
181        }
182
183        result = AuthorizationCreateFromExternalForm((AuthorizationExternalForm*) p, &gAuthRef);
184
185        free( p);
186ReadParamsFailed:
187        return result;
188}
189
190
191static int
192HandleWriteDomain(int fd, int domainType)
193{
194        CFArrayRef      domainArray;
195        CFDataRef       domainData;
196        int                             result = 0;
197        u_int32_t               tag, len;
198        char                    *p;
199
200        AuthorizationItem       scAuth = { UPDATE_SC_RIGHT, 0, NULL, 0 };
201        AuthorizationRights     authSet = { 1, &scAuth };
202
203        if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags)0, NULL)))
204                return result;
205
206        result = readTaggedBlock(fd, &tag, &len, &p);
207        require(result == 0, ReadParamsFailed);
208
209        domainData = CFDataCreate(NULL, (UInt8 *)p, len);
210        domainArray = (CFArrayRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)domainData];
211        CFRelease(domainData);
212        free(p);
213       
214    if (domainType)
215    {
216        result = WriteArrayToDynDNS(SC_DYNDNS_REGDOMAINS_KEY, domainArray);
217    }
218    else
219    {
220        result = WriteArrayToDynDNS(SC_DYNDNS_BROWSEDOMAINS_KEY, domainArray);
221    }
222
223ReadParamsFailed:
224        return result;
225}
226
227
228static int
229HandleWriteHostname(int fd)
230{
231        CFArrayRef      domainArray;
232        CFDataRef       domainData;
233        int                             result = 0;
234        u_int32_t               tag, len;
235        char                    *p;
236
237        AuthorizationItem       scAuth = { UPDATE_SC_RIGHT, 0, NULL, 0 };
238        AuthorizationRights     authSet = { 1, &scAuth };
239
240        if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags) 0, NULL)))
241                return result;
242
243        result = readTaggedBlock(fd, &tag, &len, &p);
244        require(result == 0, ReadParamsFailed);
245
246        domainData = CFDataCreate(NULL, (const UInt8 *)p, len);
247        domainArray = (CFArrayRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)domainData];
248        result = WriteArrayToDynDNS(SC_DYNDNS_HOSTNAMES_KEY, domainArray);
249        CFRelease(domainData);
250        free(p);
251       
252ReadParamsFailed:
253        return result;
254}
255
256
257static SecAccessRef
258MyMakeUidAccess(uid_t uid)
259{
260        // make the "uid/gid" ACL subject
261        // this is a CSSM_LIST_ELEMENT chain
262        CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = {
263                CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION,      // selector version
264                CSSM_ACL_MATCH_UID,     // set mask: match uids (only)
265                uid,                            // uid to match
266                0                                       // gid (not matched here)
267        };
268        CSSM_LIST_ELEMENT subject2 = { NULL, 0, 0, {{0,0,0}} };
269        subject2.Element.Word.Data = (UInt8 *)&selector;
270        subject2.Element.Word.Length = sizeof(selector);
271        CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID, {{0,0,0}} };
272
273
274        // rights granted (replace with individual list if desired)
275        CSSM_ACL_AUTHORIZATION_TAG rights[] = {
276                CSSM_ACL_AUTHORIZATION_ANY      // everything
277        };
278        // owner component (right to change ACL)
279        CSSM_ACL_OWNER_PROTOTYPE owner = {
280                // TypedSubject
281                { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
282                // Delegate
283                false
284        };
285        // ACL entries (any number, just one here)
286        CSSM_ACL_ENTRY_INFO acls =
287                {
288                // CSSM_ACL_ENTRY_PROTOTYPE
289                        {
290                        { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, // TypedSubject
291                        false,  // Delegate
292                        { sizeof(rights) / sizeof(rights[0]), rights }, // Authorization rights for this entry
293                        { { 0, 0 }, { 0, 0 } }, // CSSM_ACL_VALIDITY_PERIOD
294                        "" // CSSM_STRING EntryTag
295                        },
296                // CSSM_ACL_HANDLE
297                0
298                };
299
300        SecAccessRef a = NULL;
301        (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &a);
302        return a;
303}
304
305
306static OSStatus
307MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef a, UInt32 serviceNameLength, const char *serviceName,
308    UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData)
309{
310        char * description       = DYNDNS_KEYCHAIN_DESCRIPTION;
311        UInt32 descriptionLength = strlen(DYNDNS_KEYCHAIN_DESCRIPTION);
312        UInt32 type              = 'ddns';
313        UInt32 creator           = 'ddns';
314        UInt32 typeLength        = sizeof(type);
315        UInt32 creatorLength     = sizeof(creator);
316    OSStatus err;
317       
318        // set up attribute vector (each attribute consists of {tag, length, pointer})
319        SecKeychainAttribute attrs[] = { { kSecLabelItemAttr,       serviceNameLength,   (char *)serviceName },
320                                     { kSecAccountItemAttr,     accountNameLength,   (char *)accountName },
321                                     { kSecServiceItemAttr,     serviceNameLength,   (char *)serviceName },
322                                     { kSecDescriptionItemAttr, descriptionLength,   (char *)description },
323                                     { kSecTypeItemAttr,               typeLength, (UInt32 *)&type       },
324                                     { kSecCreatorItemAttr,         creatorLength, (UInt32 *)&creator    } };
325        SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
326
327        err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, a, NULL);
328    return err;
329}
330
331
332static int
333SetKeychainEntry(int fd)
334// Create a new entry in system keychain, or replace existing
335{
336        CFDataRef           secretData;
337        CFDictionaryRef     secretDictionary;
338        CFStringRef         keyNameString;
339        CFStringRef         domainString;
340        CFStringRef         secretString;
341        SecKeychainItemRef      item = NULL;
342        int                                     result = 0;
343        u_int32_t                       tag, len;
344        char                            *p;
345        char                keyname[kDNSServiceMaxDomainName];
346        char                domain[kDNSServiceMaxDomainName];
347        char                secret[kDNSServiceMaxDomainName];
348
349        AuthorizationItem       kcAuth = { EDIT_SYS_KEYCHAIN_RIGHT, 0, NULL, 0 };
350        AuthorizationRights     authSet = { 1, &kcAuth };
351
352        if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags)0, NULL)))
353                return result;
354
355        result = readTaggedBlock(fd, &tag, &len, &p);
356        require_noerr(result, ReadParamsFailed);
357
358        secretData = CFDataCreate(NULL, (UInt8 *)p, len);
359        secretDictionary = (CFDictionaryRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)secretData];
360        CFRelease(secretData);
361        free(p);
362
363        keyNameString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_KEYNAME_KEY);
364        assert(keyNameString != NULL);
365       
366        domainString  = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_DOMAIN_KEY);
367        assert(domainString != NULL);
368       
369        secretString  = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_SECRET_KEY);
370        assert(secretString != NULL);
371                       
372        CFStringGetCString(keyNameString, keyname, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
373        CFStringGetCString(domainString,   domain, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
374        CFStringGetCString(secretString,   secret, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
375
376        result = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
377        if (result == noErr)
378        {
379                result = SecKeychainFindGenericPassword(NULL, strlen(domain), domain, 0, NULL, 0, NULL, &item);
380                if (result == noErr)
381                {
382                        result = SecKeychainItemDelete(item);
383                        if (result != noErr) fprintf(stderr, "SecKeychainItemDelete returned %d\n", result);
384                }
385                         
386                result = MyAddDynamicDNSPassword(NULL, MyMakeUidAccess(0), strlen(domain), domain, strlen(keyname)+1, keyname, strlen(secret)+1, secret);
387                if (result != noErr) fprintf(stderr, "MyAddDynamicDNSPassword returned %d\n", result);
388                if (item) CFRelease(item);
389        }
390
391ReadParamsFailed:
392        return result;
393}
394
395
396int     main( int argc, char **argv)
397/* argv[0] is the exec path; argv[1] is a fd for input data; argv[2]... are operation codes.
398   The tool supports the following operations:
399        V               -- exit with status PRIV_OP_TOOL_VERS
400        A               -- read AuthInfo from input pipe
401        Wd              -- write registration domain to dynamic store
402        Wb              -- write browse domain to dynamic store
403        Wh              -- write hostname to dynamic store
404        Wk              -- write keychain entry for given account name
405*/
406{
407        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
408        int     commFD = -1, iArg, result = 0;
409
410        if ( 0 != seteuid( 0))
411                return -1;
412
413        if ( argc == 3 && 0 == strcmp( argv[2], "V"))
414                return PRIV_OP_TOOL_VERS;
415
416        if ( argc > 1)
417        {
418                commFD = strtol( argv[1], NULL, 0);
419                lseek( commFD, 0, SEEK_SET);
420        }
421        for ( iArg = 2; iArg < argc && result == 0; iArg++)
422        {
423                if ( 0 == strcmp( "A", argv[ iArg]))    // get auth info
424                {
425                        result = SetAuthInfo( commFD);
426                }
427                else if ( 0 == strcmp( "Wd", argv[ iArg]))      // Write registration domain
428                {
429                        result = HandleWriteDomain( commFD, 1);
430                }
431        else if ( 0 == strcmp( "Wb", argv[ iArg]))      // Write browse domain
432                {
433                        result = HandleWriteDomain( commFD, 0);
434                }
435                else if ( 0 == strcmp( "Wh", argv[ iArg]))      // Write hostname
436                {
437                        result = HandleWriteHostname( commFD);
438                }
439                else if ( 0 == strcmp( "Wk", argv[ iArg]))      // Write keychain entry
440                {
441                        result = SetKeychainEntry( commFD);
442                }
443        }
444        [pool release];
445        return result;
446}
447
448// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
449// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
450// To expand "version" to its value before making the string, use STRINGIFY(version) instead
451#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
452#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
453
454// NOT static -- otherwise the compiler may optimize it out
455// The "@(#) " pattern is a special prefix the "what" command looks for
456const char VersionString_SCCS[] = "@(#) ddnswriteconfig " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
457
458#if _BUILDING_XCODE_PROJECT_
459// If the process crashes, then this string will be magically included in the automatically-generated crash log
460const char *__crashreporter_info__ = VersionString_SCCS + 5;
461asm(".desc ___crashreporter_info__, 0x10");
462#endif
Note: See TracBrowser for help on using the repository browser.