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();
257 return SHOW_USAGE_MESSAGE
;
265 return SHOW_USAGE_MESSAGE
; // 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 SHOW_USAGE_MESSAGE
; // 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 SHOW_USAGE_MESSAGE
; // unrecognized parameter
392 return SHOW_USAGE_MESSAGE
; // 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)
411 return SHOW_USAGE_MESSAGE
;
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
);
495 return SHOW_USAGE_MESSAGE
;
498 return SHOW_USAGE_MESSAGE
;
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
)
516 Boolean user_interaction_allowed
= FALSE
, extend_rights
= TRUE
;
517 Boolean partial_rights
= FALSE
, destroy_rights
= FALSE
;
518 Boolean pre_authorize
= FALSE
, internalize
= FALSE
, externalize
= FALSE
;
519 Boolean wait
= FALSE
, explicit_credentials
= FALSE
;
520 Boolean isolate_explicit_credentials
= FALSE
, least_privileged
= FALSE
;
523 while ((ch
= getopt(argc
, argv
, "ucC:EpdPieqwxl")) != -1)
528 user_interaction_allowed
= TRUE
;
531 explicit_credentials
= TRUE
;
534 explicit_credentials
= TRUE
;
541 extend_rights
= FALSE
;
544 partial_rights
= TRUE
;
547 destroy_rights
= TRUE
;
550 pre_authorize
= TRUE
;
560 isolate_explicit_credentials
= TRUE
;
563 least_privileged
= TRUE
;
567 return SHOW_USAGE_MESSAGE
;
575 return SHOW_USAGE_MESSAGE
; // required right parameter(s)
577 // set up AuthorizationFlags
578 AuthorizationFlags flags
= kAuthorizationFlagDefaults
|
579 (user_interaction_allowed
? kAuthorizationFlagInteractionAllowed
: 0) |
580 (extend_rights
? kAuthorizationFlagExtendRights
: 0) |
581 (partial_rights
? kAuthorizationFlagPartialRights
: 0) |
582 (pre_authorize
? kAuthorizationFlagPreAuthorize
: 0) |
583 (least_privileged
? kAuthorizationFlagLeastPrivileged
: 0);
585 // set up AuthorizationRightSet
586 AuthorizationItem
*rights
= malloc(argc
* sizeof(AuthorizationItem
));
588 fprintf(stderr
, "Out of memory\n");
592 memset(rights
, '\0', argc
* sizeof(AuthorizationItem
));
593 AuthorizationItemSet rightset
= { argc
, rights
};
595 rights
[--argc
].name
= *argv
++;
597 AuthorizationRef auth_ref
= NULL
;
599 // internalize AuthorizationRef
602 auth_ref
= read_auth_ref_from_stdin();
609 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
,
610 (least_privileged
? kAuthorizationFlagLeastPrivileged
: 0),
616 // prepare environment if needed
617 AuthorizationEnvironment
*envp
= NULL
;
618 if (explicit_credentials
) {
621 char *pass
= getpass("Password:");
622 if (!(login
&& pass
)) {
626 static AuthorizationItem authenv
[] = {
627 { kAuthorizationEnvironmentUsername
},
628 { kAuthorizationEnvironmentPassword
},
629 { kAuthorizationEnvironmentShared
} // optional (see below)
631 static AuthorizationEnvironment env
= { 0, authenv
};
632 authenv
[0].valueLength
= strlen(login
);
633 authenv
[0].value
= login
;
634 authenv
[1].valueLength
= strlen(pass
);
635 authenv
[1].value
= pass
;
636 if (isolate_explicit_credentials
)
637 env
.count
= 2; // do not send kAuthorizationEnvironmentShared
639 env
.count
= 3; // do send kAuthorizationEnvironmentShared
643 // perform Authorization
644 AuthorizationRights
*granted_rights
= NULL
;
645 status
= AuthorizationCopyRights(auth_ref
, &rightset
, envp
, flags
, &granted_rights
);
647 // externalize AuthorizationRef
649 write_auth_ref_to_stdout(auth_ref
);
652 fprintf(stderr
, "%s (%d) ", status
? "NO" : "YES", (int)status
);
654 if (!do_quiet
&& !status
&& granted_rights
)
657 fprintf(stderr
, "{ %d: ", (int)granted_rights
->count
);
658 for (index
= 0; index
< granted_rights
->count
; index
++)
660 fprintf(stderr
, "\"%s\"%s %c ", granted_rights
->items
[index
].name
,
661 (kAuthorizationFlagCanNotPreAuthorize
& granted_rights
->items
[index
].flags
) ? " (cannot-preauthorize)" : "",
662 (index
+1 != granted_rights
->count
) ? ',' : '}');
664 AuthorizationFreeItemSet(granted_rights
);
668 fprintf(stderr
, "\n");
670 // wait for client to pick up AuthorizationRef
671 if (externalize
&& wait
)
672 while (-1 != write(STDOUT_FILENO
, NULL
, 0))
675 // drop AuthorizationRef
677 AuthorizationFree(auth_ref
, destroy_rights
? kAuthorizationFlagDestroyRights
: 0);
679 retval
= (status
? -1 : 0);
689 execute_with_privileges(int argc
, char * const *argv
)
691 AuthorizationRef auth_ref
= NULL
;
693 while ((ch
= getopt(argc
, argv
, "i")) != -1)
698 auth_ref
= read_auth_ref_from_stdin();
702 return SHOW_USAGE_MESSAGE
;
710 return SHOW_USAGE_MESSAGE
; // required tool parameter(s)
714 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
, 0, &auth_ref
))
717 FILE *communications_pipe
= NULL
;
719 status
= AuthorizationExecuteWithPrivileges(auth_ref
,argv
[0], 0, (argc
> 1) ? &argv
[1] : NULL
, &communications_pipe
);
722 fprintf(stderr
, "%s (%d) ", status
? "NO" : "YES", (int)status
);
726 ssize_t bytes_read
= 0;
727 uint8_t buffer
[4096];
729 while ((bytes_read
= read(STDIN_FILENO
, &buffer
, sizeof(buffer
))))
731 if ((bytes_read
== -1) && ((errno
!= EAGAIN
) || (errno
!= EINTR
)))
734 while ((-1 == write(fileno(communications_pipe
), buffer
, bytes_read
)) &&
735 ((errno
== EAGAIN
) || (errno
== EINTR
)))
740 return (status
? -1 : 0);