2 * Copyright (c) 2003-2004,2006-2007,2009-2010,2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
28 #include <Security/AuthorizationPriv.h>
29 #include <utilities/SecCFRelease.h>
32 #include "security_tool.h"
36 static AuthorizationRef
37 read_auth_ref_from_stdin()
39 AuthorizationRef auth_ref
= NULL
;
40 AuthorizationExternalForm extform
;
43 while (kAuthorizationExternalFormLength
!= (bytes_read
= read(STDIN_FILENO
, &extform
, kAuthorizationExternalFormLength
)))
45 if ((bytes_read
== -1) && ((errno
!= EAGAIN
) || (errno
!= EINTR
)))
48 if (bytes_read
!= kAuthorizationExternalFormLength
)
49 fprintf(stderr
, "ERR: Failed to read authref\n");
51 if (AuthorizationCreateFromExternalForm(&extform
, &auth_ref
))
52 fprintf(stderr
, "ERR: Failed to internalize authref\n");
60 write_auth_ref_to_stdout(AuthorizationRef auth_ref
)
62 AuthorizationExternalForm extform
;
63 ssize_t bytes_written
;
65 if (AuthorizationMakeExternalForm(auth_ref
, &extform
))
68 while (kAuthorizationExternalFormLength
!= (bytes_written
= write(STDOUT_FILENO
, &extform
, kAuthorizationExternalFormLength
)))
70 if ((bytes_written
== -1) && ((errno
!= EAGAIN
) || (errno
!= EINTR
)))
74 if (bytes_written
== kAuthorizationExternalFormLength
)
81 write_dict_to_stdout(CFDictionaryRef dict
)
86 CFDataRef right_definition_xml
= CFPropertyListCreateXMLData(NULL
, dict
);
88 if (!right_definition_xml
)
91 write(STDOUT_FILENO
, CFDataGetBytePtr(right_definition_xml
), CFDataGetLength(right_definition_xml
));
92 CFRelease(right_definition_xml
);
95 static CFDictionaryRef CF_RETURNS_RETAINED
96 read_dict_from_stdin()
98 ssize_t bytes_read
= 0;
100 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
101 CFErrorRef err
= NULL
;
106 while ((bytes_read
= read(STDIN_FILENO
, (void *)buffer
, sizeof(buffer
))))
108 if (bytes_read
== -1)
111 CFDataAppendBytes(data
, buffer
, bytes_read
);
114 CFDictionaryRef right_dict
= (CFDictionaryRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
, data
, kCFPropertyListImmutable
, NULL
, &err
);
117 if (NULL
== right_dict
) {
122 if (CFGetTypeID(right_dict
) != CFDictionaryGetTypeID())
124 fprintf(stderr
, "This is not a dictionary.\n");
125 CFRelease(right_dict
);
131 static CFPropertyListRef CF_RETURNS_RETAINED
132 read_plist_from_file(CFStringRef filePath
)
134 CFTypeRef property
= NULL
;
135 CFPropertyListRef propertyList
= NULL
;
136 CFURLRef fileURL
= NULL
;
137 CFErrorRef errorString
= NULL
;
138 CFDataRef resourceData
= NULL
;
139 Boolean status
= FALSE
;
140 SInt32 errorCode
= -1;
142 // Convert the path to a URL.
143 fileURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, filePath
, kCFURLPOSIXPathStyle
, false);
144 if (NULL
== fileURL
) {
147 property
= CFURLCreatePropertyFromResource(kCFAllocatorDefault
, fileURL
, kCFURLFileExists
, NULL
);
148 if (NULL
== property
) {
151 status
= CFBooleanGetValue(property
);
153 fprintf(stderr
, "The file does not exist.\n");
157 // Read the XML file.
158 status
= CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
);
160 fprintf(stderr
, "Error (%d) reading the file.\n", (int)errorCode
);
164 // Reconstitute the dictionary using the XML data.
165 propertyList
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, kCFPropertyListImmutable
, NULL
, &errorString
);
166 if (NULL
== propertyList
) {
171 // Some error checking.
172 if (!CFPropertyListIsValid(propertyList
, kCFPropertyListXMLFormat_v1_0
) || CFGetTypeID(propertyList
) != CFDictionaryGetTypeID()) {
173 fprintf(stderr
, "The file is invalid.\n");
174 CFRelease(propertyList
);
182 if (NULL
!= property
)
184 if (NULL
!= resourceData
)
185 CFRelease(resourceData
);
191 write_plist_to_file(CFPropertyListRef propertyList
, CFStringRef filePath
)
193 CFTypeRef property
= NULL
;
194 CFURLRef fileURL
= NULL
;
195 CFDataRef xmlData
= NULL
;
196 Boolean status
= FALSE
;
197 SInt32 errorCode
= -1;
198 CFErrorRef errorRef
= NULL
;
200 // Convert the path to a URL.
201 fileURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, filePath
, kCFURLPOSIXPathStyle
, false);
202 if (NULL
== fileURL
) {
205 property
= CFURLCreatePropertyFromResource(kCFAllocatorDefault
, fileURL
, kCFURLFileExists
, NULL
);
206 if (NULL
== property
) {
209 if (!CFBooleanGetValue(property
)) {
210 fprintf(stderr
, "The file does not exist.\n");
214 // Convert the property list into XML data.
215 xmlData
= CFPropertyListCreateData(kCFAllocatorDefault
, propertyList
, kCFPropertyListXMLFormat_v1_0
, 0, &errorRef
);
217 fprintf(stderr
, "The file could not be written.\n");
221 // Write the XML data to the file.
222 if (!CFURLWriteDataAndPropertiesToResource(fileURL
, xmlData
, NULL
, &errorCode
)) {
223 fprintf(stderr
, "The file could not be written.\n");
229 CFReleaseNull(property
);
238 static void merge_dictionaries(const void *key
, const void *value
, void *mergeDict
)
240 CFDictionarySetValue(mergeDict
, key
, value
);
244 authorizationdb(int argc
, char * const * argv
)
246 AuthorizationRef auth_ref
= NULL
;
248 while ((ch
= getopt(argc
, argv
, "i")) != -1)
253 auth_ref
= read_auth_ref_from_stdin();
265 return 2; // required right parameter(s)
271 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
, 0, &auth_ref
))
274 if (!strcmp("read", argv
[0]))
276 CFDictionaryRef right_definition
;
277 status
= AuthorizationRightGet(argv
[1], &right_definition
);
280 write_dict_to_stdout(right_definition
);
281 CFRelease(right_definition
);
284 else if (!strcmp("write", argv
[0]))
288 CFDictionaryRef right_definition
= read_dict_from_stdin();
289 if (!right_definition
)
291 status
= AuthorizationRightSet(auth_ref
, argv
[1], right_definition
, NULL
, NULL
, NULL
);
292 CFRelease(right_definition
);
296 // argv[2] is shortcut string
297 CFStringRef shortcut_definition
= CFStringCreateWithCStringNoCopy(NULL
, argv
[2], kCFStringEncodingUTF8
, kCFAllocatorNull
);
298 if (!shortcut_definition
)
300 status
= AuthorizationRightSet(auth_ref
, argv
[1], shortcut_definition
, NULL
, NULL
, NULL
);
301 CFRelease(shortcut_definition
);
304 return 2; // take one optional argument - no more
307 else if (!strcmp("remove", argv
[0]))
309 status
= AuthorizationRightRemove(auth_ref
, argv
[1]);
311 else if (!strcmp("smartcard", argv
[0]))
315 if(!strcmp("status", argv
[1]))
317 const CFStringRef SMARTCARD_LINE
= CFSTR("builtin:smartcard-sniffer,privileged");
318 const CFStringRef MECHANISMS
= CFSTR("mechanisms");
319 const CFStringRef BUILTIN_LINE
= CFSTR("builtin:policy-banner");
320 const char* SYSTEM_LOGIN_CONSOLE
= "system.login.console";
321 const char* AUTHENTICATE
= "authenticate";
323 CFIndex requiredLine1
= -1;
324 CFIndex requiredLine2
= -1;
326 CFDictionaryRef right_definition
;
327 status
= AuthorizationRightGet(SYSTEM_LOGIN_CONSOLE
, &right_definition
);
330 CFArrayRef mechanisms
;
332 Boolean res
= CFDictionaryGetValueIfPresent(right_definition
, MECHANISMS
, (void*)&mechanisms
);
335 // now parse all array elements until "builtin:policy-banner" is found
336 CFIndex c
= CFArrayGetCount(mechanisms
);
337 CFStringRef mechanismName
;
339 for (CFIndex i
= 0; i
< c
; ++i
)
341 mechanismName
= CFArrayGetValueAtIndex(mechanisms
, i
);
342 if(CFStringCompare(mechanismName
, BUILTIN_LINE
, 0) == kCFCompareEqualTo
)
346 mechanismName
= CFArrayGetValueAtIndex(mechanisms
, i
+ 1);
347 if(CFStringCompare(mechanismName
, SMARTCARD_LINE
, 0) == kCFCompareEqualTo
)
349 requiredLine1
= i
+ 1;
356 CFRelease(right_definition
);
358 status
= AuthorizationRightGet(AUTHENTICATE
, &right_definition
);
361 CFArrayRef mechanisms
;
363 Boolean res
= CFDictionaryGetValueIfPresent(right_definition
, MECHANISMS
, (void*)&mechanisms
);
366 // now parse all array elements until "builtin:policy-banner" is found
367 CFIndex c
= CFArrayGetCount(mechanisms
);
368 CFStringRef mechanismName
;
372 mechanismName
= CFArrayGetValueAtIndex(mechanisms
, 0);
373 if(CFStringCompare(mechanismName
, SMARTCARD_LINE
, 0) == kCFCompareEqualTo
)
379 CFRelease(right_definition
);
381 printf("Current smartcard login state: %s (system.login.console %s, authentication rule %s)\n", requiredLine1
!= -1 && requiredLine2
!= -1 ?"enabled":"disabled", requiredLine1
!= -1 ? "enabled":"disabled", requiredLine2
!= -1 ? "enabled":"disabled");
384 else if(!strcmp("disable", argv
[1]))
385 status
= AuthorizationEnableSmartCard(auth_ref
, FALSE
);
386 else if(!strcmp("enable", argv
[1]))
387 status
= AuthorizationEnableSmartCard(auth_ref
, TRUE
);
389 return 2; // unrecognized parameter
392 return 2; // required parameter missing
394 else if (!strcmp("merge", argv
[0])) {
396 CFStringRef sourcePath
= NULL
;
397 CFStringRef destPath
= NULL
;
398 CFPropertyListRef sourcePlist
= NULL
;
399 CFPropertyListRef destPlist
= NULL
;
400 CFDictionaryRef sourceRights
= NULL
;
401 CFDictionaryRef sourceRules
= NULL
;
402 CFDictionaryRef destRights
= NULL
;
403 CFDictionaryRef destRules
= NULL
;
404 CFIndex rightsCount
= 0;
405 CFIndex rulesCount
= 0;
406 CFMutableDictionaryRef mergeRights
= NULL
;
407 CFMutableDictionaryRef mergeRules
= NULL
;
408 CFMutableDictionaryRef outDict
= NULL
;
410 if (argc
< 2 || argc
> 3)
413 if (!strcmp("-", argv
[1])) {
414 // Merging from <STDIN>.
415 sourcePlist
= read_dict_from_stdin();
417 sourcePath
= CFStringCreateWithCString(kCFAllocatorDefault
, argv
[1], kCFStringEncodingUTF8
);
418 if (NULL
== sourcePath
) {
421 sourcePlist
= read_plist_from_file(sourcePath
);
423 if (NULL
== sourcePlist
)
426 // Merging to /etc/authorization.
427 destPath
= CFStringCreateWithCString(kCFAllocatorDefault
, "/etc/authorization", kCFStringEncodingUTF8
);
429 destPath
= CFStringCreateWithCString(kCFAllocatorDefault
, argv
[2], kCFStringEncodingUTF8
);
431 if (NULL
== destPath
) {
434 destPlist
= read_plist_from_file(destPath
);
435 if (NULL
== destPlist
)
438 sourceRights
= CFDictionaryGetValue(sourcePlist
, CFSTR("rights"));
439 sourceRules
= CFDictionaryGetValue(sourcePlist
, CFSTR("rules"));
440 destRights
= CFDictionaryGetValue(destPlist
, CFSTR("rights"));
441 destRules
= CFDictionaryGetValue(destPlist
, CFSTR("rules"));
443 rightsCount
+= CFDictionaryGetCount(sourceRights
);
445 rightsCount
+= CFDictionaryGetCount(destRights
);
446 mergeRights
= CFDictionaryCreateMutable(NULL
, rightsCount
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
447 if (NULL
== mergeRights
) {
451 rulesCount
+= CFDictionaryGetCount(sourceRules
);
453 rulesCount
+= CFDictionaryGetCount(destRules
);
454 mergeRules
= CFDictionaryCreateMutable(NULL
, rulesCount
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
455 if (NULL
== mergeRules
) {
460 CFDictionaryApplyFunction(destRights
, merge_dictionaries
, mergeRights
);
462 CFDictionaryApplyFunction(destRules
, merge_dictionaries
, mergeRules
);
464 CFDictionaryApplyFunction(sourceRights
, merge_dictionaries
, mergeRights
);
466 CFDictionaryApplyFunction(sourceRules
, merge_dictionaries
, mergeRules
);
468 outDict
= CFDictionaryCreateMutable(NULL
, 3, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
469 if (NULL
== outDict
) {
472 if (CFDictionaryContainsKey(sourcePlist
, CFSTR("comment")))
473 CFDictionaryAddValue(outDict
, CFSTR("comment"), CFDictionaryGetValue(sourcePlist
, CFSTR("comment")));
474 else if (CFDictionaryContainsKey(destPlist
, CFSTR("comment")))
475 CFDictionaryAddValue(outDict
, CFSTR("comment"), CFDictionaryGetValue(destPlist
, CFSTR("comment")));
476 CFDictionaryAddValue(outDict
, CFSTR("rights"), mergeRights
);
477 CFDictionaryAddValue(outDict
, CFSTR("rules"), mergeRules
);
478 if (!write_plist_to_file(outDict
, destPath
))
484 CFRelease(sourcePath
);
488 CFRelease(sourcePlist
);
490 CFRelease(destPlist
);
501 AuthorizationFree(auth_ref
, 0);
504 fprintf(stderr
, "%s (%d)\n", status
? "NO" : "YES", (int)status
);
506 return (status
? -1 : 0);
510 authorize(int argc
, char * const *argv
)
515 Boolean user_interaction_allowed
= FALSE
, extend_rights
= TRUE
;
516 Boolean partial_rights
= FALSE
, destroy_rights
= FALSE
;
517 Boolean pre_authorize
= FALSE
, internalize
= FALSE
, externalize
= FALSE
;
518 Boolean wait
= FALSE
, explicit_credentials
= FALSE
;
519 Boolean isolate_explicit_credentials
= FALSE
, least_privileged
= FALSE
;
522 while ((ch
= getopt(argc
, argv
, "ucC:EpdPieqwxl")) != -1)
527 user_interaction_allowed
= TRUE
;
530 explicit_credentials
= TRUE
;
533 explicit_credentials
= TRUE
;
540 extend_rights
= FALSE
;
543 partial_rights
= TRUE
;
546 destroy_rights
= TRUE
;
549 pre_authorize
= TRUE
;
559 isolate_explicit_credentials
= TRUE
;
562 least_privileged
= TRUE
;
566 return 2; /* @@@ Return 2 triggers usage message. */
574 return 2; // required right parameter(s)
576 // set up AuthorizationFlags
577 AuthorizationFlags flags
= kAuthorizationFlagDefaults
|
578 (user_interaction_allowed
? kAuthorizationFlagInteractionAllowed
: 0) |
579 (extend_rights
? kAuthorizationFlagExtendRights
: 0) |
580 (partial_rights
? kAuthorizationFlagPartialRights
: 0) |
581 (pre_authorize
? kAuthorizationFlagPreAuthorize
: 0) |
582 (least_privileged
? kAuthorizationFlagLeastPrivileged
: 0);
584 // set up AuthorizationRightSet
585 AuthorizationItem rights
[argc
];
586 memset(rights
, '\0', argc
* sizeof(AuthorizationItem
));
587 AuthorizationItemSet rightset
= { argc
, rights
};
589 rights
[--argc
].name
= *argv
++;
591 AuthorizationRef auth_ref
= NULL
;
593 // internalize AuthorizationRef
596 auth_ref
= read_auth_ref_from_stdin();
601 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
,
602 (least_privileged
? kAuthorizationFlagLeastPrivileged
: 0),
606 // prepare environment if needed
607 AuthorizationEnvironment
*envp
= NULL
;
608 if (explicit_credentials
) {
611 char *pass
= getpass("Password:");
612 if (!(login
&& pass
))
614 static AuthorizationItem authenv
[] = {
615 { kAuthorizationEnvironmentUsername
},
616 { kAuthorizationEnvironmentPassword
},
617 { kAuthorizationEnvironmentShared
} // optional (see below)
619 static AuthorizationEnvironment env
= { 0, authenv
};
620 authenv
[0].valueLength
= strlen(login
);
621 authenv
[0].value
= login
;
622 authenv
[1].valueLength
= strlen(pass
);
623 authenv
[1].value
= pass
;
624 if (isolate_explicit_credentials
)
625 env
.count
= 2; // do not send kAuthorizationEnvironmentShared
627 env
.count
= 3; // do send kAuthorizationEnvironmentShared
631 // perform Authorization
632 AuthorizationRights
*granted_rights
= NULL
;
633 status
= AuthorizationCopyRights(auth_ref
, &rightset
, envp
, flags
, &granted_rights
);
635 // externalize AuthorizationRef
637 write_auth_ref_to_stdout(auth_ref
);
640 fprintf(stderr
, "%s (%d) ", status
? "NO" : "YES", (int)status
);
642 if (!do_quiet
&& !status
&& granted_rights
)
645 fprintf(stderr
, "{ %d: ", (int)granted_rights
->count
);
646 for (index
= 0; index
< granted_rights
->count
; index
++)
648 fprintf(stderr
, "\"%s\"%s %c ", granted_rights
->items
[index
].name
,
649 (kAuthorizationFlagCanNotPreAuthorize
& granted_rights
->items
[index
].flags
) ? " (cannot-preauthorize)" : "",
650 (index
+1 != granted_rights
->count
) ? ',' : '}');
652 AuthorizationFreeItemSet(granted_rights
);
656 fprintf(stderr
, "\n");
658 // wait for client to pick up AuthorizationRef
659 if (externalize
&& wait
)
660 while (-1 != write(STDOUT_FILENO
, NULL
, 0))
663 // drop AuthorizationRef
665 AuthorizationFree(auth_ref
, destroy_rights
? kAuthorizationFlagDestroyRights
: 0);
667 return (status
? -1 : 0);
672 execute_with_privileges(int argc
, char * const *argv
)
674 AuthorizationRef auth_ref
= NULL
;
676 while ((ch
= getopt(argc
, argv
, "i")) != -1)
681 auth_ref
= read_auth_ref_from_stdin();
693 return 2; // required tool parameter(s)
697 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
, 0, &auth_ref
))
700 FILE *communications_pipe
= NULL
;
702 status
= AuthorizationExecuteWithPrivileges(auth_ref
,argv
[0], 0, (argc
> 1) ? &argv
[1] : NULL
, &communications_pipe
);
705 fprintf(stderr
, "%s (%d) ", status
? "NO" : "YES", (int)status
);
709 ssize_t bytes_read
= 0;
710 uint8_t buffer
[4096];
712 while ((bytes_read
= read(STDIN_FILENO
, &buffer
, sizeof(buffer
))))
714 if ((bytes_read
== -1) && ((errno
!= EAGAIN
) || (errno
!= EINTR
)))
717 while ((-1 == write(fileno(communications_pipe
), buffer
, bytes_read
)) &&
718 ((errno
== EAGAIN
) || (errno
== EINTR
)))
723 return (status
? -1 : 0);