]> git.saurik.com Git - apple/security.git/blob - SecurityTool/macOS/authz.c
Security-59306.11.20.tar.gz
[apple/security.git] / SecurityTool / macOS / authz.c
1 /*
2 * Copyright (c) 2003-2004,2006-2007,2009-2010,2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * authz.c
24 */
25
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <Security/AuthorizationPriv.h>
29 #include <utilities/SecCFRelease.h>
30
31 #include "authz.h"
32 #include "security_tool.h"
33
34 // AEWP?
35
36 static AuthorizationRef
37 read_auth_ref_from_stdin()
38 {
39 AuthorizationRef auth_ref = NULL;
40 AuthorizationExternalForm extform;
41 ssize_t bytes_read;
42
43 while (kAuthorizationExternalFormLength != (bytes_read = read(STDIN_FILENO, &extform, kAuthorizationExternalFormLength)))
44 {
45 if ((bytes_read == -1) && ((errno != EAGAIN) || (errno != EINTR)))
46 break;
47 }
48 if (bytes_read != kAuthorizationExternalFormLength)
49 fprintf(stderr, "ERR: Failed to read authref\n");
50 else
51 if (AuthorizationCreateFromExternalForm(&extform, &auth_ref))
52 fprintf(stderr, "ERR: Failed to internalize authref\n");
53
54 close(0);
55
56 return auth_ref;
57 }
58
59 static int
60 write_auth_ref_to_stdout(AuthorizationRef auth_ref)
61 {
62 AuthorizationExternalForm extform;
63 ssize_t bytes_written;
64
65 if (AuthorizationMakeExternalForm(auth_ref, &extform))
66 return -1;
67
68 while (kAuthorizationExternalFormLength != (bytes_written = write(STDOUT_FILENO, &extform, kAuthorizationExternalFormLength)))
69 {
70 if ((bytes_written == -1) && ((errno != EAGAIN) || (errno != EINTR)))
71 break;
72 }
73
74 if (bytes_written == kAuthorizationExternalFormLength)
75 return 0;
76
77 return -1;
78 }
79
80 static void
81 write_dict_to_stdout(CFDictionaryRef dict)
82 {
83 if (!dict)
84 return;
85
86 CFDataRef right_definition_xml = CFPropertyListCreateXMLData(NULL, dict);
87
88 if (!right_definition_xml)
89 return;
90
91 write(STDOUT_FILENO, CFDataGetBytePtr(right_definition_xml), CFDataGetLength(right_definition_xml));
92 CFRelease(right_definition_xml);
93 }
94
95 static CFDictionaryRef CF_RETURNS_RETAINED
96 read_dict_from_stdin()
97 {
98 ssize_t bytes_read = 0;
99 uint8_t buffer[4096];
100 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
101 CFErrorRef err = NULL;
102
103 if (!data)
104 return NULL;
105
106 while ((bytes_read = read(STDIN_FILENO, (void *)buffer, sizeof(buffer))))
107 {
108 if (bytes_read == -1)
109 break;
110 else
111 CFDataAppendBytes(data, buffer, bytes_read);
112 }
113
114 CFDictionaryRef right_dict = (CFDictionaryRef)CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, &err);
115 CFRelease(data);
116
117 if (NULL == right_dict) {
118 CFShow(err);
119 return NULL;
120 }
121
122 if (CFGetTypeID(right_dict) != CFDictionaryGetTypeID())
123 {
124 fprintf(stderr, "This is not a dictionary.\n");
125 CFRelease(right_dict);
126 return NULL;
127 }
128 return right_dict;
129 }
130
131 static CFPropertyListRef CF_RETURNS_RETAINED
132 read_plist_from_file(CFStringRef filePath)
133 {
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;
141
142 // Convert the path to a URL.
143 fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
144 if (NULL == fileURL) {
145 goto bail;
146 }
147 property = CFURLCreatePropertyFromResource(kCFAllocatorDefault, fileURL, kCFURLFileExists, NULL);
148 if (NULL == property) {
149 goto bail;
150 }
151 status = CFBooleanGetValue(property);
152 if (!status) {
153 fprintf(stderr, "The file does not exist.\n");
154 goto bail;
155 }
156
157 // Read the XML file.
158 status = CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode);
159 if (!status) {
160 fprintf(stderr, "Error (%d) reading the file.\n", (int)errorCode);
161 goto bail;
162 }
163
164 // Reconstitute the dictionary using the XML data.
165 propertyList = CFPropertyListCreateWithData(kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, NULL, &errorString);
166 if (NULL == propertyList) {
167 CFShow(errorString);
168 goto bail;
169 }
170
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);
175 propertyList = NULL;
176 goto bail;
177 }
178
179 bail:
180 if (NULL != fileURL)
181 CFRelease(fileURL);
182 if (NULL != property)
183 CFRelease(property);
184 if (NULL != resourceData)
185 CFRelease(resourceData);
186
187 return propertyList;
188 }
189
190 static Boolean
191 write_plist_to_file(CFPropertyListRef propertyList, CFStringRef filePath)
192 {
193 CFTypeRef property = NULL;
194 CFURLRef fileURL = NULL;
195 CFDataRef xmlData = NULL;
196 Boolean status = FALSE;
197 SInt32 errorCode = -1;
198 CFErrorRef errorRef = NULL;
199
200 // Convert the path to a URL.
201 fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
202 if (NULL == fileURL) {
203 goto bail;
204 }
205 property = CFURLCreatePropertyFromResource(kCFAllocatorDefault, fileURL, kCFURLFileExists, NULL);
206 if (NULL == property) {
207 goto bail;
208 }
209 if (!CFBooleanGetValue(property)) {
210 fprintf(stderr, "The file does not exist.\n");
211 goto bail;
212 }
213
214 // Convert the property list into XML data.
215 xmlData = CFPropertyListCreateData(kCFAllocatorDefault, propertyList, kCFPropertyListXMLFormat_v1_0, 0, &errorRef);
216 if (errorRef) {
217 fprintf(stderr, "The file could not be written.\n");
218 goto bail;
219 }
220
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");
224 goto bail;
225 }
226
227 status = TRUE;
228 bail:
229 CFReleaseNull(property);
230 if (NULL != xmlData)
231 CFRelease(xmlData);
232 if (NULL != fileURL)
233 CFRelease(fileURL);
234
235 return status;
236 }
237
238 static void merge_dictionaries(const void *key, const void *value, void *mergeDict)
239 {
240 CFDictionarySetValue(mergeDict, key, value);
241 }
242
243 int
244 authorizationdb(int argc, char * const * argv)
245 {
246 AuthorizationRef auth_ref = NULL;
247 int ch;
248 while ((ch = getopt(argc, argv, "i")) != -1)
249 {
250 switch (ch)
251 {
252 case 'i':
253 auth_ref = read_auth_ref_from_stdin();
254 break;
255 case '?':
256 default:
257 return SHOW_USAGE_MESSAGE;
258 }
259 }
260
261 argc -= optind;
262 argv += optind;
263
264 if (argc == 0)
265 return SHOW_USAGE_MESSAGE; // required right parameter(s)
266
267 OSStatus status;
268
269 if (argc > 1)
270 {
271 if (!auth_ref && AuthorizationCreate(NULL, NULL, 0, &auth_ref))
272 return -1;
273
274 if (!strcmp("read", argv[0]))
275 {
276 CFDictionaryRef right_definition;
277 status = AuthorizationRightGet(argv[1], &right_definition);
278 if (!status)
279 {
280 write_dict_to_stdout(right_definition);
281 CFRelease(right_definition);
282 }
283 }
284 else if (!strcmp("write", argv[0]))
285 {
286 if (argc == 2)
287 {
288 CFDictionaryRef right_definition = read_dict_from_stdin();
289 if (!right_definition)
290 return -1;
291 status = AuthorizationRightSet(auth_ref, argv[1], right_definition, NULL, NULL, NULL);
292 CFRelease(right_definition);
293 }
294 else if (argc == 3)
295 {
296 // argv[2] is shortcut string
297 CFStringRef shortcut_definition = CFStringCreateWithCStringNoCopy(NULL, argv[2], kCFStringEncodingUTF8, kCFAllocatorNull);
298 if (!shortcut_definition)
299 return -1;
300 status = AuthorizationRightSet(auth_ref, argv[1], shortcut_definition, NULL, NULL, NULL);
301 CFRelease(shortcut_definition);
302 }
303 else
304 return SHOW_USAGE_MESSAGE; // take one optional argument - no more
305
306 }
307 else if (!strcmp("remove", argv[0]))
308 {
309 status = AuthorizationRightRemove(auth_ref, argv[1]);
310 }
311 else if (!strcmp("smartcard", argv[0]))
312 {
313 if (argc == 2)
314 {
315 if(!strcmp("status", argv[1]))
316 {
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";
322
323 CFIndex requiredLine1 = -1;
324 CFIndex requiredLine2 = -1;
325
326 CFDictionaryRef right_definition;
327 status = AuthorizationRightGet(SYSTEM_LOGIN_CONSOLE, &right_definition);
328 if(!status)
329 {
330 CFArrayRef mechanisms;
331
332 Boolean res = CFDictionaryGetValueIfPresent(right_definition, MECHANISMS, (void*)&mechanisms);
333 if(res)
334 {
335 // now parse all array elements until "builtin:policy-banner" is found
336 CFIndex c = CFArrayGetCount(mechanisms);
337 CFStringRef mechanismName;
338
339 for (CFIndex i = 0; i < c; ++i)
340 {
341 mechanismName = CFArrayGetValueAtIndex(mechanisms, i);
342 if(CFStringCompare(mechanismName, BUILTIN_LINE, 0) == kCFCompareEqualTo)
343 {
344 if(i + 1 < c)
345 {
346 mechanismName = CFArrayGetValueAtIndex(mechanisms, i + 1);
347 if(CFStringCompare(mechanismName, SMARTCARD_LINE, 0) == kCFCompareEqualTo)
348 {
349 requiredLine1 = i + 1;
350 }
351 break;
352 }
353 }
354 }
355 }
356 CFRelease(right_definition);
357 }
358 status = AuthorizationRightGet(AUTHENTICATE, &right_definition);
359 if(!status)
360 {
361 CFArrayRef mechanisms;
362
363 Boolean res = CFDictionaryGetValueIfPresent(right_definition, MECHANISMS, (void*)&mechanisms);
364 if(res)
365 {
366 // now parse all array elements until "builtin:policy-banner" is found
367 CFIndex c = CFArrayGetCount(mechanisms);
368 CFStringRef mechanismName;
369
370 if(c > 0)
371 {
372 mechanismName = CFArrayGetValueAtIndex(mechanisms, 0);
373 if(CFStringCompare(mechanismName, SMARTCARD_LINE, 0) == kCFCompareEqualTo)
374 {
375 requiredLine2 = 0;
376 }
377 }
378 }
379 CFRelease(right_definition);
380 }
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");
382
383 }
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);
388 else
389 return SHOW_USAGE_MESSAGE; // unrecognized parameter
390 }
391 else
392 return SHOW_USAGE_MESSAGE; // required parameter missing
393 }
394 else if (!strcmp("merge", argv[0])) {
395 status = 1;
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;
409
410 if (argc < 2 || argc > 3)
411 return SHOW_USAGE_MESSAGE;
412
413 if (!strcmp("-", argv[1])) {
414 // Merging from <STDIN>.
415 sourcePlist = read_dict_from_stdin();
416 } else {
417 sourcePath = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8);
418 if (NULL == sourcePath) {
419 goto bail;
420 }
421 sourcePlist = read_plist_from_file(sourcePath);
422 }
423 if (NULL == sourcePlist)
424 goto bail;
425 if (argc == 2) {
426 // Merging to /etc/authorization.
427 destPath = CFStringCreateWithCString(kCFAllocatorDefault, "/etc/authorization", kCFStringEncodingUTF8);
428 } else {
429 destPath = CFStringCreateWithCString(kCFAllocatorDefault, argv[2], kCFStringEncodingUTF8);
430 }
431 if (NULL == destPath) {
432 goto bail;
433 }
434 destPlist = read_plist_from_file(destPath);
435 if (NULL == destPlist)
436 goto bail;
437
438 sourceRights = CFDictionaryGetValue(sourcePlist, CFSTR("rights"));
439 sourceRules = CFDictionaryGetValue(sourcePlist, CFSTR("rules"));
440 destRights = CFDictionaryGetValue(destPlist, CFSTR("rights"));
441 destRules = CFDictionaryGetValue(destPlist, CFSTR("rules"));
442 if (sourceRights)
443 rightsCount += CFDictionaryGetCount(sourceRights);
444 if (destRights)
445 rightsCount += CFDictionaryGetCount(destRights);
446 mergeRights = CFDictionaryCreateMutable(NULL, rightsCount, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
447 if (NULL == mergeRights) {
448 goto bail;
449 }
450 if (sourceRules)
451 rulesCount += CFDictionaryGetCount(sourceRules);
452 if (destRules)
453 rulesCount += CFDictionaryGetCount(destRules);
454 mergeRules = CFDictionaryCreateMutable(NULL, rulesCount, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
455 if (NULL == mergeRules) {
456 goto bail;
457 }
458
459 if (destRights)
460 CFDictionaryApplyFunction(destRights, merge_dictionaries, mergeRights);
461 if (destRules)
462 CFDictionaryApplyFunction(destRules, merge_dictionaries, mergeRules);
463 if (sourceRights)
464 CFDictionaryApplyFunction(sourceRights, merge_dictionaries, mergeRights);
465 if (sourceRules)
466 CFDictionaryApplyFunction(sourceRules, merge_dictionaries, mergeRules);
467
468 outDict = CFDictionaryCreateMutable(NULL, 3, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
469 if (NULL == outDict) {
470 goto bail;
471 }
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))
479 goto bail;
480
481 status = noErr;
482 bail:
483 if (sourcePath)
484 CFRelease(sourcePath);
485 if (destPath)
486 CFRelease(destPath);
487 if (sourcePlist)
488 CFRelease(sourcePlist);
489 if (destPlist)
490 CFRelease(destPlist);
491 if (outDict)
492 CFRelease(outDict);
493 }
494 else
495 return SHOW_USAGE_MESSAGE;
496 }
497 else
498 return SHOW_USAGE_MESSAGE;
499
500 if (auth_ref)
501 AuthorizationFree(auth_ref, 0);
502
503 if (!do_quiet)
504 fprintf(stderr, "%s (%d)\n", status ? "NO" : "YES", (int)status);
505
506 return (status ? -1 : 0);
507 }
508
509 int
510 authorize(int argc, char * const *argv)
511 {
512 int ch;
513 int retval = 1;
514 OSStatus status;
515
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;
521 char *login = NULL;
522
523 while ((ch = getopt(argc, argv, "ucC:EpdPieqwxl")) != -1)
524 {
525 switch (ch)
526 {
527 case 'u':
528 user_interaction_allowed = TRUE;
529 break;
530 case 'c':
531 explicit_credentials = TRUE;
532 break;
533 case 'C':
534 explicit_credentials = TRUE;
535 login = optarg;
536 break;
537 case 'e':
538 externalize = TRUE;
539 break;
540 case 'E':
541 extend_rights = FALSE;
542 break;
543 case 'p':
544 partial_rights = TRUE;
545 break;
546 case 'd':
547 destroy_rights = TRUE;
548 break;
549 case 'P':
550 pre_authorize = TRUE;
551 break;
552 case 'i':
553 internalize = TRUE;
554 break;
555 case 'w':
556 wait = TRUE;
557 externalize = TRUE;
558 break;
559 case 'x':
560 isolate_explicit_credentials = TRUE;
561 break;
562 case 'l':
563 least_privileged = TRUE;
564 break;
565 case '?':
566 default:
567 return SHOW_USAGE_MESSAGE;
568 }
569 }
570
571 argc -= optind;
572 argv += optind;
573
574 if (argc == 0)
575 return SHOW_USAGE_MESSAGE; // required right parameter(s)
576
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);
584
585 // set up AuthorizationRightSet
586 AuthorizationItem *rights = malloc(argc * sizeof(AuthorizationItem));
587 if (!rights) {
588 fprintf(stderr, "Out of memory\n");
589 retval = 1;
590 goto bail;
591 }
592 memset(rights, '\0', argc * sizeof(AuthorizationItem));
593 AuthorizationItemSet rightset = { argc, rights };
594 while (argc > 0)
595 rights[--argc].name = *argv++;
596
597 AuthorizationRef auth_ref = NULL;
598
599 // internalize AuthorizationRef
600 if (internalize)
601 {
602 auth_ref = read_auth_ref_from_stdin();
603 if (!auth_ref) {
604 retval = 1;
605 goto bail;
606 }
607 }
608
609 if (!auth_ref && AuthorizationCreate(NULL, NULL,
610 (least_privileged ? kAuthorizationFlagLeastPrivileged : 0),
611 &auth_ref)) {
612 retval = -1;
613 goto bail;
614 }
615
616 // prepare environment if needed
617 AuthorizationEnvironment *envp = NULL;
618 if (explicit_credentials) {
619 if (!login)
620 login = getlogin();
621 char *pass = getpass("Password:");
622 if (!(login && pass)) {
623 retval = 1;
624 goto bail;
625 }
626 static AuthorizationItem authenv[] = {
627 { kAuthorizationEnvironmentUsername },
628 { kAuthorizationEnvironmentPassword },
629 { kAuthorizationEnvironmentShared } // optional (see below)
630 };
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
638 else
639 env.count = 3; // do send kAuthorizationEnvironmentShared
640 envp = &env;
641 }
642
643 // perform Authorization
644 AuthorizationRights *granted_rights = NULL;
645 status = AuthorizationCopyRights(auth_ref, &rightset, envp, flags, &granted_rights);
646
647 // externalize AuthorizationRef
648 if (externalize)
649 write_auth_ref_to_stdout(auth_ref);
650
651 if (!do_quiet)
652 fprintf(stderr, "%s (%d) ", status ? "NO" : "YES", (int)status);
653
654 if (!do_quiet && !status && granted_rights)
655 {
656 uint32_t index;
657 fprintf(stderr, "{ %d: ", (int)granted_rights->count);
658 for (index = 0; index < granted_rights->count; index++)
659 {
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) ? ',' : '}');
663 }
664 AuthorizationFreeItemSet(granted_rights);
665 }
666
667 if (!do_quiet)
668 fprintf(stderr, "\n");
669
670 // wait for client to pick up AuthorizationRef
671 if (externalize && wait)
672 while (-1 != write(STDOUT_FILENO, NULL, 0))
673 usleep(100);
674
675 // drop AuthorizationRef
676 if (auth_ref)
677 AuthorizationFree(auth_ref, destroy_rights ? kAuthorizationFlagDestroyRights : 0);
678
679 retval = (status ? -1 : 0);
680 bail:
681 if (rights)
682 free(rights);
683
684 return retval;
685 }
686
687
688 int
689 execute_with_privileges(int argc, char * const *argv)
690 {
691 AuthorizationRef auth_ref = NULL;
692 int ch;
693 while ((ch = getopt(argc, argv, "i")) != -1)
694 {
695 switch (ch)
696 {
697 case 'i':
698 auth_ref = read_auth_ref_from_stdin();
699 break;
700 case '?':
701 default:
702 return SHOW_USAGE_MESSAGE;
703 }
704 }
705
706 argc -= optind;
707 argv += optind;
708
709 if (argc == 0)
710 return SHOW_USAGE_MESSAGE; // required tool parameter(s)
711
712 OSStatus status;
713
714 if (!auth_ref && AuthorizationCreate(NULL, NULL, 0, &auth_ref))
715 return -1;
716
717 FILE *communications_pipe = NULL;
718
719 status = AuthorizationExecuteWithPrivileges(auth_ref,argv[0], 0, (argc > 1) ? &argv[1] : NULL, &communications_pipe);
720
721 if (!do_quiet)
722 fprintf(stderr, "%s (%d) ", status ? "NO" : "YES", (int)status);
723
724 if (!status)
725 {
726 ssize_t bytes_read = 0;
727 uint8_t buffer[4096];
728
729 while ((bytes_read = read(STDIN_FILENO, &buffer, sizeof(buffer))))
730 {
731 if ((bytes_read == -1) && ((errno != EAGAIN) || (errno != EINTR)))
732 break;
733 else
734 while ((-1 == write(fileno(communications_pipe), buffer, bytes_read)) &&
735 ((errno == EAGAIN) || (errno == EINTR)))
736 usleep(100);
737 }
738 }
739
740 return (status ? -1 : 0);
741 }
742