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>
31 #include "security_tool.h"
35 static AuthorizationRef
36 read_auth_ref_from_stdin()
38 AuthorizationRef auth_ref
= NULL
;
39 AuthorizationExternalForm extform
;
42 while (kAuthorizationExternalFormLength
!= (bytes_read
= read(STDIN_FILENO
, &extform
, kAuthorizationExternalFormLength
)))
44 if ((bytes_read
== -1) && ((errno
!= EAGAIN
) || (errno
!= EINTR
)))
47 if (bytes_read
!= kAuthorizationExternalFormLength
)
48 fprintf(stderr
, "ERR: Failed to read authref\n");
50 if (AuthorizationCreateFromExternalForm(&extform
, &auth_ref
))
51 fprintf(stderr
, "ERR: Failed to internalize authref\n");
59 write_auth_ref_to_stdout(AuthorizationRef auth_ref
)
61 AuthorizationExternalForm extform
;
62 ssize_t bytes_written
;
64 if (AuthorizationMakeExternalForm(auth_ref
, &extform
))
67 while (kAuthorizationExternalFormLength
!= (bytes_written
= write(STDOUT_FILENO
, &extform
, kAuthorizationExternalFormLength
)))
69 if ((bytes_written
== -1) && ((errno
!= EAGAIN
) || (errno
!= EINTR
)))
73 if (bytes_written
== kAuthorizationExternalFormLength
)
80 write_dict_to_stdout(CFDictionaryRef dict
)
85 CFDataRef right_definition_xml
= CFPropertyListCreateXMLData(NULL
, dict
);
87 if (!right_definition_xml
)
90 write(STDOUT_FILENO
, CFDataGetBytePtr(right_definition_xml
), CFDataGetLength(right_definition_xml
));
91 CFRelease(right_definition_xml
);
94 static CFDictionaryRef
95 read_dict_from_stdin()
97 ssize_t bytes_read
= 0;
99 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
100 CFErrorRef err
= NULL
;
105 while ((bytes_read
= read(STDIN_FILENO
, (void *)buffer
, sizeof(buffer
))))
107 if (bytes_read
== -1)
110 CFDataAppendBytes(data
, buffer
, bytes_read
);
113 CFDictionaryRef right_dict
= (CFDictionaryRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
, data
, kCFPropertyListImmutable
, NULL
, &err
);
116 if (NULL
== right_dict
) {
121 if (CFGetTypeID(right_dict
) != CFDictionaryGetTypeID())
123 fprintf(stderr
, "This is not a dictionary.\n");
124 CFRelease(right_dict
);
130 static CFPropertyListRef
131 read_plist_from_file(CFStringRef filePath
)
133 CFTypeRef property
= NULL
;
134 CFPropertyListRef propertyList
= NULL
;
135 CFURLRef fileURL
= NULL
;
136 CFErrorRef errorString
= NULL
;
137 CFDataRef resourceData
= NULL
;
138 Boolean status
= FALSE
;
139 SInt32 errorCode
= -1;
141 // Convert the path to a URL.
142 fileURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, filePath
, kCFURLPOSIXPathStyle
, false);
143 if (NULL
== fileURL
) {
146 property
= CFURLCreatePropertyFromResource(kCFAllocatorDefault
, fileURL
, kCFURLFileExists
, NULL
);
147 if (NULL
== property
) {
150 status
= CFBooleanGetValue(property
);
152 fprintf(stderr
, "The file does not exist.\n");
156 // Read the XML file.
157 status
= CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
);
159 fprintf(stderr
, "Error (%d) reading the file.\n", (int)errorCode
);
163 // Reconstitute the dictionary using the XML data.
164 propertyList
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, kCFPropertyListImmutable
, NULL
, &errorString
);
165 if (NULL
== propertyList
) {
170 // Some error checking.
171 if (!CFPropertyListIsValid(propertyList
, kCFPropertyListXMLFormat_v1_0
) || CFGetTypeID(propertyList
) != CFDictionaryGetTypeID()) {
172 fprintf(stderr
, "The file is invalid.\n");
173 CFRelease(propertyList
);
181 if (NULL
!= property
)
183 if (NULL
!= resourceData
)
184 CFRelease(resourceData
);
190 write_plist_to_file(CFPropertyListRef propertyList
, CFStringRef filePath
)
192 CFTypeRef property
= NULL
;
193 CFURLRef fileURL
= NULL
;
194 CFDataRef xmlData
= NULL
;
195 Boolean status
= FALSE
;
196 SInt32 errorCode
= -1;
197 CFErrorRef errorRef
= NULL
;
199 // Convert the path to a URL.
200 fileURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, filePath
, kCFURLPOSIXPathStyle
, false);
201 if (NULL
== fileURL
) {
204 property
= CFURLCreatePropertyFromResource(kCFAllocatorDefault
, fileURL
, kCFURLFileExists
, NULL
);
205 if (NULL
== property
) {
208 if (!CFBooleanGetValue(property
)) {
209 fprintf(stderr
, "The file does not exist.\n");
213 // Convert the property list into XML data.
214 xmlData
= CFPropertyListCreateData(kCFAllocatorDefault
, propertyList
, kCFPropertyListXMLFormat_v1_0
, 0, &errorRef
);
216 fprintf(stderr
, "The file could not be written.\n");
220 // Write the XML data to the file.
221 if (!CFURLWriteDataAndPropertiesToResource(fileURL
, xmlData
, NULL
, &errorCode
)) {
222 fprintf(stderr
, "The file could not be written.\n");
236 static void merge_dictionaries(const void *key
, const void *value
, void *mergeDict
)
238 CFDictionarySetValue(mergeDict
, key
, value
);
242 authorizationdb(int argc
, char * const * argv
)
244 AuthorizationRef auth_ref
= NULL
;
246 while ((ch
= getopt(argc
, argv
, "i")) != -1)
251 auth_ref
= read_auth_ref_from_stdin();
263 return 2; // required right parameter(s)
269 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
, 0, &auth_ref
))
272 if (!strcmp("read", argv
[0]))
274 CFDictionaryRef right_definition
;
275 status
= AuthorizationRightGet(argv
[1], &right_definition
);
278 write_dict_to_stdout(right_definition
);
279 CFRelease(right_definition
);
282 else if (!strcmp("write", argv
[0]))
286 CFDictionaryRef right_definition
= read_dict_from_stdin();
287 if (!right_definition
)
289 status
= AuthorizationRightSet(auth_ref
, argv
[1], right_definition
, NULL
, NULL
, NULL
);
290 CFRelease(right_definition
);
294 // argv[2] is shortcut string
295 CFStringRef shortcut_definition
= CFStringCreateWithCStringNoCopy(NULL
, argv
[2], kCFStringEncodingUTF8
, kCFAllocatorNull
);
296 if (!shortcut_definition
)
298 status
= AuthorizationRightSet(auth_ref
, argv
[1], shortcut_definition
, NULL
, NULL
, NULL
);
299 CFRelease(shortcut_definition
);
302 return 2; // take one optional argument - no more
305 else if (!strcmp("remove", argv
[0]))
307 status
= AuthorizationRightRemove(auth_ref
, argv
[1]);
309 else if (!strcmp("smartcard", argv
[0]))
313 if(!strcmp("status", argv
[1]))
315 const CFStringRef SMARTCARD_LINE
= CFSTR("builtin:smartcard-sniffer,privileged");
316 const CFStringRef MECHANISMS
= CFSTR("mechanisms");
317 const CFStringRef BUILTIN_LINE
= CFSTR("builtin:policy-banner");
318 const char* SYSTEM_LOGIN_CONSOLE
= "system.login.console";
319 const char* AUTHENTICATE
= "authenticate";
321 CFIndex requiredLine1
= -1;
322 CFIndex requiredLine2
= -1;
324 CFDictionaryRef right_definition
;
325 status
= AuthorizationRightGet(SYSTEM_LOGIN_CONSOLE
, &right_definition
);
328 CFArrayRef mechanisms
;
330 Boolean res
= CFDictionaryGetValueIfPresent(right_definition
, MECHANISMS
, (void*)&mechanisms
);
333 // now parse all array elements until "builtin:policy-banner" is found
334 CFIndex c
= CFArrayGetCount(mechanisms
);
335 CFStringRef mechanismName
;
337 for (CFIndex i
= 0; i
< c
; ++i
)
339 mechanismName
= CFArrayGetValueAtIndex(mechanisms
, i
);
340 if(CFStringCompare(mechanismName
, BUILTIN_LINE
, 0) == kCFCompareEqualTo
)
344 mechanismName
= CFArrayGetValueAtIndex(mechanisms
, i
+ 1);
345 if(CFStringCompare(mechanismName
, SMARTCARD_LINE
, 0) == kCFCompareEqualTo
)
347 requiredLine1
= i
+ 1;
354 CFRelease(right_definition
);
356 status
= AuthorizationRightGet(AUTHENTICATE
, &right_definition
);
359 CFArrayRef mechanisms
;
361 Boolean res
= CFDictionaryGetValueIfPresent(right_definition
, MECHANISMS
, (void*)&mechanisms
);
364 // now parse all array elements until "builtin:policy-banner" is found
365 CFIndex c
= CFArrayGetCount(mechanisms
);
366 CFStringRef mechanismName
;
370 mechanismName
= CFArrayGetValueAtIndex(mechanisms
, 0);
371 if(CFStringCompare(mechanismName
, SMARTCARD_LINE
, 0) == kCFCompareEqualTo
)
377 CFRelease(right_definition
);
379 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");
382 else if(!strcmp("disable", argv
[1]))
383 status
= AuthorizationEnableSmartCard(auth_ref
, FALSE
);
384 else if(!strcmp("enable", argv
[1]))
385 status
= AuthorizationEnableSmartCard(auth_ref
, TRUE
);
387 return 2; // unrecognized parameter
390 return 2; // required parameter missing
392 else if (!strcmp("merge", argv
[0])) {
394 CFStringRef sourcePath
= NULL
;
395 CFStringRef destPath
= NULL
;
396 CFPropertyListRef sourcePlist
= NULL
;
397 CFPropertyListRef destPlist
= NULL
;
398 CFDictionaryRef sourceRights
= NULL
;
399 CFDictionaryRef sourceRules
= NULL
;
400 CFDictionaryRef destRights
= NULL
;
401 CFDictionaryRef destRules
= NULL
;
402 CFIndex rightsCount
= 0;
403 CFIndex rulesCount
= 0;
404 CFMutableDictionaryRef mergeRights
= NULL
;
405 CFMutableDictionaryRef mergeRules
= NULL
;
406 CFMutableDictionaryRef outDict
= NULL
;
408 if (argc
< 2 || argc
> 3)
411 if (!strcmp("-", argv
[1])) {
412 // Merging from <STDIN>.
413 sourcePlist
= read_dict_from_stdin();
415 sourcePath
= CFStringCreateWithCString(kCFAllocatorDefault
, argv
[1], kCFStringEncodingUTF8
);
416 if (NULL
== sourcePath
) {
419 sourcePlist
= read_plist_from_file(sourcePath
);
421 if (NULL
== sourcePlist
)
424 // Merging to /etc/authorization.
425 destPath
= CFStringCreateWithCString(kCFAllocatorDefault
, "/etc/authorization", kCFStringEncodingUTF8
);
427 destPath
= CFStringCreateWithCString(kCFAllocatorDefault
, argv
[2], kCFStringEncodingUTF8
);
429 if (NULL
== destPath
) {
432 destPlist
= read_plist_from_file(destPath
);
433 if (NULL
== destPlist
)
436 sourceRights
= CFDictionaryGetValue(sourcePlist
, CFSTR("rights"));
437 sourceRules
= CFDictionaryGetValue(sourcePlist
, CFSTR("rules"));
438 destRights
= CFDictionaryGetValue(destPlist
, CFSTR("rights"));
439 destRules
= CFDictionaryGetValue(destPlist
, CFSTR("rules"));
441 rightsCount
+= CFDictionaryGetCount(sourceRights
);
443 rightsCount
+= CFDictionaryGetCount(destRights
);
444 mergeRights
= CFDictionaryCreateMutable(NULL
, rightsCount
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
445 if (NULL
== mergeRights
) {
449 rulesCount
+= CFDictionaryGetCount(sourceRules
);
451 rulesCount
+= CFDictionaryGetCount(destRules
);
452 mergeRules
= CFDictionaryCreateMutable(NULL
, rulesCount
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
453 if (NULL
== mergeRules
) {
458 CFDictionaryApplyFunction(destRights
, merge_dictionaries
, mergeRights
);
460 CFDictionaryApplyFunction(destRules
, merge_dictionaries
, mergeRules
);
462 CFDictionaryApplyFunction(sourceRights
, merge_dictionaries
, mergeRights
);
464 CFDictionaryApplyFunction(sourceRules
, merge_dictionaries
, mergeRules
);
466 outDict
= CFDictionaryCreateMutable(NULL
, 3, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
467 if (NULL
== outDict
) {
470 if (CFDictionaryContainsKey(sourcePlist
, CFSTR("comment")))
471 CFDictionaryAddValue(outDict
, CFSTR("comment"), CFDictionaryGetValue(sourcePlist
, CFSTR("comment")));
472 else if (CFDictionaryContainsKey(destPlist
, CFSTR("comment")))
473 CFDictionaryAddValue(outDict
, CFSTR("comment"), CFDictionaryGetValue(destPlist
, CFSTR("comment")));
474 CFDictionaryAddValue(outDict
, CFSTR("rights"), mergeRights
);
475 CFDictionaryAddValue(outDict
, CFSTR("rules"), mergeRules
);
476 if (!write_plist_to_file(outDict
, destPath
))
482 CFRelease(sourcePath
);
486 CFRelease(sourcePlist
);
488 CFRelease(destPlist
);
499 AuthorizationFree(auth_ref
, 0);
502 fprintf(stderr
, "%s (%d)\n", status
? "NO" : "YES", (int)status
);
504 return (status
? -1 : 0);
508 authorize(int argc
, char * const *argv
)
513 Boolean user_interaction_allowed
= FALSE
, extend_rights
= TRUE
;
514 Boolean partial_rights
= FALSE
, destroy_rights
= FALSE
;
515 Boolean pre_authorize
= FALSE
, internalize
= FALSE
, externalize
= FALSE
;
516 Boolean wait
= FALSE
, explicit_credentials
= FALSE
;
517 Boolean isolate_explicit_credentials
= FALSE
, least_privileged
= FALSE
;
520 while ((ch
= getopt(argc
, argv
, "ucC:EpdPieqwxl")) != -1)
525 user_interaction_allowed
= TRUE
;
528 explicit_credentials
= TRUE
;
531 explicit_credentials
= TRUE
;
538 extend_rights
= FALSE
;
541 partial_rights
= TRUE
;
544 destroy_rights
= TRUE
;
547 pre_authorize
= TRUE
;
557 isolate_explicit_credentials
= TRUE
;
560 least_privileged
= TRUE
;
564 return 2; /* @@@ Return 2 triggers usage message. */
572 return 2; // required right parameter(s)
574 // set up AuthorizationFlags
575 AuthorizationFlags flags
= kAuthorizationFlagDefaults
|
576 (user_interaction_allowed
? kAuthorizationFlagInteractionAllowed
: 0) |
577 (extend_rights
? kAuthorizationFlagExtendRights
: 0) |
578 (partial_rights
? kAuthorizationFlagPartialRights
: 0) |
579 (pre_authorize
? kAuthorizationFlagPreAuthorize
: 0) |
580 (least_privileged
? kAuthorizationFlagLeastPrivileged
: 0);
582 // set up AuthorizationRightSet
583 AuthorizationItem rights
[argc
];
584 memset(rights
, '\0', argc
* sizeof(AuthorizationItem
));
585 AuthorizationItemSet rightset
= { argc
, rights
};
587 rights
[--argc
].name
= *argv
++;
589 AuthorizationRef auth_ref
= NULL
;
591 // internalize AuthorizationRef
594 auth_ref
= read_auth_ref_from_stdin();
599 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
,
600 (least_privileged
? kAuthorizationFlagLeastPrivileged
: 0),
604 // prepare environment if needed
605 AuthorizationEnvironment
*envp
= NULL
;
606 if (explicit_credentials
) {
609 char *pass
= getpass("Password:");
610 if (!(login
&& pass
))
612 static AuthorizationItem authenv
[] = {
613 { kAuthorizationEnvironmentUsername
},
614 { kAuthorizationEnvironmentPassword
},
615 { kAuthorizationEnvironmentShared
} // optional (see below)
617 static AuthorizationEnvironment env
= { 0, authenv
};
618 authenv
[0].valueLength
= strlen(login
);
619 authenv
[0].value
= login
;
620 authenv
[1].valueLength
= strlen(pass
);
621 authenv
[1].value
= pass
;
622 if (isolate_explicit_credentials
)
623 env
.count
= 2; // do not send kAuthorizationEnvironmentShared
625 env
.count
= 3; // do send kAuthorizationEnvironmentShared
629 // perform Authorization
630 AuthorizationRights
*granted_rights
= NULL
;
631 status
= AuthorizationCopyRights(auth_ref
, &rightset
, envp
, flags
, &granted_rights
);
633 // externalize AuthorizationRef
635 write_auth_ref_to_stdout(auth_ref
);
638 fprintf(stderr
, "%s (%d) ", status
? "NO" : "YES", (int)status
);
640 if (!do_quiet
&& !status
&& granted_rights
)
643 fprintf(stderr
, "{ %d: ", (int)granted_rights
->count
);
644 for (index
= 0; index
< granted_rights
->count
; index
++)
646 fprintf(stderr
, "\"%s\"%s %c ", granted_rights
->items
[index
].name
,
647 (kAuthorizationFlagCanNotPreAuthorize
& granted_rights
->items
[index
].flags
) ? " (cannot-preauthorize)" : "",
648 (index
+1 != granted_rights
->count
) ? ',' : '}');
650 AuthorizationFreeItemSet(granted_rights
);
654 fprintf(stderr
, "\n");
656 // wait for client to pick up AuthorizationRef
657 if (externalize
&& wait
)
658 while (-1 != write(STDOUT_FILENO
, NULL
, 0))
661 // drop AuthorizationRef
663 AuthorizationFree(auth_ref
, destroy_rights
? kAuthorizationFlagDestroyRights
: 0);
665 return (status
? -1 : 0);
670 execute_with_privileges(int argc
, char * const *argv
)
672 AuthorizationRef auth_ref
= NULL
;
674 while ((ch
= getopt(argc
, argv
, "i")) != -1)
679 auth_ref
= read_auth_ref_from_stdin();
691 return 2; // required tool parameter(s)
695 if (!auth_ref
&& AuthorizationCreate(NULL
, NULL
, 0, &auth_ref
))
698 FILE *communications_pipe
= NULL
;
700 status
= AuthorizationExecuteWithPrivileges(auth_ref
,argv
[0], 0, (argc
> 1) ? &argv
[1] : NULL
, &communications_pipe
);
703 fprintf(stderr
, "%s (%d) ", status
? "NO" : "YES", (int)status
);
707 ssize_t bytes_read
= 0;
708 uint8_t buffer
[4096];
710 while ((bytes_read
= read(STDIN_FILENO
, &buffer
, sizeof(buffer
))))
712 if ((bytes_read
== -1) && ((errno
!= EAGAIN
) || (errno
!= EINTR
)))
715 while ((-1 == write(fileno(communications_pipe
), buffer
, bytes_read
)) &&
716 ((errno
== EAGAIN
) || (errno
== EINTR
)))
721 return (status
? -1 : 0);